diff --git a/.pubnub.yml b/.pubnub.yml index 8619426ed..bc746049e 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1644,4 +1644,4 @@ sdks: - Windows Server 2012 R2 Foundation - Windows Server 2012 R2 Essentials - Windows Server 2012 R2 Standard - - Windows Server 2012 R2 Datacenter + - Windows Server 2012 R2 Datacenter \ No newline at end of file diff --git a/src/Api/PubnubApi/Builder/StatusBuilder.cs b/src/Api/PubnubApi/Builder/StatusBuilder.cs index 071b1f14d..196ff5b64 100644 --- a/src/Api/PubnubApi/Builder/StatusBuilder.cs +++ b/src/Api/PubnubApi/Builder/StatusBuilder.cs @@ -1,12 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net; -using System.Text; namespace PubnubApi { - public class StatusBuilder + public class StatusBuilder { private readonly PNConfiguration config; private readonly IJsonPluggableLibrary jsonLibrary; @@ -98,11 +96,11 @@ public PNStatus CreateStatusResponse(PNOperationType type, PNStatusCategory c if (asyncRequestState != null) { - if (asyncRequestState.Request != null) + if (asyncRequestState.RequestCancellationTokenSource != null) { - status.ClientRequest = asyncRequestState.Request; + status.ClientRequest = asyncRequestState.RequestCancellationTokenSource; - HttpValueCollection restUriQueryCollection = HttpUtility.ParseQueryString(asyncRequestState.Request.RequestUri.Query); + HttpValueCollection restUriQueryCollection = HttpUtility.ParseQueryString(new Uri(asyncRequestState.Response.RequestUrl).Query); if (restUriQueryCollection.ContainsKey("auth")) { string auth = restUriQueryCollection["auth"]; diff --git a/src/Api/PubnubApi/Builder/UriUtil.cs b/src/Api/PubnubApi/Builder/UriUtil.cs index ecb9bf4f8..b04673a70 100644 --- a/src/Api/PubnubApi/Builder/UriUtil.cs +++ b/src/Api/PubnubApi/Builder/UriUtil.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text; namespace PubnubApi @@ -196,5 +198,10 @@ private static int ConvertToUtf32(string s, int index) // Not a high-surrogate or low-surrogate. Genereate the UTF32 value for the BMP characters. return (int)s[index]; } + + public static string BuildQueryString(Dictionary queryStringParamMap) + { + return string.Join("&", queryStringParamMap?.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).Select(kvp => string.Format(CultureInfo.InvariantCulture, "{0}={1}", kvp.Key, kvp.Value)).ToArray()); + } } } diff --git a/src/Api/PubnubApi/Builder/UrlRequestBuilder.cs b/src/Api/PubnubApi/Builder/UrlRequestBuilder.cs index f5c0a14b9..6f8bb8fd2 100644 --- a/src/Api/PubnubApi/Builder/UrlRequestBuilder.cs +++ b/src/Api/PubnubApi/Builder/UrlRequestBuilder.cs @@ -3,37 +3,29 @@ using System.Linq; using System.Text; using System.Globalization; -using System.Threading.Tasks; -using System.Threading; using PubnubApi.Security.Crypto.Common; -#if !NETSTANDARD10 && !NETSTANDARD11 && !NETSTANDARD12 && !WP81 -using System.Reflection; -#endif -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif using PubnubApi.Security.Crypto; using PubnubApi.Security.Crypto.Cryptors; +using System.Collections.Concurrent; +using System.Reflection; namespace PubnubApi { - public sealed class UrlRequestBuilder : IUrlRequestBuilder + public sealed class UrlRequestBuilder : IUrlRequestBuilder { private ConcurrentDictionary pubnubConfig { get; } = new ConcurrentDictionary(); private readonly IJsonPluggableLibrary jsonLib ; private readonly IPubnubUnitTest pubnubUnitTest; private readonly IPubnubLog pubnubLog; private readonly string pubnubInstanceId; - private readonly EndPoint.TelemetryManager telemetryMgr; private readonly EndPoint.TokenManager tokenMgr; - public UrlRequestBuilder(PNConfiguration config, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnitTest, IPubnubLog log, EndPoint.TelemetryManager pubnubTelemetryMgr, EndPoint.TokenManager pubnubTokenMgr, string pnInstanceId) + public UrlRequestBuilder(PNConfiguration config, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnitTest, IPubnubLog log, EndPoint.TokenManager pubnubTokenMgr, string pnInstanceId) { pubnubConfig.AddOrUpdate(pnInstanceId, config, (k, o) => config); this.jsonLib = jsonPluggableLibrary; this.pubnubUnitTest = pubnubUnitTest; this.pubnubLog = log; - this.telemetryMgr = pubnubTelemetryMgr; this.tokenMgr = pubnubTokenMgr; this.pubnubInstanceId = string.IsNullOrEmpty(pnInstanceId) ? "" : pnInstanceId; } @@ -2073,18 +2065,6 @@ private Dictionary GenerateCommonQueryParams(PNOperationType typ ret.Add("instanceid", pubnubInstanceId); } - if (pubnubConfig.ContainsKey(pubnubInstanceId) && pubnubConfig[pubnubInstanceId].EnableTelemetry && telemetryMgr != null) - { - Dictionary opsLatency = telemetryMgr.GetOperationsLatency().ConfigureAwait(false).GetAwaiter().GetResult(); - if (opsLatency != null && opsLatency.Count > 0) - { - foreach (string key in opsLatency.Keys) - { - ret.Add(key, opsLatency[key]); - } - } - } - if (pubnubConfig.ContainsKey(pubnubInstanceId) && !string.IsNullOrEmpty(pubnubConfig[pubnubInstanceId].SecretKey)) { ret.Add("timestamp", timeStamp.ToString(CultureInfo.InvariantCulture)); diff --git a/src/Api/PubnubApi/ClientNetworkStatus.cs b/src/Api/PubnubApi/ClientNetworkStatus.cs index d706e6b9a..9583672bf 100644 --- a/src/Api/PubnubApi/ClientNetworkStatus.cs +++ b/src/Api/PubnubApi/ClientNetworkStatus.cs @@ -1,154 +1,87 @@ using System; using System.Threading; -using System.Net; using System.Threading.Tasks; -using System.IO; using System.Globalization; -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 -using System.Net.Http; -using System.Net.Http.Headers; -#endif +using System.Collections.Generic; namespace PubnubApi { - #region "Network Status -- code split required" internal static class ClientNetworkStatus { - private static IJsonPluggableLibrary jsonLib; - private static PNConfiguration pubnubConfig; - private static IPubnubUnitTest unit; - private static IPubnubLog pubnubLog; + private static IJsonPluggableLibrary jsonLib; + private static PNConfiguration pubnubConfig; + private static IPubnubUnitTest unit; + private static IPubnubLog pubnubLog; + private static Pubnub pubnubInstance; - private static bool networkStatus = true; -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - private static HttpClient httpClient; -#endif + private static bool networkStatus = true; - public static PNConfiguration PubnubConfiguation - { - set - { - pubnubConfig = value; - } - get - { - return pubnubConfig; - } - } - - public static IJsonPluggableLibrary JsonLibrary - { - set - { - jsonLib = value; - } - get - { - return jsonLib; - } - } - - public static IPubnubUnitTest PubnubUnitTest - { - set - { - unit = value; - } - get - { - return unit; - } - } + public static Pubnub PubnubInstance { + set { + pubnubInstance = value; + } + get { + return pubnubInstance; + } + } - public static IPubnubLog PubnubLog - { - set - { - pubnubLog = value; - } - get - { - return pubnubLog; - } - } + public static PNConfiguration PubnubConfiguation { + set { + pubnubConfig = value; + } + get { + return pubnubConfig; + } + } -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - public static HttpClient RefHttpClient - { - set - { - httpClient = value; - if (httpClient == null) - { - if (pubnubConfig.Proxy != null) - { - HttpClientHandler httpClientHandler = new HttpClientHandler(); - if (httpClientHandler.SupportsProxy) - { - httpClientHandler.Proxy = pubnubConfig.Proxy; - httpClientHandler.UseProxy = true; - } - PubnubHttpClientHandler pubnubHttpClientHandler = new PubnubHttpClientHandler("PubnubHttpClientHandler", httpClientHandler, pubnubConfig, jsonLib, unit, pubnubLog); + public static IJsonPluggableLibrary JsonLibrary { + set { + jsonLib = value; + } + get { + return jsonLib; + } + } - httpClient = new HttpClient(pubnubHttpClientHandler); - } - else - { - httpClient = new HttpClient(); - } - httpClient.DefaultRequestHeaders.Accept.Clear(); - httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - httpClient.Timeout = TimeSpan.FromSeconds(pubnubConfig.NonSubscribeRequestTimeout); - } + public static IPubnubUnitTest PubnubUnitTest { + set { + unit = value; + } + get { + return unit; + } + } - } - get - { - return httpClient; - } - } -#endif + public static IPubnubLog PubnubLog { + set { + pubnubLog = value; + } + get { + return pubnubLog; + } + } - internal static bool CheckInternetStatus(bool systemActive, PNOperationType type, PNCallback callback, string[] channels, string[] channelGroups) + internal static bool CheckInternetStatus(bool systemActive, PNOperationType type, PNCallback callback, string[] channels, string[] channelGroups) { - if (unit != null) - { - return unit.InternetAvailable; - } - else - { - try - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task[] tasks = new Task[1]; - tasks[0] = Task.Factory.StartNew(async() => - { - await CheckClientNetworkAvailability(CallbackClientNetworkStatus, type, callback, channels, channelGroups).ConfigureAwait(false); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default); - tasks[0].ConfigureAwait(false); - Task.WaitAll(tasks); -#else - Thread networkCheckThread = new Thread(async () => - { - await CheckClientNetworkAvailability(CallbackClientNetworkStatus, type, callback, channels, channelGroups).ConfigureAwait(false); - }) - { IsBackground = true }; - networkCheckThread.Start(); - networkCheckThread.Join(pubnubConfig.NonSubscribeRequestTimeout * 1000); -#endif - } - catch (AggregateException ae) { - foreach (var ie in ae.InnerExceptions) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} AggregateException CheckInternetStatus Error: {1} {2} ", DateTime.Now.ToString(CultureInfo.InvariantCulture), ie.GetType().Name, ie.Message), pubnubConfig.LogVerbosity); - } - } - catch(Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} Exception CheckInternetStatus Error: {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); - } - - return networkStatus; + if (unit != null) { + return unit.InternetAvailable; + } else { + try { + Task[] tasks = new Task[1]; + tasks[0] = Task.Factory.StartNew(async () => { + await CheckClientNetworkAvailability(CallbackClientNetworkStatus, type, callback, channels, channelGroups).ConfigureAwait(false); + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default); + tasks[0].ConfigureAwait(false); + Task.WaitAll(tasks); + } catch (AggregateException ae) { + foreach (var ie in ae.InnerExceptions) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} AggregateException CheckInternetStatus Error: {1} {2} ", DateTime.Now.ToString(CultureInfo.InvariantCulture), ie.GetType().Name, ie.Message), pubnubConfig.LogVerbosity); + } + } catch (Exception ex) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} Exception CheckInternetStatus Error: {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); + } + + return networkStatus; } } @@ -157,239 +90,114 @@ private static void CallbackClientNetworkStatus(bool status) networkStatus = status; } - private static object internetCheckLock = new object(); - private static bool isInternetCheckRunning; + private static object internetCheckLock = new object(); + private static bool isInternetCheckRunning; - internal static bool IsInternetCheckRunning() - { - return isInternetCheckRunning; - } + internal static bool IsInternetCheckRunning() + { + return isInternetCheckRunning; + } - private static async Task CheckClientNetworkAvailability(Action internalCallback, PNOperationType type, PNCallback callback, string[] channels, string[] channelGroups) + private static async Task CheckClientNetworkAvailability(Action internalCallback, PNOperationType type, PNCallback callback, string[] channels, string[] channelGroups) { - lock (internetCheckLock) - { - if (isInternetCheckRunning) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} InternetCheckRunning Already running", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - return networkStatus; - } - } + lock (internetCheckLock) { + if (isInternetCheckRunning) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} InternetCheckRunning Already running", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); + return networkStatus; + } + } InternetState state = new InternetState(); state.InternalCallback = internalCallback; - state.PubnubCallbacck = callback; - state.ResponseType = type; - state.Channels = channels; - state.ChannelGroups = channelGroups; + state.PubnubCallbacck = callback; + state.ResponseType = type; + state.Channels = channels; + state.ChannelGroups = channelGroups; - networkStatus = await CheckSocketConnect(state).ConfigureAwait(false); - return networkStatus; + networkStatus = await CheckSocketConnect(state).ConfigureAwait(false); + return networkStatus; } - private static async Task CheckSocketConnect(object internetState) + private static async Task CheckSocketConnect(object internetState) { - lock (internetCheckLock) - { - isInternetCheckRunning = true; - } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} CheckSocketConnect Entered", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - - Action internalCallback = null; - PNCallback pubnubCallback = null; - PNOperationType type = PNOperationType.None; + lock (internetCheckLock) { + isInternetCheckRunning = true; + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} CheckSocketConnect Entered", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - var t = new TaskCompletionSource(); + Action internalCallback = null; + PNCallback pubnubCallback = null; + PNOperationType type = PNOperationType.None; - InternetState state = internetState as InternetState; - if (state != null) - { - internalCallback = state.InternalCallback; - type = state.ResponseType; - pubnubCallback = state.PubnubCallbacck; - } + var t = new TaskCompletionSource(); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(pubnubConfig, jsonLib, unit, pubnubLog, null, null, ""); - Uri requestUri = urlBuilder.BuildTimeRequest("GET", "", null); - try - { - bool gotTimeResp = false; - if (pubnubConfig.UseClassicHttpWebRequest) - { - gotTimeResp = await GetTimeWithClassicHttp(requestUri).ConfigureAwait(false); - t.TrySetResult(gotTimeResp); - } - else - { -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - if (pubnubConfig.UseTaskFactoryAsyncInsteadOfHttpClient) - { - gotTimeResp = await GetTimeWithTaskFactoryAsync(requestUri).ConfigureAwait(false); - } - else - { - gotTimeResp = await GetTimeWithHttpClient(requestUri).ConfigureAwait(false); - } - t.TrySetResult(gotTimeResp); -#else - gotTimeResp = await GetTimeWithTaskFactoryAsync(requestUri).ConfigureAwait(false); - t.TrySetResult(gotTimeResp); -#endif - } - } - catch (Exception ex) - { - networkStatus = false; - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} CheckSocketConnect (HttpClient Or Task.Factory) Failed {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); - if (!networkStatus) - { - t.TrySetResult(false); - isInternetCheckRunning = false; - ParseCheckSocketConnectException(ex, type, pubnubCallback, internalCallback); - } - } - finally - { - isInternetCheckRunning = false; - } - return await t.Task.ConfigureAwait(false); + InternetState state = internetState as InternetState; + if (state != null) { + internalCallback = state.InternalCallback; + type = state.ResponseType; + pubnubCallback = state.PubnubCallbacck; + } + try { + bool gotTimeResp = false; + gotTimeResp = await GetTimeWithTaskFactoryAsync().ConfigureAwait(false); + + } catch (Exception ex) { + networkStatus = false; + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} CheckSocketConnect (HttpClient Or Task.Factory) Failed {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); + if (!networkStatus) { + t.TrySetResult(false); + isInternetCheckRunning = false; + ParseCheckSocketConnectException(ex, type, pubnubCallback, internalCallback); + } + } finally { + isInternetCheckRunning = false; + } + return isInternetCheckRunning; } - private static void ParseCheckSocketConnectException(Exception ex, PNOperationType type, PNCallback callback, Action internalcallback) + private static void ParseCheckSocketConnectException(Exception ex, PNOperationType type, PNCallback callback, Action internalcallback) { - PNStatusCategory errorCategory = PNStatusCategoryHelper.GetPNStatusCategory(ex); - StatusBuilder statusBuilder = new StatusBuilder(pubnubConfig, jsonLib); - PNStatus status = statusBuilder.CreateStatusResponse(type, errorCategory, null, (int)System.Net.HttpStatusCode.NotFound, new PNException(ex)); + PNStatusCategory errorCategory = PNStatusCategoryHelper.GetPNStatusCategory(ex); + StatusBuilder statusBuilder = new StatusBuilder(pubnubConfig, jsonLib); + PNStatus status = statusBuilder.CreateStatusResponse(type, errorCategory, null, 404, new PNException(ex)); - if (callback != null) - { - callback.OnResponse(default(T), status); - } + if (callback != null) { + callback.OnResponse(default(T), status); + } LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} ParseCheckSocketConnectException Error. {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); internalcallback(false); } -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - private static async Task GetTimeWithHttpClient(Uri requestUri) - { - bool successFlag = false; - try - { - var response = await httpClient.GetAsync(requestUri).ConfigureAwait(false); - successFlag = response.IsSuccessStatusCode; - if (successFlag) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GetTimeWithHttpClient Resp OK", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GetTimeWithHttpClient FAILED", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - } - } - finally - { - networkStatus = successFlag; - } - return networkStatus; - } -#endif - private static async Task GetTimeWithTaskFactoryAsync(Uri requestUri) - { - bool successFlag = false; - try - { - HttpWebRequest myRequest = null; - myRequest = (HttpWebRequest)System.Net.WebRequest.Create(requestUri); - myRequest.Method = "GET"; - #if NET35 || NET40 || NET45 || NET61 || NET48 - myRequest.KeepAlive = true; - #endif - using (HttpWebResponse response = await Task.Factory.FromAsync(myRequest.BeginGetResponse, asyncPubnubResult => (HttpWebResponse)myRequest.EndGetResponse(asyncPubnubResult), null).ConfigureAwait(false)) - { - if (response != null) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GetTimeWithTaskFactoryAsync Resp {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), response.StatusCode.ToString()), pubnubConfig.LogVerbosity); - successFlag = response.StatusCode == HttpStatusCode.OK; - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GetTimeWithTaskFactoryAsync FAILED.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - } - } - } - finally - { - networkStatus = successFlag; - } - return networkStatus; - } - - private static async Task GetTimeWithClassicHttp(Uri requestUri) - { - bool successFlag = true; - try - { - HttpWebRequest myRequest = (HttpWebRequest)System.Net.WebRequest.Create(requestUri); - myRequest.Method = "GET"; - - RequestState pubnubRequestState = new RequestState(); - pubnubRequestState.Request = myRequest; - - myRequest.BeginGetResponse(new AsyncCallback( - (asynchronousResult) => { - RequestState asyncRequestState = asynchronousResult.AsyncState as RequestState; - HttpWebRequest asyncWebRequest = asyncRequestState.Request as HttpWebRequest; - if (asyncWebRequest != null) - { - HttpWebResponse asyncWebResponse = (HttpWebResponse)asyncWebRequest.EndGetResponse(asynchronousResult); - if (asyncWebResponse != null) - { - successFlag = asyncWebResponse.StatusCode == HttpStatusCode.OK; - } - if (asyncRequestState.Response != null) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); -#endif - asyncRequestState.Response = null; - asyncRequestState.Request = null; - } - } - } - ), pubnubRequestState); - - var _ = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, pubnubConfig.NonSubscribeRequestTimeout * 1000, Timeout.Infinite); - } - finally - { -#if NET35 || NET40 - await Task.Factory.StartNew(() => { }).ConfigureAwait(false); -#else - await Task.Delay(1).ConfigureAwait(false); -#endif - networkStatus = successFlag; - } - return networkStatus; - } + private static async Task GetTimeWithTaskFactoryAsync() + { + bool successFlag = false; + try { + var transportResponse = await TimeRequest(); + if (transportResponse.Error != null) throw transportResponse.Error; + successFlag = transportResponse.StatusCode == 200; + } finally { + networkStatus = successFlag; + } + return networkStatus; + } - private static void OnPubnubWebRequestTimeout(System.Object requestState) - { - RequestState currentState = requestState as RequestState; - if (currentState != null && currentState.Response == null && currentState.Request != null) - { - currentState.Timeout = true; - try - { - currentState.Request.Abort(); - } - catch { /* ignore */ } + private static async Task TimeRequest() + { + List pathSegments = new List { + "time", + "0" + }; + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments + }; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNTimeOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + return transportResponse; + } + } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, GetTimeWithClassicHttp timedout", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - } - } - } -#endregion } diff --git a/src/Api/PubnubApi/Constants.cs b/src/Api/PubnubApi/Constants.cs new file mode 100644 index 000000000..b71ba6b88 --- /dev/null +++ b/src/Api/PubnubApi/Constants.cs @@ -0,0 +1,15 @@ +using System; +namespace PubnubApi +{ + public static class Constants + { + public static readonly string Pnpres = "-pnpres"; + + public const string GET = "GET"; + public const string POST = "POST"; + public const string PATCH = "PATCH"; + public const string PUT = "PUT"; + public const string DELETE = "DELETE"; + } +} + diff --git a/src/Api/PubnubApi/EndPoint/Access/AuditOperation.cs b/src/Api/PubnubApi/EndPoint/Access/AuditOperation.cs index 2e4368e52..374c6065f 100644 --- a/src/Api/PubnubApi/EndPoint/Access/AuditOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Access/AuditOperation.cs @@ -3,213 +3,214 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; -using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class AuditOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string channelName; - private string channelGroupName; - private string[] authenticationKeys; - private PNCallback savedCallback; - private Dictionary queryParam; - - public AuditOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, null, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public AuditOperation Channel(string channel) - { - this.channelName = channel; - return this; - } - - public AuditOperation ChannelGroup(string channelGroup) - { - this.channelGroupName = channelGroup; - return this; - } - - public AuditOperation AuthKeys(string[] authKeys) - { - this.authenticationKeys = authKeys; - return this; - } - - public AuditOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - AuditAccess(this.channelName, this.channelGroupName, this.authenticationKeys, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - AuditAccess(this.channelName, this.channelGroupName, this.authenticationKeys, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - - public async Task> ExecuteAsync() - { - return await AuditAccess(this.channelName, this.channelGroupName, this.authenticationKeys, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - AuditAccess(this.channelName, this.channelGroupName, this.authenticationKeys, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - AuditAccess(this.channelName, this.channelGroupName, this.authenticationKeys, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void AuditAccess(string channel, string channelGroup, string[] authKeys, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) - { - throw new MissingMemberException("Invalid secret key"); - } - - string authKeysCommaDelimited = (authKeys != null && authKeys.Length > 0) ? string.Join(",", authKeys.OrderBy(x => x).ToArray()) : ""; - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildAuditAccessRequest("GET", "", channel, channelGroup, authKeysCommaDelimited, externalQueryParam); - - RequestState requestState = new RequestState(); - if (!string.IsNullOrEmpty(channel)) - { - requestState.Channels = new [] { channel }; - } - if (!string.IsNullOrEmpty(channelGroup)) - { - requestState.ChannelGroups = new [] { channelGroup }; - } - requestState.ResponseType = PNOperationType.PNAccessManagerAudit; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - - } - - internal async Task> AuditAccess(string channel, string channelGroup, string[] authKeys, Dictionary externalQueryParam) - { - if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) - { - throw new MissingMemberException("Invalid secret key"); - } - - PNResult ret = new PNResult(); - - string authKeysCommaDelimited = (authKeys != null && authKeys.Length > 0) ? string.Join(",", authKeys.OrderBy(x => x).ToArray()) : ""; - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildAuditAccessRequest("GET", "", channel, channelGroup, authKeysCommaDelimited, externalQueryParam); - - RequestState requestState = new RequestState(); - if (!string.IsNullOrEmpty(channel)) - { - requestState.Channels = new[] { channel }; - } - if (!string.IsNullOrEmpty(channelGroup)) - { - requestState.ChannelGroups = new[] { channelGroup }; - } - requestState.ResponseType = PNOperationType.PNAccessManagerAudit; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - if (result != null) - { - List resultList = ProcessJsonResponse(requestState, json); - if (resultList != null && resultList.Count > 0) - { - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNAccessManagerAuditResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class AuditOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelName; + private string channelGroupName; + private string[] authenticationKeys; + private PNCallback savedCallback; + private Dictionary queryParam; + + public AuditOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, null, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public AuditOperation Channel(string channel) + { + this.channelName = channel; + return this; + } + + public AuditOperation ChannelGroup(string channelGroup) + { + this.channelGroupName = channelGroup; + return this; + } + + public AuditOperation AuthKeys(string[] authKeys) + { + this.authenticationKeys = authKeys; + return this; + } + + public AuditOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + AuditAccess(this.channelName, this.channelGroupName, this.authenticationKeys, this.queryParam, callback); + } + + + public async Task> ExecuteAsync() + { + return await AuditAccess(this.channelName, this.channelGroupName, this.authenticationKeys, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + AuditAccess(this.channelName, this.channelGroupName, this.authenticationKeys, this.queryParam, savedCallback); + } + + internal void AuditAccess(string channel, string channelGroup, string[] authKeys, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) { + throw new MissingMemberException("Invalid secret key"); + } + RequestState requestState = new RequestState(); + if (!string.IsNullOrEmpty(channel)) { + requestState.Channels = new[] { channel }; + } + if (!string.IsNullOrEmpty(channelGroup)) { + requestState.ChannelGroups = new[] { channelGroup }; + } + requestState.ResponseType = PNOperationType.PNAccessManagerAudit; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAccessManagerAudit); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAccessManagerAudit, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + + } + + internal async Task> AuditAccess(string channel, string channelGroup, string[] authKeys, Dictionary externalQueryParam) + { + if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) { + throw new MissingMemberException("Invalid secret key"); + } + + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNAccessManagerAudit; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + if (!string.IsNullOrEmpty(channel)) { + requestState.Channels = new[] { channel }; + } + if (!string.IsNullOrEmpty(channelGroup)) { + requestState.ChannelGroups = new[] { channelGroup }; + } + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAccessManagerAudit); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List result = ProcessJsonResponse(requestState, json); + if (result != null) { + List resultList = ProcessJsonResponse(requestState, json); + if (resultList != null && resultList.Count > 0) { + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNAccessManagerAuditResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAccessManagerAudit, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v2", + "auth", + "audit", + "sub-key", + config.SubscribeKey + }; + + Dictionary requestQueryStringParams = new Dictionary(); + string authKeysCommaDelimited = (authenticationKeys != null && authenticationKeys.Length > 0) ? string.Join(",", authenticationKeys.OrderBy(x => x).ToArray()) : string.Empty; + if (!string.IsNullOrEmpty(authKeysCommaDelimited)) { + requestQueryStringParams.Add("auth", UriUtil.EncodeUriComponent(authKeysCommaDelimited, PNOperationType.PNAccessManagerAudit, false, false, false)); + } + + if (!string.IsNullOrEmpty(channelName)) { + requestQueryStringParams.Add("channel", UriUtil.EncodeUriComponent(channelName, PNOperationType.PNAccessManagerAudit, false, false, false)); + } + + if (!string.IsNullOrEmpty(channelGroupName)) { + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(channelGroupName, PNOperationType.PNAccessManagerAudit, false, false, false)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNAccessManagerAudit, false, false, false)); + } + } + } + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Access/GrantOperation.cs b/src/Api/PubnubApi/EndPoint/Access/GrantOperation.cs index d11eab87b..25951ebc8 100644 --- a/src/Api/PubnubApi/EndPoint/Access/GrantOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Access/GrantOperation.cs @@ -1,24 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; -using System.Threading; -using System.Net; using System.Globalization; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Text; namespace PubnubApi.EndPoint { - public class GrantOperation : PubnubCoreBase + public class GrantOperation : PubnubCoreBase { private readonly PNConfiguration config; private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; private string[] pubnubChannelNames; private string[] pubnubChannelGroupNames; @@ -35,13 +29,12 @@ public class GrantOperation : PubnubCoreBase private PNCallback savedCallback; private Dictionary queryParam; - public GrantOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, null, instance) + public GrantOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, null, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; } public GrantOperation Channels(string[] channels) @@ -138,20 +131,8 @@ public void Execute(PNCallback callback) { throw new InvalidOperationException("Only Get/Update/Delete permissions are allowed for UUID"); } -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GrantAccess(callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GrantAccess(callback); - }) - { IsBackground = true }.Start(); -#endif + this.savedCallback = callback; + GrantAccess(callback); } public async Task> ExecuteAsync() @@ -169,18 +150,7 @@ public async Task> ExecuteAsync() internal void Retry() { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GrantAccess(savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GrantAccess(savedCallback); - }) - { IsBackground = true }.Start(); -#endif + GrantAccess(savedCallback); } internal void GrantAccess(PNCallback callback) @@ -189,44 +159,6 @@ internal void GrantAccess(PNCallback callback) { throw new MissingMemberException("Invalid secret key"); } - - List channelList = new List(); - List channelGroupList = new List(); - List uuidList = new List(); - List authList = new List(); - - if (this.pubnubChannelNames != null && this.pubnubChannelNames.Length > 0) - { - channelList = new List(this.pubnubChannelNames); - channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); - } - - if (this.pubnubChannelGroupNames != null && this.pubnubChannelGroupNames.Length > 0) - { - channelGroupList = new List(this.pubnubChannelGroupNames); - channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); - } - - if (this.pubnubTargetUuids != null && this.pubnubTargetUuids.Length > 0) - { - uuidList = new List(this.pubnubTargetUuids); - uuidList = uuidList.Where(uuid => !string.IsNullOrEmpty(uuid) && uuid.Trim().Length > 0).Distinct().ToList(); - } - - if (this.pamAuthenticationKeys != null && this.pamAuthenticationKeys.Length > 0) - { - authList = new List(this.pamAuthenticationKeys); - authList = authList.Where(auth => !string.IsNullOrEmpty(auth) && auth.Trim().Length > 0).Distinct().ToList(); - } - - string channelsCommaDelimited = string.Join(",", channelList.OrderBy(x => x).ToArray()); - string channelGroupsCommaDelimited = string.Join(",", channelGroupList.OrderBy(x => x).ToArray()); - string targetUuidsCommaDelimited = string.Join(",", uuidList.OrderBy(x => x).ToArray()); - string authKeysCommaDelimited = string.Join(",", authList.OrderBy(x => x).ToArray()); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGrantV2AccessRequest("GET", "", channelsCommaDelimited, channelGroupsCommaDelimited, targetUuidsCommaDelimited, authKeysCommaDelimited, this.grantRead, this.grantWrite, this.grantDelete, this.grantManage, this.grantGet, this.grantUpdate, this.grantJoin, this.grantTTL, this.queryParam); - RequestState requestState = new RequestState(); requestState.Channels = this.pubnubChannelNames; requestState.ChannelGroups = this.pubnubChannelGroupNames; @@ -234,17 +166,26 @@ internal void GrantAccess(PNCallback callback) requestState.PubnubCallback = callback; requestState.Reconnect = false; requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAccessManagerGrant); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAccessManagerGrant, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); } internal async Task> GrantAccess() @@ -254,8 +195,57 @@ internal async Task> GrantAccess() throw new MissingMemberException("Invalid secret key"); } - PNResult ret = new PNResult(); + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.Channels = this.pubnubChannelNames; + requestState.ChannelGroups = this.pubnubChannelGroupNames; + requestState.ResponseType = PNOperationType.PNAccessManagerGrant; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAccessManagerGrant); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) + { + List resultList = ProcessJsonResponse(requestState, json); + if (resultList != null && resultList.Count > 0) + { + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNAccessManagerGrantResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) + { + returnValue.Result = responseResult; + } + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAccessManagerGrant, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + } + + private RequestParameter CreateRequestParameter() + { List channelList = new List(); List channelGroupList = new List(); List uuidList = new List(); @@ -290,52 +280,67 @@ internal async Task> GrantAccess() string targetUuidsCommaDelimited = string.Join(",", uuidList.OrderBy(x => x).ToArray()); string authKeysCommaDelimited = string.Join(",", authList.OrderBy(x => x).ToArray()); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGrantV2AccessRequest("GET", "", channelsCommaDelimited, channelGroupsCommaDelimited, targetUuidsCommaDelimited,authKeysCommaDelimited, this.grantRead, this.grantWrite, this.grantDelete, this.grantManage, this.grantGet, this.grantUpdate, this.grantJoin, this.grantTTL, this.queryParam); + List pathSegments = new List() { + "v2", + "auth", + "grant", + "sub-key", + config.SubscribeKey + }; - RequestState requestState = new RequestState(); - requestState.Channels = this.pubnubChannelNames; - requestState.ChannelGroups = this.pubnubChannelGroupNames; - requestState.ResponseType = PNOperationType.PNAccessManagerGrant; - requestState.Reconnect = false; - requestState.EndPointOperation = this; + Dictionary requestQueryStringParams = new Dictionary(); - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) + if (!string.IsNullOrEmpty(authKeysCommaDelimited)) { - List resultList = ProcessJsonResponse(requestState, json); - if (resultList != null && resultList.Count > 0) - { - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNAccessManagerGrantResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } + requestQueryStringParams.Add("auth", UriUtil.EncodeUriComponent(authKeysCommaDelimited, PNOperationType.PNAccessManagerGrant, false, false, false)); } - - return ret; - } - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; + if (!string.IsNullOrEmpty(channelsCommaDelimited)) + { + requestQueryStringParams.Add("channel", UriUtil.EncodeUriComponent(channelsCommaDelimited, PNOperationType.PNAccessManagerGrant, false, false, false)); + } - if (!ChannelRequest.ContainsKey(instance.InstanceId)) + if (!string.IsNullOrEmpty(channelGroupsCommaDelimited)) { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(channelGroupsCommaDelimited, PNOperationType.PNAccessManagerGrant, false, false, false)); } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) + + if (!string.IsNullOrEmpty(targetUuidsCommaDelimited)) { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + requestQueryStringParams.Add("target-uuid", UriUtil.EncodeUriComponent(targetUuidsCommaDelimited, PNOperationType.PNAccessManagerGrant, false, false, false)); } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) + + if (grantTTL > -1) { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + requestQueryStringParams.Add("ttl", grantTTL.ToString(CultureInfo.InvariantCulture)); } + + requestQueryStringParams.Add("r", Convert.ToInt32(grantRead).ToString(CultureInfo.InvariantCulture)); + requestQueryStringParams.Add("w", Convert.ToInt32(grantWrite).ToString(CultureInfo.InvariantCulture)); + requestQueryStringParams.Add("d", Convert.ToInt32(grantDelete).ToString(CultureInfo.InvariantCulture)); + requestQueryStringParams.Add("m", Convert.ToInt32(grantManage).ToString(CultureInfo.InvariantCulture)); + requestQueryStringParams.Add("g", Convert.ToInt32(grantGet).ToString(CultureInfo.InvariantCulture)); + requestQueryStringParams.Add("u", Convert.ToInt32(grantUpdate).ToString(CultureInfo.InvariantCulture)); + requestQueryStringParams.Add("j", Convert.ToInt32(grantJoin).ToString(CultureInfo.InvariantCulture)); + + if (queryParam != null && queryParam.Count > 0) + { + foreach (KeyValuePair kvp in queryParam) + { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) + { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNAccessManagerGrant, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; } } } diff --git a/src/Api/PubnubApi/EndPoint/Access/GrantTokenOperation.cs b/src/Api/PubnubApi/EndPoint/Access/GrantTokenOperation.cs index 5ab257582..bc8af1c50 100644 --- a/src/Api/PubnubApi/EndPoint/Access/GrantTokenOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Access/GrantTokenOperation.cs @@ -3,531 +3,416 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; -using System.Net; using System.Globalization; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class GrantTokenOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNTokenResources pubnubResources = new PNTokenResources - { - Channels = new Dictionary(), - Spaces = new Dictionary(), - ChannelGroups = new Dictionary(), - Uuids = new Dictionary(), - Users = new Dictionary() - }; - private PNTokenPatterns pubnubPatterns = new PNTokenPatterns - { - Channels = new Dictionary(), - Spaces = new Dictionary(), - ChannelGroups = new Dictionary(), - Uuids = new Dictionary(), - Users = new Dictionary() - }; - - private int grantTTL = -1; - private PNCallback savedCallbackGrantToken; - private Dictionary queryParam; - private Dictionary grantMeta; - private string pubnubAuthorizedUuid = string.Empty; - private string pubnubAuthorizedUserId = string.Empty; - - public GrantTokenOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - PubnubInstance = instance; - - InitializeDefaultVariableObjectStates(); - } - - public GrantTokenOperation AuthorizedUuid(string uuid) - { - if (!string.IsNullOrEmpty(pubnubAuthorizedUserId)) - { - throw new ArgumentException("Either UUID or UserId can be used. Not both."); - } - pubnubAuthorizedUuid = uuid; - return this; - } - - public GrantTokenOperation AuthorizedUserId(UserId user) - { - if (!string.IsNullOrEmpty(pubnubAuthorizedUuid)) - { - throw new ArgumentException("Either UUID or UserId can be used. Not both."); - } - pubnubAuthorizedUserId = user; - return this; - } - - public GrantTokenOperation Resources(PNTokenResources resources) - { - if (pubnubResources != null && resources != null) - { - if (resources.Channels != null && resources.Channels.Count > 0 && - resources.Spaces != null && resources.Spaces.Count > 0) - { - throw new ArgumentException("Either Channels or Spaces can be used. Not both."); - } - if (resources.Uuids != null && resources.Uuids.Count > 0 && - resources.Users != null && resources.Users.Count > 0) - { - throw new ArgumentException("Either Uuids or Users can be used. Not both."); - } - pubnubResources = resources; - if (pubnubResources.Channels == null) - { - pubnubResources.Channels = new Dictionary(); - } - if (pubnubResources.Spaces == null) - { - pubnubResources.Spaces = new Dictionary(); - } - if (pubnubResources.ChannelGroups == null) - { - pubnubResources.ChannelGroups = new Dictionary(); - } - if (pubnubResources.Uuids == null) - { - pubnubResources.Uuids = new Dictionary(); - } - if (pubnubResources.Users == null) - { - pubnubResources.Users = new Dictionary(); - } - } - return this; - } - - public GrantTokenOperation Patterns(PNTokenPatterns patterns) - { - if (pubnubPatterns != null && patterns != null) - { - if (patterns.Channels != null && patterns.Channels.Count > 0 && - patterns.Spaces != null && patterns.Spaces.Count > 0) - { - throw new ArgumentException("Either Channels or Spaces can be used. Not both."); - } - if (patterns.Uuids != null && patterns.Uuids.Count > 0 && - patterns.Users != null && patterns.Users.Count > 0) - { - throw new ArgumentException("Either Uuids or Users can be used. Not both."); - } - - pubnubPatterns = patterns; - if (pubnubPatterns.Channels == null) - { - pubnubPatterns.Channels = new Dictionary(); - } - if (pubnubPatterns.Spaces == null) - { - pubnubPatterns.Spaces = new Dictionary(); - } - if (pubnubPatterns.ChannelGroups == null) - { - pubnubPatterns.ChannelGroups = new Dictionary(); - } - if (pubnubPatterns.Uuids == null) - { - pubnubPatterns.Uuids = new Dictionary(); - } - if (pubnubPatterns.Users == null) - { - pubnubPatterns.Users = new Dictionary(); - } - - } - return this; - } - - public GrantTokenOperation TTL(int ttl) - { - this.grantTTL = ttl; - return this; - } - - public GrantTokenOperation Meta(Dictionary metaObject) - { - this.grantMeta = metaObject; - return this; - } - - public GrantTokenOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallbackGrantToken = callback; - GrantAccess(callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallbackGrantToken = callback; - GrantAccess(callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GrantAccess().ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GrantAccess(savedCallbackGrantToken); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GrantAccess(savedCallbackGrantToken); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void GrantAccess(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) - { - throw new MissingMemberException("Invalid secret key"); - } - - if (this.grantTTL <= 0) - { - throw new MissingMemberException("Invalid TTL value"); - } - - RequestState requestState = new RequestState(); - requestState.Channels = pubnubResources.Channels.Keys.ToArray(); - requestState.ChannelGroups = pubnubResources.ChannelGroups.Keys.ToArray(); - requestState.ResponseType = PNOperationType.PNAccessManagerGrantToken; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - - requestState.UsePostMethod = true; - - bool atleastOnePermission = false; - Dictionary chBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Channels, atleastOnePermission, out chBitmaskPermCollection); - - Dictionary chPatternBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Channels, atleastOnePermission, out chPatternBitmaskPermCollection); - - Dictionary spBitmaskPermCollection = null; - Dictionary spPatternBitmaskPermCollection = null; - if (pubnubResources.Channels.Count == 0 && pubnubPatterns.Channels.Count == 0) - { - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Spaces, atleastOnePermission, out spBitmaskPermCollection); - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Spaces, atleastOnePermission, out spPatternBitmaskPermCollection); - } - else - { - spBitmaskPermCollection = new Dictionary(); - spPatternBitmaskPermCollection = new Dictionary(); - } - - Dictionary cgBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.ChannelGroups, atleastOnePermission, out cgBitmaskPermCollection); - - Dictionary cgPatternBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.ChannelGroups, atleastOnePermission, out cgPatternBitmaskPermCollection); - - Dictionary uuidBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Uuids, atleastOnePermission, out uuidBitmaskPermCollection); - - Dictionary uuidPatternBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Uuids, atleastOnePermission, out uuidPatternBitmaskPermCollection); - - Dictionary userBitmaskPermCollection = null; - Dictionary userPatternBitmaskPermCollection = null; - if (pubnubResources.Uuids.Count == 0 && pubnubPatterns.Uuids.Count == 0) - { - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Users, atleastOnePermission, out userBitmaskPermCollection); - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Users, atleastOnePermission, out userPatternBitmaskPermCollection); - } - else - { - userBitmaskPermCollection = new Dictionary(); - userPatternBitmaskPermCollection = new Dictionary(); - - } - - if (!atleastOnePermission) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} At least one permission is needed for at least one or more of uuids/users, channels/spaces or groups",DateTime.Now.ToString(CultureInfo.InvariantCulture)), PNLogVerbosity.BODY); - } - - Dictionary resourcesCollection = new Dictionary(); - resourcesCollection.Add("channels", chBitmaskPermCollection); - resourcesCollection.Add("groups", cgBitmaskPermCollection); - resourcesCollection.Add("uuids", uuidBitmaskPermCollection); - resourcesCollection.Add("users", userBitmaskPermCollection); - resourcesCollection.Add("spaces", spBitmaskPermCollection); - - Dictionary patternsCollection = new Dictionary(); - patternsCollection.Add("channels", chPatternBitmaskPermCollection); - patternsCollection.Add("groups", cgPatternBitmaskPermCollection); - patternsCollection.Add("uuids", uuidPatternBitmaskPermCollection); - patternsCollection.Add("users", userPatternBitmaskPermCollection); - patternsCollection.Add("spaces", spPatternBitmaskPermCollection); - - Dictionary optimizedMeta = new Dictionary(); - if (this.grantMeta != null) - { - optimizedMeta = this.grantMeta; - } - - Dictionary permissionCollection = new Dictionary(); - permissionCollection.Add("resources", resourcesCollection); - permissionCollection.Add("patterns", patternsCollection); - permissionCollection.Add("meta", optimizedMeta); - if (!string.IsNullOrEmpty(this.pubnubAuthorizedUuid) && this.pubnubAuthorizedUuid.Trim().Length > 0) - { - permissionCollection.Add("uuid", this.pubnubAuthorizedUuid); - } - else if (!string.IsNullOrEmpty(this.pubnubAuthorizedUserId) && this.pubnubAuthorizedUserId.Trim().Length > 0) - { - permissionCollection.Add("uuid", this.pubnubAuthorizedUserId); - } - Dictionary messageEnvelope = new Dictionary(); - messageEnvelope.Add("ttl", this.grantTTL); - messageEnvelope.Add("permissions", permissionCollection); - - string requestMethodName = "POST"; - string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGrantV3AccessRequest(requestMethodName, postMessage, this.queryParam); - - UrlProcessRequest(request, requestState, false, postData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private bool FillPermissionMappingWithMaskValues(Dictionary dPerms, bool currentAtleastOnePermission, out Dictionary dPermsWithMaskValues) - { - dPermsWithMaskValues = new Dictionary(); - bool internalAtleastOnePermission = currentAtleastOnePermission; - foreach (KeyValuePair kvp in dPerms) - { - PNTokenAuthValues perm = kvp.Value; - int bitMaskPermissionValue = 0; - if (!string.IsNullOrEmpty(kvp.Key) && kvp.Key.Trim().Length > 0 && perm != null) - { - bitMaskPermissionValue = CalculateGrantBitMaskValue(perm); - if (!internalAtleastOnePermission && bitMaskPermissionValue > 0) { internalAtleastOnePermission = true; } - } - dPermsWithMaskValues.Add(kvp.Key, bitMaskPermissionValue); - } - return internalAtleastOnePermission; - } - - internal async Task> GrantAccess() - { - if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) - { - throw new MissingMemberException("Invalid secret key"); - } - - if (this.grantTTL <= 0) - { - throw new MissingMemberException("Invalid TTL value"); - } - - PNResult ret = new PNResult(); - - bool atleastOnePermission = false; - Dictionary chBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Channels, atleastOnePermission, out chBitmaskPermCollection); - - Dictionary chPatternBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Channels, atleastOnePermission, out chPatternBitmaskPermCollection); - Dictionary spBitmaskPermCollection = null; - Dictionary spPatternBitmaskPermCollection = null; - if (pubnubResources.Channels.Count == 0 && pubnubPatterns.Channels.Count == 0) - { - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Spaces, atleastOnePermission, out spBitmaskPermCollection); - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Spaces, atleastOnePermission, out spPatternBitmaskPermCollection); - } - else - { - spBitmaskPermCollection = new Dictionary(); - spPatternBitmaskPermCollection = new Dictionary(); - } - - Dictionary cgBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.ChannelGroups, atleastOnePermission, out cgBitmaskPermCollection); - - Dictionary cgPatternBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.ChannelGroups, atleastOnePermission, out cgPatternBitmaskPermCollection); - - Dictionary uuidBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Uuids, atleastOnePermission, out uuidBitmaskPermCollection); - - Dictionary uuidPatternBitmaskPermCollection = null; - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Uuids, atleastOnePermission, out uuidPatternBitmaskPermCollection); - - Dictionary userBitmaskPermCollection = null; - Dictionary userPatternBitmaskPermCollection = null; - if (pubnubResources.Uuids.Count == 0 && pubnubPatterns.Uuids.Count == 0) - { - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Users, atleastOnePermission, out userBitmaskPermCollection); - atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Users, atleastOnePermission, out userPatternBitmaskPermCollection); - } - else - { - userBitmaskPermCollection = new Dictionary(); - userPatternBitmaskPermCollection = new Dictionary(); - - } - - if (!atleastOnePermission) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} At least one permission is needed for at least one or more of uuids, channels or groups", DateTime.Now.ToString(CultureInfo.InvariantCulture)), PNLogVerbosity.BODY); - } - - Dictionary resourcesCollection = new Dictionary(); - resourcesCollection.Add("channels", chBitmaskPermCollection); - resourcesCollection.Add("groups", cgBitmaskPermCollection); - resourcesCollection.Add("uuids", uuidBitmaskPermCollection); - resourcesCollection.Add("users", userBitmaskPermCollection); - resourcesCollection.Add("spaces", spBitmaskPermCollection); - - Dictionary patternsCollection = new Dictionary(); - patternsCollection.Add("channels", chPatternBitmaskPermCollection); - patternsCollection.Add("groups", cgPatternBitmaskPermCollection); - patternsCollection.Add("uuids", uuidPatternBitmaskPermCollection); - patternsCollection.Add("users", new Dictionary()); //Empty object for users for json structure - patternsCollection.Add("spaces", new Dictionary()); //Empty object for spaces for json structure - - Dictionary optimizedMeta = new Dictionary(); - if (this.grantMeta != null) - { - optimizedMeta = this.grantMeta; - } - - Dictionary permissionCollection = new Dictionary(); - permissionCollection.Add("resources", resourcesCollection); - permissionCollection.Add("patterns", patternsCollection); - permissionCollection.Add("meta", optimizedMeta); - if (!string.IsNullOrEmpty(this.pubnubAuthorizedUuid) && this.pubnubAuthorizedUuid.Trim().Length > 0) - { - permissionCollection.Add("uuid", this.pubnubAuthorizedUuid); - } - - Dictionary messageEnvelope = new Dictionary(); - messageEnvelope.Add("ttl", this.grantTTL); - messageEnvelope.Add("permissions", permissionCollection); - - string requestMethodName = "POST"; - string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGrantV3AccessRequest(requestMethodName, postMessage, this.queryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = pubnubResources.Channels.Keys.ToArray(); - requestState.ChannelGroups = pubnubResources.ChannelGroups.Keys.ToArray(); - requestState.ResponseType = PNOperationType.PNAccessManagerGrantToken; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = true; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, postData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - if (resultList != null && resultList.Count > 0) - { - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNAccessManagerTokenResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - } - - return ret; - } - - private static int CalculateGrantBitMaskValue(PNTokenAuthValues perm) - { - int result = 0; - - if (perm.Read) - { - result = (int)GrantBitFlag.READ; - } - if (perm.Write) - { - result = result + (int)GrantBitFlag.WRITE; - } - if (perm.Manage) - { - result = result + (int)GrantBitFlag.MANAGE; - } - if (perm.Delete) - { - result = result + (int)GrantBitFlag.DELETE; - } - if (perm.Create) - { - result = result + (int)GrantBitFlag.CREATE; - } - if (perm.Get) - { - result = result + (int)GrantBitFlag.GET; - } - if (perm.Update) - { - result = result + (int)GrantBitFlag.UPDATE; - } - if (perm.Join) - { - result = result + (int)GrantBitFlag.JOIN; - } - - return result; - } - } + public class GrantTokenOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNTokenResources pubnubResources = new PNTokenResources { + Channels = new Dictionary(), + Spaces = new Dictionary(), + ChannelGroups = new Dictionary(), + Uuids = new Dictionary(), + Users = new Dictionary() + }; + private PNTokenPatterns pubnubPatterns = new PNTokenPatterns { + Channels = new Dictionary(), + Spaces = new Dictionary(), + ChannelGroups = new Dictionary(), + Uuids = new Dictionary(), + Users = new Dictionary() + }; + + private int grantTTL = -1; + private PNCallback savedCallbackGrantToken; + private Dictionary queryParam; + private Dictionary grantMeta; + private string pubnubAuthorizedUuid = string.Empty; + private string pubnubAuthorizedUserId = string.Empty; + + public GrantTokenOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + PubnubInstance = instance; + + InitializeDefaultVariableObjectStates(); + } + + public GrantTokenOperation AuthorizedUuid(string uuid) + { + if (!string.IsNullOrEmpty(pubnubAuthorizedUserId)) { + throw new ArgumentException("Either UUID or UserId can be used. Not both."); + } + pubnubAuthorizedUuid = uuid; + return this; + } + + public GrantTokenOperation AuthorizedUserId(UserId user) + { + if (!string.IsNullOrEmpty(pubnubAuthorizedUuid)) { + throw new ArgumentException("Either UUID or UserId can be used. Not both."); + } + pubnubAuthorizedUserId = user; + return this; + } + + public GrantTokenOperation Resources(PNTokenResources resources) + { + if (pubnubResources != null && resources != null) { + if (resources.Channels != null && resources.Channels.Count > 0 && + resources.Spaces != null && resources.Spaces.Count > 0) { + throw new ArgumentException("Either Channels or Spaces can be used. Not both."); + } + if (resources.Uuids != null && resources.Uuids.Count > 0 && + resources.Users != null && resources.Users.Count > 0) { + throw new ArgumentException("Either Uuids or Users can be used. Not both."); + } + pubnubResources = resources; + if (pubnubResources.Channels == null) { + pubnubResources.Channels = new Dictionary(); + } + if (pubnubResources.Spaces == null) { + pubnubResources.Spaces = new Dictionary(); + } + if (pubnubResources.ChannelGroups == null) { + pubnubResources.ChannelGroups = new Dictionary(); + } + if (pubnubResources.Uuids == null) { + pubnubResources.Uuids = new Dictionary(); + } + if (pubnubResources.Users == null) { + pubnubResources.Users = new Dictionary(); + } + } + return this; + } + + public GrantTokenOperation Patterns(PNTokenPatterns patterns) + { + if (pubnubPatterns != null && patterns != null) { + if (patterns.Channels != null && patterns.Channels.Count > 0 && + patterns.Spaces != null && patterns.Spaces.Count > 0) { + throw new ArgumentException("Either Channels or Spaces can be used. Not both."); + } + if (patterns.Uuids != null && patterns.Uuids.Count > 0 && + patterns.Users != null && patterns.Users.Count > 0) { + throw new ArgumentException("Either Uuids or Users can be used. Not both."); + } + + pubnubPatterns = patterns; + if (pubnubPatterns.Channels == null) { + pubnubPatterns.Channels = new Dictionary(); + } + if (pubnubPatterns.Spaces == null) { + pubnubPatterns.Spaces = new Dictionary(); + } + if (pubnubPatterns.ChannelGroups == null) { + pubnubPatterns.ChannelGroups = new Dictionary(); + } + if (pubnubPatterns.Uuids == null) { + pubnubPatterns.Uuids = new Dictionary(); + } + if (pubnubPatterns.Users == null) { + pubnubPatterns.Users = new Dictionary(); + } + + } + return this; + } + + public GrantTokenOperation TTL(int ttl) + { + this.grantTTL = ttl; + return this; + } + + public GrantTokenOperation Meta(Dictionary metaObject) + { + this.grantMeta = metaObject; + return this; + } + + public GrantTokenOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + GrantAccess(callback); + } + + public async Task> ExecuteAsync() + { + return await GrantAccess(); + } + + internal void Retry() + { + GrantAccess(savedCallbackGrantToken); + } + + internal void GrantAccess(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) { + throw new MissingMemberException("Invalid secret key"); + } + + if (this.grantTTL <= 0) { + throw new MissingMemberException("Invalid TTL value"); + } + + RequestState requestState = new RequestState(); + requestState.Channels = pubnubResources.Channels.Keys.ToArray(); + requestState.ChannelGroups = pubnubResources.ChannelGroups.Keys.ToArray(); + requestState.ResponseType = PNOperationType.PNAccessManagerGrantToken; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAccessManagerGrantToken); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAccessManagerGrantToken, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNAccessManagerTokenResult), status); + } + }); + } + + private bool FillPermissionMappingWithMaskValues(Dictionary dPerms, bool currentAtleastOnePermission, out Dictionary dPermsWithMaskValues) + { + dPermsWithMaskValues = new Dictionary(); + bool internalAtleastOnePermission = currentAtleastOnePermission; + foreach (KeyValuePair kvp in dPerms) { + PNTokenAuthValues perm = kvp.Value; + int bitMaskPermissionValue = 0; + if (!string.IsNullOrEmpty(kvp.Key) && kvp.Key.Trim().Length > 0 && perm != null) { + bitMaskPermissionValue = CalculateGrantBitMaskValue(perm); + if (!internalAtleastOnePermission && bitMaskPermissionValue > 0) { internalAtleastOnePermission = true; } + } + dPermsWithMaskValues.Add(kvp.Key, bitMaskPermissionValue); + } + return internalAtleastOnePermission; + } + + internal async Task> GrantAccess() + { + if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) { + throw new MissingMemberException("Invalid secret key"); + } + + if (this.grantTTL <= 0) { + throw new MissingMemberException("Invalid TTL value"); + } + RequestState requestState = new RequestState(); + requestState.Channels = pubnubResources.Channels.Keys.ToArray(); + requestState.ChannelGroups = pubnubResources.ChannelGroups.Keys.ToArray(); + requestState.ResponseType = PNOperationType.PNAccessManagerGrantToken; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + Tuple JsonAndStatusTuple; + + PNResult returnValue = new PNResult(); + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAccessManagerGrantToken); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple("", errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + if (resultList != null && resultList.Count > 0) { + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNAccessManagerTokenResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAccessManagerGrantToken, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private static int CalculateGrantBitMaskValue(PNTokenAuthValues perm) + { + int result = 0; + + if (perm.Read) { + result = (int)GrantBitFlag.READ; + } + if (perm.Write) { + result = result + (int)GrantBitFlag.WRITE; + } + if (perm.Manage) { + result = result + (int)GrantBitFlag.MANAGE; + } + if (perm.Delete) { + result = result + (int)GrantBitFlag.DELETE; + } + if (perm.Create) { + result = result + (int)GrantBitFlag.CREATE; + } + if (perm.Get) { + result = result + (int)GrantBitFlag.GET; + } + if (perm.Update) { + result = result + (int)GrantBitFlag.UPDATE; + } + if (perm.Join) { + result = result + (int)GrantBitFlag.JOIN; + } + + return result; + } + + private RequestParameter CreateRequestParameter() + { + bool atleastOnePermission = false; + Dictionary chBitmaskPermCollection = null; + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Channels, atleastOnePermission, out chBitmaskPermCollection); + + Dictionary chPatternBitmaskPermCollection = null; + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Channels, atleastOnePermission, out chPatternBitmaskPermCollection); + + Dictionary spBitmaskPermCollection = null; + Dictionary spPatternBitmaskPermCollection = null; + if (pubnubResources.Channels.Count == 0 && pubnubPatterns.Channels.Count == 0) { + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Spaces, atleastOnePermission, out spBitmaskPermCollection); + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Spaces, atleastOnePermission, out spPatternBitmaskPermCollection); + } else { + spBitmaskPermCollection = new Dictionary(); + spPatternBitmaskPermCollection = new Dictionary(); + } + + Dictionary cgBitmaskPermCollection = null; + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.ChannelGroups, atleastOnePermission, out cgBitmaskPermCollection); + + Dictionary cgPatternBitmaskPermCollection = null; + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.ChannelGroups, atleastOnePermission, out cgPatternBitmaskPermCollection); + + Dictionary uuidBitmaskPermCollection = null; + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Uuids, atleastOnePermission, out uuidBitmaskPermCollection); + + Dictionary uuidPatternBitmaskPermCollection = null; + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Uuids, atleastOnePermission, out uuidPatternBitmaskPermCollection); + + Dictionary userBitmaskPermCollection = null; + Dictionary userPatternBitmaskPermCollection = null; + if (pubnubResources.Uuids.Count == 0 && pubnubPatterns.Uuids.Count == 0) { + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubResources.Users, atleastOnePermission, out userBitmaskPermCollection); + atleastOnePermission = FillPermissionMappingWithMaskValues(this.pubnubPatterns.Users, atleastOnePermission, out userPatternBitmaskPermCollection); + } else { + userBitmaskPermCollection = new Dictionary(); + userPatternBitmaskPermCollection = new Dictionary(); + } + + if (!atleastOnePermission) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} At least one permission is needed for at least one or more of uuids/users, channels/spaces or groups", DateTime.Now.ToString(CultureInfo.InvariantCulture)), PNLogVerbosity.BODY); + } + + Dictionary resourcesCollection = new Dictionary + { + { "channels", chBitmaskPermCollection }, + { "groups", cgBitmaskPermCollection }, + { "uuids", uuidBitmaskPermCollection }, + { "users", userBitmaskPermCollection }, + { "spaces", spBitmaskPermCollection } + }; + + Dictionary patternsCollection = new Dictionary + { + { "channels", chPatternBitmaskPermCollection }, + { "groups", cgPatternBitmaskPermCollection }, + { "uuids", uuidPatternBitmaskPermCollection }, + { "users", userPatternBitmaskPermCollection }, + { "spaces", spPatternBitmaskPermCollection } + }; + + Dictionary optimizedMeta = new Dictionary(); + if (this.grantMeta != null) { + optimizedMeta = this.grantMeta; + } + + Dictionary permissionCollection = new Dictionary + { + { "resources", resourcesCollection }, + { "patterns", patternsCollection }, + { "meta", optimizedMeta } + }; + if (!string.IsNullOrEmpty(this.pubnubAuthorizedUuid) && this.pubnubAuthorizedUuid.Trim().Length > 0) { + permissionCollection.Add("uuid", this.pubnubAuthorizedUuid); + } else if (!string.IsNullOrEmpty(this.pubnubAuthorizedUserId) && this.pubnubAuthorizedUserId.Trim().Length > 0) { + permissionCollection.Add("uuid", this.pubnubAuthorizedUserId); + } + Dictionary messageEnvelope = new Dictionary + { + { "ttl", this.grantTTL }, + { "permissions", permissionCollection } + }; + string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); + byte[] postData = Encoding.UTF8.GetBytes(postMessage); + + List pathSegments = new List() { + "v3", + "pam", + config.SubscribeKey, + "grant" + }; + + + Dictionary requestQueryStringParams = new Dictionary(); + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNAccessManagerGrantToken, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.POST, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = postMessage + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Access/RevokeTokenOperation.cs b/src/Api/PubnubApi/EndPoint/Access/RevokeTokenOperation.cs index cddae2111..532bc551e 100644 --- a/src/Api/PubnubApi/EndPoint/Access/RevokeTokenOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Access/RevokeTokenOperation.cs @@ -1,155 +1,165 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Text; namespace PubnubApi.EndPoint { - public class RevokeTokenOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string pnToken = string.Empty; - private PNCallback savedCallbackRevokeToken; - private Dictionary queryParam; - - public RevokeTokenOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - PubnubInstance = instance; - - InitializeDefaultVariableObjectStates(); - } - - public RevokeTokenOperation Token(string tokenToBeRevoked) - { - this.pnToken = tokenToBeRevoked; - return this; - } - - public RevokeTokenOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallbackRevokeToken = callback; - RevokeAccess(callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallbackRevokeToken = callback; - RevokeAccess(callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await RevokeAccess().ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - RevokeAccess(savedCallbackRevokeToken); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - RevokeAccess(savedCallbackRevokeToken); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void RevokeAccess(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) - { - throw new MissingMemberException("Invalid secret key"); - } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNAccessManagerRevokeToken; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - string requestMethodName = "DELETE"; - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildRevokeV3AccessRequest(requestMethodName, null, pnToken, this.queryParam); - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> RevokeAccess() - { - if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) - { - throw new MissingMemberException("Invalid secret key"); - } - - PNResult ret = new PNResult(); - - string requestMethodName = "DELETE"; - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildRevokeV3AccessRequest(requestMethodName, null, pnToken, queryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNAccessManagerRevokeToken; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - if (resultList != null && resultList.Count > 0) - { - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNAccessManagerRevokeTokenResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - } - - return ret; - } - - } + public class RevokeTokenOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string pnToken = string.Empty; + private PNCallback savedCallbackRevokeToken; + private Dictionary queryParam; + + public RevokeTokenOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + PubnubInstance = instance; + + InitializeDefaultVariableObjectStates(); + } + + public RevokeTokenOperation Token(string tokenToBeRevoked) + { + this.pnToken = tokenToBeRevoked; + return this; + } + + public RevokeTokenOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + this.savedCallbackRevokeToken = callback; + RevokeAccess(callback); + } + + public async Task> ExecuteAsync() + { + return await RevokeAccess(); + } + + internal void Retry() + { + RevokeAccess(savedCallbackRevokeToken); + } + + internal void RevokeAccess(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) { + throw new MissingMemberException("Invalid secret key"); + } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNAccessManagerRevokeToken; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAccessManagerRevokeToken); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(t.Result.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAccessManagerRevokeToken, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNAccessManagerRevokeTokenResult), status); + } + }); + } + + internal async Task> RevokeAccess() + { + if (string.IsNullOrEmpty(config.SecretKey) || string.IsNullOrEmpty(config.SecretKey.Trim()) || config.SecretKey.Length <= 0) { + throw new MissingMemberException("Invalid secret key"); + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNAccessManagerRevokeToken; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAccessManagerRevokeToken); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple("", errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + if (resultList != null && resultList.Count > 0) { + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNAccessManagerRevokeTokenResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAccessManagerRevokeToken, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List() { + "v3", + "pam", + config.SubscribeKey, + "grant", + pnToken + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.ChannelGroupRevokeAccess, false, false, false)); + } + } + } + + string queryString = UriUtil.BuildQueryString(requestQueryStringParams); + + var requestParameter = new RequestParameter() { + RequestType = Constants.DELETE, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/ChannelGroup/AddChannelsToChannelGroupOperation.cs b/src/Api/PubnubApi/EndPoint/ChannelGroup/AddChannelsToChannelGroupOperation.cs index e5b382245..89534bc0b 100644 --- a/src/Api/PubnubApi/EndPoint/ChannelGroup/AddChannelsToChannelGroupOperation.cs +++ b/src/Api/PubnubApi/EndPoint/ChannelGroup/AddChannelsToChannelGroupOperation.cs @@ -2,205 +2,202 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Text; namespace PubnubApi.EndPoint { - public class AddChannelsToChannelGroupOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pnTelemetryMgr; - - private string channelGroupName = ""; - private string[] channelNames; - private PNCallback savedCallback; - private Dictionary queryParam; - - public AddChannelsToChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pnTelemetryMgr = telemetryManager; - } - - public AddChannelsToChannelGroupOperation ChannelGroup(string channelGroup) - { - this.channelGroupName = channelGroup; - return this; - } - - public AddChannelsToChannelGroupOperation Channels(string[] channels) - { - this.channelNames = channels; - return this; - } - - public AddChannelsToChannelGroupOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - AddChannelsToChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - AddChannelsToChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await AddChannelsToChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - AddChannelsToChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - AddChannelsToChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void AddChannelsToChannelGroup(string[] channels, string nameSpace, string groupName, Dictionary externalQueryParam, PNCallback callback) - { - if (channels == null || channels.Length == 0) - { - throw new ArgumentException("Missing channel(s)"); - } - - if (nameSpace == null) - { - throw new ArgumentException("Missing nameSpace"); - } - - if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) - { - throw new ArgumentException("Missing groupName"); - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pnTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - string channelsCommaDelimited = string.Join(",", channels.OrderBy(x => x).ToArray()); - - Uri request = urlBuilder.BuildAddChannelsToChannelGroupRequest("GET", "", channelsCommaDelimited, nameSpace, groupName, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNAddChannelsToGroupOperation; - requestState.Channels = new string[] { }; - requestState.ChannelGroups = new [] { groupName }; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> AddChannelsToChannelGroup(string[] channels, string nameSpace, string groupName, Dictionary externalQueryParam) - { - if (channels == null || channels.Length == 0) - { - throw new ArgumentException("Missing channel(s)"); - } - - if (nameSpace == null) - { - throw new ArgumentException("Missing nameSpace"); - } - - if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) - { - throw new ArgumentException("Missing groupName"); - } - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pnTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - string channelsCommaDelimited = string.Join(",", channels.OrderBy(x => x).ToArray()); - - Uri request = urlBuilder.BuildAddChannelsToChannelGroupRequest("GET", "", channelsCommaDelimited, nameSpace, groupName, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNAddChannelsToGroupOperation; - requestState.Channels = new string[] { }; - requestState.ChannelGroups = new[] { groupName }; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNChannelGroupsAddChannelResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class AddChannelsToChannelGroupOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelGroupName = ""; + private string[] channelNames; + private PNCallback savedCallback; + private Dictionary queryParam; + + public AddChannelsToChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public AddChannelsToChannelGroupOperation ChannelGroup(string channelGroup) + { + this.channelGroupName = channelGroup; + return this; + } + + public AddChannelsToChannelGroupOperation Channels(string[] channels) + { + this.channelNames = channels; + return this; + } + + public AddChannelsToChannelGroupOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + AddChannelsToChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await AddChannelsToChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + AddChannelsToChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, savedCallback); + } + + internal void AddChannelsToChannelGroup(string[] channels, string nameSpace, string groupName, Dictionary externalQueryParam, PNCallback callback) + { + if (channels == null || channels.Length == 0) { + throw new ArgumentException("Missing channel(s)"); + } + + if (nameSpace == null) { + throw new ArgumentException("Missing nameSpace"); + } + + if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) { + throw new ArgumentException("Missing groupName"); + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNAddChannelsToGroupOperation; + requestState.Channels = new string[] { }; + requestState.ChannelGroups = new[] { groupName }; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAddChannelsToGroupOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(t.Result.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAddChannelsToGroupOperation, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNChannelGroupsAddChannelResult), status); + } + }); + } + + internal async Task> AddChannelsToChannelGroup(string[] channels, string nameSpace, string groupName, Dictionary externalQueryParam) + { + if (channels == null || channels.Length == 0) { + throw new ArgumentException("Missing channel(s)"); + } + + if (nameSpace == null) { + throw new ArgumentException("Missing nameSpace"); + } + + if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) { + throw new ArgumentException("Missing groupName"); + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNAddChannelsToGroupOperation; + requestState.Channels = new string[] { }; + requestState.ChannelGroups = new[] { groupName }; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + Tuple JsonAndStatusTuple; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNAddChannelsToGroupOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple("", errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNChannelGroupsAddChannelResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAccessManagerRevokeToken, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "channel-registration", + "sub-key", + config.SubscribeKey, + "channel-group", + channelGroupName + }; + + Dictionary requestQueryStringParams = new Dictionary + { + { "add", UriUtil.EncodeUriComponent(string.Join(",", channelNames.OrderBy(x => x).ToArray()), PNOperationType.PNAddChannelsToGroupOperation, false, false, false) } + }; + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNAddChannelsToGroupOperation, false, false, false)); + } + } + } + + string queryString = UriUtil.BuildQueryString(requestQueryStringParams); + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/ChannelGroup/DeleteChannelGroupOperation.cs b/src/Api/PubnubApi/EndPoint/ChannelGroup/DeleteChannelGroupOperation.cs index af125b23f..5cc70c7de 100644 --- a/src/Api/PubnubApi/EndPoint/ChannelGroup/DeleteChannelGroupOperation.cs +++ b/src/Api/PubnubApi/EndPoint/ChannelGroup/DeleteChannelGroupOperation.cs @@ -1,173 +1,179 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using System.Threading; using System.Net; +using System.Text; #if !NET35 && !NET40 using System.Collections.Concurrent; #endif namespace PubnubApi.EndPoint { - public class DeleteChannelGroupOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string channelGroupName = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public DeleteChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public DeleteChannelGroupOperation ChannelGroup(string channelGroup) - { - this.channelGroupName = channelGroup; - return this; - } - - public DeleteChannelGroupOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - DeleteChannelGroup(this.channelGroupName, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - DeleteChannelGroup(this.channelGroupName, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await DeleteChannelGroup(this.channelGroupName, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - DeleteChannelGroup(this.channelGroupName, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - DeleteChannelGroup(this.channelGroupName, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void DeleteChannelGroup(string groupName, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) - { - throw new ArgumentException("Missing groupName"); - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildRemoveChannelsFromChannelGroupRequest("GET", "", null, "", groupName, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNRemoveGroupOperation; - requestState.Channels = new string[] { }; - requestState.ChannelGroups = new [] { groupName }; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> DeleteChannelGroup(string groupName, Dictionary externalQueryParam) - { - if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) - { - throw new ArgumentException("Missing groupName"); - } - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildRemoveChannelsFromChannelGroupRequest("GET", "", null, "", groupName, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNRemoveGroupOperation; - requestState.Channels = new string[] { }; - requestState.ChannelGroups = new[] { groupName }; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNChannelGroupsDeleteGroupResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - - } + public class DeleteChannelGroupOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelGroupName = ""; + private PNCallback savedCallback; + private Dictionary queryParam; + + public DeleteChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public DeleteChannelGroupOperation ChannelGroup(string channelGroup) + { + this.channelGroupName = channelGroup; + return this; + } + + public DeleteChannelGroupOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + DeleteChannelGroup(this.channelGroupName, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await DeleteChannelGroup(this.channelGroupName, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + DeleteChannelGroup(this.channelGroupName, this.queryParam, savedCallback); + } + + internal void DeleteChannelGroup(string groupName, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) { + throw new ArgumentException("Missing groupName"); + } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNRemoveGroupOperation; + requestState.Channels = new string[] { }; + requestState.ChannelGroups = new[] { groupName }; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveGroupOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(t.Result.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveGroupOperation, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNChannelGroupsDeleteGroupResult), status); + } + }); + } + + internal async Task> DeleteChannelGroup(string groupName, Dictionary externalQueryParam) + { + if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) { + throw new ArgumentException("Missing groupName"); + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNRemoveGroupOperation; + requestState.Channels = new string[] { }; + requestState.ChannelGroups = new[] { groupName }; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveGroupOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple("", errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNChannelGroupsDeleteGroupResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveGroupOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + } + + private RequestParameter CreateRequestParameter() + { + + List pathSegments = new List + { + "v1", + "channel-registration", + "sub-key", + config.SubscribeKey, + "channel-group", + channelGroupName, + "remove" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNRemoveGroupOperation, false, false, false)); + } + } + } + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/ChannelGroup/ListAllChannelGroupOperation.cs b/src/Api/PubnubApi/EndPoint/ChannelGroup/ListAllChannelGroupOperation.cs index 36409c2c4..075c81b7e 100644 --- a/src/Api/PubnubApi/EndPoint/ChannelGroup/ListAllChannelGroupOperation.cs +++ b/src/Api/PubnubApi/EndPoint/ChannelGroup/ListAllChannelGroupOperation.cs @@ -1,152 +1,169 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Text; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class ListAllChannelGroupOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public ListAllChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public ListAllChannelGroupOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetAllChannelGroup(this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetAllChannelGroup(this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GetAllChannelGroup(this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetAllChannelGroup(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetAllChannelGroup(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void GetAllChannelGroup(Dictionary externalQueryParam, PNCallback callback) - { - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGetAllChannelGroupRequest("GET", "", externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.ChannelGroupAllGet; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> GetAllChannelGroup(Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGetAllChannelGroupRequest("GET", "", externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.ChannelGroupAllGet; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNChannelGroupsListAllResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class ListAllChannelGroupOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public ListAllChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public ListAllChannelGroupOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + GetAllChannelGroup(this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await GetAllChannelGroup(this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + GetAllChannelGroup(this.queryParam, savedCallback); + } + + internal void GetAllChannelGroup(Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.ChannelGroupAllGet; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.ChannelGroupAllGet); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(t.Result.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.ChannelGroupAllGet, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNChannelGroupsListAllResult), status); + } + }); + } + + internal async Task> GetAllChannelGroup(Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.ChannelGroupAllGet; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + Tuple JsonAndStatusTuple; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.ChannelGroupAllGet); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNChannelGroupsListAllResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.ChannelGroupAllGet, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "channel-registration", + "sub-key", + config.SubscribeKey, + "channel-group" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.ChannelGroupAllGet, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/ChannelGroup/ListChannelsForChannelGroupOperation.cs b/src/Api/PubnubApi/EndPoint/ChannelGroup/ListChannelsForChannelGroupOperation.cs index e939d0a03..a23921328 100644 --- a/src/Api/PubnubApi/EndPoint/ChannelGroup/ListChannelsForChannelGroupOperation.cs +++ b/src/Api/PubnubApi/EndPoint/ChannelGroup/ListChannelsForChannelGroupOperation.cs @@ -1,173 +1,184 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Text; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class ListChannelsForChannelGroupOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string channelGroupName = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public ListChannelsForChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - - public ListChannelsForChannelGroupOperation ChannelGroup(string channelGroup) - { - this.channelGroupName = channelGroup; - return this; - } - - public ListChannelsForChannelGroupOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetChannelsForChannelGroup(this.channelGroupName, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetChannelsForChannelGroup(this.channelGroupName, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GetChannelsForChannelGroup(this.channelGroupName, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetChannelsForChannelGroup(this.channelGroupName, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetChannelsForChannelGroup(this.channelGroupName, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void GetChannelsForChannelGroup(string groupName, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) - { - throw new ArgumentException("Missing groupName"); - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetChannelsForChannelGroupRequest("GET", "", null, groupName, false, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.ChannelGroupGet; - requestState.ChannelGroups = new [] { groupName }; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> GetChannelsForChannelGroup(string groupName, Dictionary externalQueryParam) - { - if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) - { - throw new ArgumentException("Missing groupName"); - } - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetChannelsForChannelGroupRequest("GET", "", null, groupName, false, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.ChannelGroupGet; - requestState.ChannelGroups = new[] { groupName }; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNChannelGroupsAllChannelsResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class ListChannelsForChannelGroupOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelGroupName = ""; + private PNCallback savedCallback; + private Dictionary queryParam; + + public ListChannelsForChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + + public ListChannelsForChannelGroupOperation ChannelGroup(string channelGroup) + { + this.channelGroupName = channelGroup; + return this; + } + + public ListChannelsForChannelGroupOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + GetChannelsForChannelGroup(this.channelGroupName, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await GetChannelsForChannelGroup(this.channelGroupName, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + GetChannelsForChannelGroup(this.channelGroupName, this.queryParam, savedCallback); + } + + internal void GetChannelsForChannelGroup(string groupName, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) { + throw new ArgumentException("Missing groupName"); + } + var requestParameter = CreateRequestParameter(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.ChannelGroupGet; + requestState.ChannelGroups = new[] { groupName }; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.ChannelGroupGet); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(t.Result.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.ChannelGroupGet, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNChannelGroupsAllChannelsResult), status); + } + }); + } + + internal async Task> GetChannelsForChannelGroup(string groupName, Dictionary externalQueryParam) + { + if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) { + throw new ArgumentException("Missing groupName"); + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.ChannelGroupGet; + requestState.ChannelGroups = new[] { groupName }; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.ChannelGroupGet); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNChannelGroupsAllChannelsResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.ChannelGroupGet, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "channel-registration", + "sub-key", + config.SubscribeKey, + "channel-group", + channelGroupName + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.ChannelGroupGet, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/ChannelGroup/RemoveChannelsFromChannelGroupOperation.cs b/src/Api/PubnubApi/EndPoint/ChannelGroup/RemoveChannelsFromChannelGroupOperation.cs index cc6a2c8a1..db93d2469 100644 --- a/src/Api/PubnubApi/EndPoint/ChannelGroup/RemoveChannelsFromChannelGroupOperation.cs +++ b/src/Api/PubnubApi/EndPoint/ChannelGroup/RemoveChannelsFromChannelGroupOperation.cs @@ -2,207 +2,214 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Text; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class RemoveChannelsFromChannelGroupOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string channelGroupName = ""; - private string[] channelNames; - private PNCallback savedCallback; - private Dictionary queryParam; - - public RemoveChannelsFromChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public RemoveChannelsFromChannelGroupOperation ChannelGroup(string channelGroup) - { - this.channelGroupName = channelGroup; - return this; - } - - public RemoveChannelsFromChannelGroupOperation Channels(string[] channels) - { - this.channelNames = channels; - return this; - } - - public RemoveChannelsFromChannelGroupOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - RemoveChannelsFromChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - RemoveChannelsFromChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await RemoveChannelsFromChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - RemoveChannelsFromChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - RemoveChannelsFromChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void RemoveChannelsFromChannelGroup(string[] channels, string nameSpace, string groupName, Dictionary externalQueryParam, PNCallback callback) - { - if (channels == null || channels.Length == 0) - { - throw new ArgumentException("Missing channel(s)"); - } - - if (nameSpace == null) - { - throw new ArgumentException("Missing nameSpace"); - } - - if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) - { - throw new ArgumentException("Missing groupName"); - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - string channelsCommaDelimited = string.Join(",", channels.OrderBy(x => x).ToArray()); - - - Uri request = urlBuilder.BuildRemoveChannelsFromChannelGroupRequest("GET", "", channelsCommaDelimited, nameSpace, groupName, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNRemoveChannelsFromGroupOperation; - requestState.Channels = new string[] { }; - requestState.ChannelGroups = new [] { groupName }; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> RemoveChannelsFromChannelGroup(string[] channels, string nameSpace, string groupName, Dictionary externalQueryParam) - { - if (channels == null || channels.Length == 0) - { - throw new ArgumentException("Missing channel(s)"); - } - - if (nameSpace == null) - { - throw new ArgumentException("Missing nameSpace"); - } - - if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) - { - throw new ArgumentException("Missing groupName"); - } - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - string channelsCommaDelimited = string.Join(",", channels.OrderBy(x => x).ToArray()); - - - Uri request = urlBuilder.BuildRemoveChannelsFromChannelGroupRequest("GET", "", channelsCommaDelimited, nameSpace, groupName, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNRemoveChannelsFromGroupOperation; - requestState.Channels = new string[] { }; - requestState.ChannelGroups = new[] { groupName }; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNChannelGroupsRemoveChannelResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class RemoveChannelsFromChannelGroupOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelGroupName = ""; + private string[] channelNames; + private PNCallback savedCallback; + private Dictionary queryParam; + + public RemoveChannelsFromChannelGroupOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public RemoveChannelsFromChannelGroupOperation ChannelGroup(string channelGroup) + { + this.channelGroupName = channelGroup; + return this; + } + + public RemoveChannelsFromChannelGroupOperation Channels(string[] channels) + { + this.channelNames = channels; + return this; + } + + public RemoveChannelsFromChannelGroupOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + RemoveChannelsFromChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await RemoveChannelsFromChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + RemoveChannelsFromChannelGroup(this.channelNames, "", this.channelGroupName, this.queryParam, savedCallback); + } + + internal void RemoveChannelsFromChannelGroup(string[] channels, string nameSpace, string groupName, Dictionary externalQueryParam, PNCallback callback) + { + if (channels == null || channels.Length == 0) { + throw new ArgumentException("Missing channel(s)"); + } + + if (nameSpace == null) { + throw new ArgumentException("Missing nameSpace"); + } + + if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) { + throw new ArgumentException("Missing groupName"); + } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNRemoveChannelsFromGroupOperation; + requestState.Channels = new string[] { }; + requestState.ChannelGroups = new[] { groupName }; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveChannelsFromGroupOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(t.Result.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveChannelsFromGroupOperation, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNChannelGroupsRemoveChannelResult), status); + } + }); + } + + internal async Task> RemoveChannelsFromChannelGroup(string[] channels, string nameSpace, string groupName, Dictionary externalQueryParam) + { + if (channels == null || channels.Length == 0) { + throw new ArgumentException("Missing channel(s)"); + } + + if (nameSpace == null) { + throw new ArgumentException("Missing nameSpace"); + } + + if (string.IsNullOrEmpty(groupName) || groupName.Trim().Length == 0) { + throw new ArgumentException("Missing groupName"); + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNRemoveChannelsFromGroupOperation; + requestState.Channels = new string[] { }; + requestState.ChannelGroups = new[] { groupName }; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveChannelsFromGroupOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNChannelGroupsRemoveChannelResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveChannelsFromGroupOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + + private RequestParameter CreateRequestParameter() + { + + List pathSegments = new List + { + "v1", + "channel-registration", + "sub-key", + config.SubscribeKey, + "channel-group", + channelGroupName + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (channelNames.Length > 0) { + string channelsCommaDelimited = string.Join(",", channelNames.OrderBy(x => x).ToArray()); + requestQueryStringParams.Add("remove", UriUtil.EncodeUriComponent(channelsCommaDelimited, PNOperationType.PNRemoveChannelsFromGroupOperation, false, false, false)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNRemoveChannelsFromGroupOperation, false, false, false)); + } + } + } + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Files/DeleteFileOperation.cs b/src/Api/PubnubApi/EndPoint/Files/DeleteFileOperation.cs index e24165d97..8b4431db8 100644 --- a/src/Api/PubnubApi/EndPoint/Files/DeleteFileOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Files/DeleteFileOperation.cs @@ -1,218 +1,204 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class DeleteFileOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNCallback savedCallback; - private Dictionary queryParam; - - private string channelName; - private string currentFileId; - private string currentFileName; - - public DeleteFileOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public DeleteFileOperation Channel(string channel) - { - this.channelName = channel; - return this; - } - - public DeleteFileOperation FileId(string fileId) - { - this.currentFileId = fileId; - return this; - } - - public DeleteFileOperation FileName(string fileName) - { - this.currentFileName = fileName; - return this; - } - - public DeleteFileOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - if (string.IsNullOrEmpty(this.channelName)) - { - throw new ArgumentException("Missing Channel Name"); - } - if (string.IsNullOrEmpty(this.currentFileId)) - { - throw new ArgumentException("Missing File Id"); - } - if (string.IsNullOrEmpty(this.currentFileName)) - { - throw new ArgumentException("Missing File Name"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - ProcessDeleteFileRequest(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - ProcessDeleteFileRequest(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await ProcessDeleteFileRequest(this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ProcessDeleteFileRequest(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ProcessDeleteFileRequest(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void ProcessDeleteFileRequest(Dictionary externalQueryParam, PNCallback callback) - { - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetFileUrlOrDeleteReqest("DELETE", "", this.channelName, this.currentFileId, this.currentFileName, externalQueryParam, PNOperationType.PNDeleteFileOperation); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNDeleteFileOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> ProcessDeleteFileRequest(Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(this.channelName)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Channel name", new ArgumentException("Invalid Channel name")) }; - ret.Status = errStatus; - return ret; - } - if (string.IsNullOrEmpty(this.currentFileId)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing File Id", new ArgumentException("Missing File Id")) }; - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(this.currentFileName)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid file name", new ArgumentException("Invalid file name")) }; - ret.Status = errStatus; - return ret; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetFileUrlOrDeleteReqest("DELETE", "", this.channelName, this.currentFileId, this.currentFileName, externalQueryParam, PNOperationType.PNDeleteFileOperation); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNDeleteFileOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNDeleteFileResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - } + public class DeleteFileOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNCallback savedCallback; + private Dictionary queryParam; + + private string channelName; + private string fileId; + private string fileName; + + public DeleteFileOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public DeleteFileOperation Channel(string channel) + { + this.channelName = channel; + return this; + } + + public DeleteFileOperation FileId(string fileId) + { + this.fileId = fileId; + return this; + } + + public DeleteFileOperation FileName(string fileName) + { + this.fileName = fileName; + return this; + } + + public DeleteFileOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + if (string.IsNullOrEmpty(this.channelName)) { + throw new ArgumentException("Missing Channel Name"); + } + if (string.IsNullOrEmpty(this.fileId)) { + throw new ArgumentException("Missing File Id"); + } + if (string.IsNullOrEmpty(this.fileName)) { + throw new ArgumentException("Missing File Name"); + } + + this.savedCallback = callback; + ProcessDeleteFileRequest(this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + return await ProcessDeleteFileRequest(this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + ProcessDeleteFileRequest(this.queryParam, savedCallback); + } + + private void ProcessDeleteFileRequest(Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNDeleteFileOperation; + requestState.PubnubCallback = callback; + requestState.UsePostMethod = false; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNDeleteFileOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNDeleteFileOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> ProcessDeleteFileRequest(Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(this.channelName)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Channel name", new ArgumentException("Invalid Channel name")) }; + returnValue.Status = errStatus; + return returnValue; + } + if (string.IsNullOrEmpty(this.fileId)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing File Id", new ArgumentException("Missing File Id")) }; + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(this.fileName)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid file name", new ArgumentException("Invalid file name")) }; + returnValue.Status = errStatus; + return returnValue; + } + var requestParameter = CreateRequestParameter(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNDeleteFileOperation; + requestState.Reconnect = false; + requestState.UsePostMethod = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNDeleteFileOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNDeleteFileResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNDeleteFileOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "files", + config.SubscribeKey, + "channels", + channelName, + "files", + fileId, + fileName + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNDeleteFileOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.DELETE, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Files/DownloadFileOperation.cs b/src/Api/PubnubApi/EndPoint/Files/DownloadFileOperation.cs index 93896da53..014d16dc1 100644 --- a/src/Api/PubnubApi/EndPoint/Files/DownloadFileOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Files/DownloadFileOperation.cs @@ -1,260 +1,233 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif using PubnubApi.Security.Crypto; using PubnubApi.Security.Crypto.Cryptors; namespace PubnubApi.EndPoint { - public class DownloadFileOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNCallback savedCallback; - private Dictionary queryParam; - - private string channelName; - private string currentFileId; - private string currentFileName; - private string currentFileCipherKey; - - public DownloadFileOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public DownloadFileOperation Channel(string channel) - { - this.channelName = channel; - return this; - } - - public DownloadFileOperation FileId(string fileId) - { - this.currentFileId = fileId; - return this; - } - - public DownloadFileOperation FileName(string fileName) - { - this.currentFileName = fileName; - return this; - } - - public DownloadFileOperation CipherKey(string cipherKeyForFile) - { - this.currentFileCipherKey = cipherKeyForFile; - return this; - } - - public DownloadFileOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - - if (string.IsNullOrEmpty(this.currentFileId)) - { - throw new ArgumentException("Missing File Id"); - } - if (string.IsNullOrEmpty(this.currentFileName)) - { - throw new ArgumentException("Missing File Name"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - ProcessFileDownloadRequest(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - ProcessFileDownloadRequest(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await ProcessFileDownloadRequest(this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ProcessFileDownloadRequest(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ProcessFileDownloadRequest(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void ProcessFileDownloadRequest(Dictionary externalQueryParam, PNCallback callback) - { - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetFileUrlOrDeleteReqest("GET", "", this.channelName, this.currentFileId, this.currentFileName, externalQueryParam, PNOperationType.PNDownloadFileOperation); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNDownloadFileOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - byte[] item1Bytes = null; - UrlProcessRequestForStream(request, requestState, false,"").ContinueWith(r => - { - item1Bytes = r.Result.Item1; - if (item1Bytes != null) - { - byte[] outputBytes = null; - if (string.IsNullOrEmpty(this.currentFileCipherKey) && string.IsNullOrEmpty(config.CipherKey) && config.CryptoModule == null) - { - outputBytes = item1Bytes; - } - else - { - CryptoModule currentCryptoModule = !string.IsNullOrEmpty(this.currentFileCipherKey) ? new CryptoModule(new LegacyCryptor(this.currentFileCipherKey, true, pubnubLog), null) : (config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, true, pubnubLog), null)); - try - { - outputBytes = currentCryptoModule.Decrypt(item1Bytes); - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Stream length (after Decrypt)= {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), item1Bytes.Length), config.LogVerbosity); - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine("{0}\nMessage might be not encrypted, returning as is...", ex.ToString()); - outputBytes = item1Bytes; - } - } - PNDownloadFileResult result = new PNDownloadFileResult(); - result.FileBytes = outputBytes; - result.FileName = currentFileName; - callback.OnResponse(result, r.Result.Item2); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - - - } - - private async Task> ProcessFileDownloadRequest(Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(this.currentFileId)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing File Id", new ArgumentException("Missing File Id")) }; - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(this.currentFileName)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid file name", new ArgumentException("Invalid file name")) }; - ret.Status = errStatus; - return ret; - } - - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetFileUrlOrDeleteReqest("GET", "", this.channelName, this.currentFileId, this.currentFileName, externalQueryParam, PNOperationType.PNDownloadFileOperation); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNDownloadFileOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequestForStream(request, requestState, false,"").ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - byte[] item1Bytes = JsonAndStatusTuple.Item1; - if (item1Bytes != null) - { - byte[] outputBytes = null; - if (string.IsNullOrEmpty(this.currentFileCipherKey) && string.IsNullOrEmpty(config.CipherKey) && config.CryptoModule == null) - { - outputBytes = item1Bytes; - } - else - { - CryptoModule currentCryptoModule = !string.IsNullOrEmpty(this.currentFileCipherKey) ? new CryptoModule(new LegacyCryptor(this.currentFileCipherKey, true, pubnubLog), null) : (config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, true, pubnubLog), null)); - try - { - outputBytes = currentCryptoModule.Decrypt(item1Bytes); - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Stream length (after Decrypt)= {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), item1Bytes.Length), config.LogVerbosity); - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine("{0}\nMessage might be not encrypted, returning as is...", ex.ToString()); - outputBytes = item1Bytes; - ret.Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Decryption error", ex) }; - } - } - - PNDownloadFileResult result = new PNDownloadFileResult(); - result.FileBytes = outputBytes; - result.FileName = currentFileName; - ret.Result = result; - } - - return ret; - } - - } + public class DownloadFileOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNCallback savedCallback; + private Dictionary queryParam; + + private string channelName; + private string currentFileId; + private string currentFileName; + private string currentFileCipherKey; + + public DownloadFileOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public DownloadFileOperation Channel(string channel) + { + this.channelName = channel; + return this; + } + + public DownloadFileOperation FileId(string fileId) + { + this.currentFileId = fileId; + return this; + } + + public DownloadFileOperation FileName(string fileName) + { + this.currentFileName = fileName; + return this; + } + + public DownloadFileOperation CipherKey(string cipherKeyForFile) + { + this.currentFileCipherKey = cipherKeyForFile; + return this; + } + + public DownloadFileOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + + if (string.IsNullOrEmpty(this.currentFileId)) { + throw new ArgumentException("Missing File Id"); + } + if (string.IsNullOrEmpty(this.currentFileName)) { + throw new ArgumentException("Missing File Name"); + } + + ProcessFileDownloadRequest(this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + return await ProcessFileDownloadRequest(this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + ProcessFileDownloadRequest(this.queryParam, savedCallback); + } + + private void ProcessFileDownloadRequest(Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNDownloadFileOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + byte[] fileContentBytes = null; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNDownloadFileOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + fileContentBytes = transportResponse.Content; + if (fileContentBytes != null) { + byte[] outputBytes = null; + if (string.IsNullOrEmpty(this.currentFileCipherKey) && string.IsNullOrEmpty(config.CipherKey) && config.CryptoModule == null) { + outputBytes = fileContentBytes; + } else { + CryptoModule currentCryptoModule = !string.IsNullOrEmpty(this.currentFileCipherKey) ? new CryptoModule(new LegacyCryptor(this.currentFileCipherKey, true, pubnubLog), null) : (config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, true, pubnubLog), null)); + try { + outputBytes = currentCryptoModule.Decrypt(fileContentBytes); + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Stream length (after Decrypt)= {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), fileContentBytes.Length), config.LogVerbosity); + } catch (Exception ex) { + System.Diagnostics.Debug.WriteLine("{0}\nMessage might be not encrypted, returning as is...", ex.ToString()); + outputBytes = fileContentBytes; + } + } + PNDownloadFileResult result = new PNDownloadFileResult(); + result.FileBytes = outputBytes; + result.FileName = currentFileName; + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, 200, null); + callback.OnResponse(result, status); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, null); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNDownloadFileOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + private async Task> ProcessFileDownloadRequest(Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(this.currentFileId)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing File Id", new ArgumentException("Missing File Id")) }; + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(this.currentFileName)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid file name", new ArgumentException("Invalid file name")) }; + returnValue.Status = errStatus; + return returnValue; + } + + + IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); + + Uri request = urlBuilder.BuildGetFileUrlOrDeleteReqest(Constants.GET, "", this.channelName, this.currentFileId, this.currentFileName, externalQueryParam, PNOperationType.PNDownloadFileOperation); + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNDownloadFileOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNDownloadFileOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + byte[] fileContentBytes = null; + if (transportResponse.Error == null) { + fileContentBytes = transportResponse.Content; + if (fileContentBytes != null) { + byte[] outputBytes = null; + if (string.IsNullOrEmpty(this.currentFileCipherKey) && string.IsNullOrEmpty(config.CipherKey) && config.CryptoModule == null) { + outputBytes = fileContentBytes; + } else { + CryptoModule currentCryptoModule = !string.IsNullOrEmpty(this.currentFileCipherKey) ? new CryptoModule(new LegacyCryptor(this.currentFileCipherKey, true, pubnubLog), null) : (config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, true, pubnubLog), null)); + try { + outputBytes = currentCryptoModule.Decrypt(fileContentBytes); + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Stream length (after Decrypt)= {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), fileContentBytes.Length), config.LogVerbosity); + } catch (Exception ex) { + System.Diagnostics.Debug.WriteLine("{0}\nFile content might be not encrypted, returning as is...", ex.ToString()); + outputBytes = fileContentBytes; + returnValue.Status = new PNStatus { Error = true, ErrorData = new PNErrorData("Decryption error", ex) }; + } + } + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + PNDownloadFileResult result = new PNDownloadFileResult(); + result.FileBytes = outputBytes; + result.FileName = currentFileName; + returnValue.Result = result; + returnValue.Status = status; + } else { + PNStatus errorStatus = GetStatusIfError(requestState, null); + returnValue.Status = errorStatus; + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNDownloadFileOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "files", + config.SubscribeKey, + "channels", + channelName, + "files", + currentFileId, + currentFileName + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNDownloadFileOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Files/GenerateFileUploadUrlOperation.cs b/src/Api/PubnubApi/EndPoint/Files/GenerateFileUploadUrlOperation.cs index bed5b7551..e0d60ec94 100644 --- a/src/Api/PubnubApi/EndPoint/Files/GenerateFileUploadUrlOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Files/GenerateFileUploadUrlOperation.cs @@ -1,179 +1,181 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Net; using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - internal class GenerateFileUploadUrlOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private Dictionary queryParam; - - private string channelName; - private string sendFileName; - - public GenerateFileUploadUrlOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public GenerateFileUploadUrlOperation Channel(string channel) - { - this.channelName = channel; - return this; - } - - public GenerateFileUploadUrlOperation FileName(string fileName) - { - this.sendFileName = fileName; - return this; - } - - public GenerateFileUploadUrlOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - - if (string.IsNullOrEmpty(this.sendFileName)) - { - throw new ArgumentException("Missing File Name"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GenerateFileUploadUrl(this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GenerateFileUploadUrl(this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GenerateFileUploadUrl(this.queryParam).ConfigureAwait(false); - } - - private void GenerateFileUploadUrl(Dictionary externalQueryParam, PNCallback callback) - { - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGenerateFileUploadUrlOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = true; - - Dictionary messageEnvelope = new Dictionary(); - if (!string.IsNullOrEmpty(sendFileName)) - { - messageEnvelope.Add("name", sendFileName); - } - string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGenerateFileUploadUrlRequest("POST", postMessage, this.channelName, externalQueryParam); - - UrlProcessRequest(request, requestState, false, postData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> GenerateFileUploadUrl(Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - if (string.IsNullOrEmpty(sendFileName)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid file name", new ArgumentException("Invalid file name")) }; - ret.Status = errStatus; - return ret; - } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGenerateFileUploadUrlOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = true; - - Dictionary messageEnvelope = new Dictionary(); - if (!string.IsNullOrEmpty(sendFileName)) - { - messageEnvelope.Add("name", sendFileName); - } - string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGenerateFileUploadUrlRequest("POST", postMessage, this.channelName, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, postData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNGenerateFileUploadUrlResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - } + internal class GenerateFileUploadUrlOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private Dictionary queryParam; + + private string channelName; + private string sendFileName; + + public GenerateFileUploadUrlOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + PubnubInstance = instance; + } + + public GenerateFileUploadUrlOperation Channel(string channel) + { + this.channelName = channel; + return this; + } + + public GenerateFileUploadUrlOperation FileName(string fileName) + { + this.sendFileName = fileName; + return this; + } + + public GenerateFileUploadUrlOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + + if (string.IsNullOrEmpty(this.sendFileName)) { + throw new ArgumentException("Missing File Name"); + } + + GenerateFileUploadUrl(this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await GenerateFileUploadUrl(this.queryParam).ConfigureAwait(false); + } + + private void GenerateFileUploadUrl(Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGenerateFileUploadUrlOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.UsePostMethod = true; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGenerateFileUploadUrlOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGenerateFileUploadUrlOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> GenerateFileUploadUrl(Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + if (string.IsNullOrEmpty(sendFileName)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid file name", new ArgumentException("Invalid file name")) }; + returnValue.Status = errStatus; + return returnValue; + } + + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGenerateFileUploadUrlOperation; + requestState.Reconnect = false; + requestState.UsePostMethod = true; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGenerateFileUploadUrlOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNGenerateFileUploadUrlResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGenerateFileUploadUrlOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "files", + config.SubscribeKey, + "channels", + channelName, + "generate-upload-url" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGenerateFileUploadUrlOperation, false, false, false)); + } + } + } + + Dictionary messageEnvelope = new Dictionary(); + if (!string.IsNullOrEmpty(sendFileName)) { + messageEnvelope.Add("name", sendFileName); + } + string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); + + var requestParameter = new RequestParameter() { + RequestType = Constants.POST, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = postMessage + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Files/GetFileUrlOperation.cs b/src/Api/PubnubApi/EndPoint/Files/GetFileUrlOperation.cs index 15f71572a..baced70dd 100644 --- a/src/Api/PubnubApi/EndPoint/Files/GetFileUrlOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Files/GetFileUrlOperation.cs @@ -1,24 +1,15 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class GetFileUrlOperation : PubnubCoreBase + public class GetFileUrlOperation : PubnubCoreBase { private readonly PNConfiguration config; private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; private PNCallback savedCallback; private Dictionary queryParam; @@ -27,29 +18,13 @@ public class GetFileUrlOperation : PubnubCoreBase private string currentFileId; private string currentFileName; - public GetFileUrlOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public GetFileUrlOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } + PubnubInstance = instance; } public GetFileUrlOperation Channel(string channel) @@ -90,21 +65,8 @@ public void Execute(PNCallback callback) { throw new ArgumentException("Missing File Name"); } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - ProcessGetFileUrl(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - ProcessGetFileUrl(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif + this.savedCallback = callback; + ProcessGetFileUrl(this.queryParam, savedCallback); } public async Task> ExecuteAsync() @@ -114,67 +76,84 @@ public async Task> ExecuteAsync() internal void Retry() { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ProcessGetFileUrl(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ProcessGetFileUrl(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif + ProcessGetFileUrl(this.queryParam, savedCallback); } private void ProcessGetFileUrl(Dictionary externalQueryParam, PNCallback callback) { - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetFileUrlOrDeleteReqest("GET", "", this.channelName, this.currentFileId, this.currentFileName, externalQueryParam, PNOperationType.PNFileUrlOperation); - + var requestParameter = CreateRequestParameter(); PNFileUrlResult result = new PNFileUrlResult(); - result.Url = request.ToString(); - + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNFileUrlOperation); + result.Url = transportRequest.RequestUrl; PNStatus status = new PNStatus { Error = false, StatusCode = 200 }; - callback.OnResponse(result, status); } - private async Task> ProcessGetFileUrl(Dictionary externalQueryParam) + private Task> ProcessGetFileUrl(Dictionary externalQueryParam) { - PNResult ret = new PNResult(); + var requestParameter = CreateRequestParameter(); + PNResult returnValue = new PNResult(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNFileUrlOperation); if (string.IsNullOrEmpty(this.currentFileId)) { PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing File Id", new ArgumentException("Missing File Id")) }; - ret.Status = errStatus; - return ret; + returnValue.Status = errStatus; + return Task.FromResult(returnValue); } if (string.IsNullOrEmpty(this.currentFileName)) { PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid file name", new ArgumentException("Invalid file name")) }; - ret.Status = errStatus; - return ret; + returnValue.Status = errStatus; + return Task.FromResult(returnValue); } - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetFileUrlOrDeleteReqest("GET", "", this.channelName, this.currentFileId, this.currentFileName, externalQueryParam, PNOperationType.PNFileUrlOperation); - PNFileUrlResult result = new PNFileUrlResult(); - result.Url = request.ToString(); + result.Url = transportRequest.RequestUrl; PNStatus status = new PNStatus { Error = false, StatusCode = 200 }; - ret.Result = result; - ret.Status = status; - await Task.Factory.StartNew(() =>{ }).ConfigureAwait(false);//dummy stmt. + returnValue.Result = result; + returnValue.Status = status; - return ret; + return Task.FromResult(returnValue); } + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "files", + config.SubscribeKey, + "channels", + channelName, + "files", + currentFileId, + currentFileName + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (queryParam != null && queryParam.Count > 0) + { + foreach (KeyValuePair kvp in queryParam) + { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) + { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNDownloadFileOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } } } diff --git a/src/Api/PubnubApi/EndPoint/Files/ListFilesOperation.cs b/src/Api/PubnubApi/EndPoint/Files/ListFilesOperation.cs index 68f5b264b..3f9d4ebc5 100644 --- a/src/Api/PubnubApi/EndPoint/Files/ListFilesOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Files/ListFilesOperation.cs @@ -1,197 +1,192 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Globalization; namespace PubnubApi.EndPoint { - public class ListFilesOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNCallback savedCallback; - private Dictionary queryParam; - - private string channelName; - private string nextFileBatchToken; - private int limitFileCount=-1; - - public ListFilesOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public ListFilesOperation Channel(string channel) - { - this.channelName = channel; - return this; - } - - public ListFilesOperation Limit(int count) - { - this.limitFileCount = count; - return this; - } - - public ListFilesOperation Next(string nextToken) - { - this.nextFileBatchToken = nextToken; - return this; - } - - public ListFilesOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - if (string.IsNullOrEmpty(this.channelName)) - { - throw new ArgumentException("Missing Channel Name"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - ProcessListFilesRequest(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - ProcessListFilesRequest(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await ProcessListFilesRequest(this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ProcessListFilesRequest(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ProcessListFilesRequest(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void ProcessListFilesRequest(Dictionary externalQueryParam, PNCallback callback) - { - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildListFilesReqest("GET", "", this.channelName, this.limitFileCount, this.nextFileBatchToken, externalQueryParam, PNOperationType.PNListFilesOperation); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNListFilesOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> ProcessListFilesRequest(Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(this.channelName)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Channel name", new ArgumentException("Invalid Channel name")) }; - ret.Status = errStatus; - return ret; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildListFilesReqest("GET", "", this.channelName, this.limitFileCount, this.nextFileBatchToken, externalQueryParam, PNOperationType.PNListFilesOperation); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNListFilesOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNListFilesResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - } + public class ListFilesOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNCallback savedCallback; + private Dictionary queryParam; + + private string channelName; + private string nextFileBatchToken; + private int limitFileCount = -1; + + public ListFilesOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public ListFilesOperation Channel(string channel) + { + this.channelName = channel; + return this; + } + + public ListFilesOperation Limit(int count) + { + this.limitFileCount = count; + return this; + } + + public ListFilesOperation Next(string nextToken) + { + this.nextFileBatchToken = nextToken; + return this; + } + + public ListFilesOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + if (string.IsNullOrEmpty(this.channelName)) { + throw new ArgumentException("Missing Channel Name"); + } + this.savedCallback = callback; + ProcessListFilesRequest(this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + return await ProcessListFilesRequest(this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + ProcessListFilesRequest(this.queryParam, savedCallback); + } + + private void ProcessListFilesRequest(Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNListFilesOperation; + requestState.PubnubCallback = callback; + requestState.UsePostMethod = false; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNListFilesOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNListFilesOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> ProcessListFilesRequest(Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(this.channelName)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Channel name", new ArgumentException("Invalid Channel name")) }; + returnValue.Status = errStatus; + return returnValue; + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNListFilesOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePostMethod = false; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNListFilesOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNListFilesResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNListFilesOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "files", + config.SubscribeKey, + "channels", + channelName, + "files" + }; + + Dictionary requestQueryStringParams = new Dictionary + { + { "limit", (limitFileCount <= -1) ? "100" : limitFileCount.ToString(CultureInfo.InvariantCulture) } + }; + if (!string.IsNullOrEmpty(nextFileBatchToken)) { + requestQueryStringParams.Add("next", nextFileBatchToken); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNListFilesOperation, false, false, false)); + } + } + } + + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Files/PublishFileMessage.cs b/src/Api/PubnubApi/EndPoint/Files/PublishFileMessage.cs index 5fc623dee..e6f2c2cd5 100644 --- a/src/Api/PubnubApi/EndPoint/Files/PublishFileMessage.cs +++ b/src/Api/PubnubApi/EndPoint/Files/PublishFileMessage.cs @@ -1,284 +1,281 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Net; using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Globalization; +using PubnubApi.Security.Crypto; +using PubnubApi.Security.Crypto.Cryptors; +using System.Net; namespace PubnubApi.EndPoint { - public class PublishFileMessageOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNCallback savedCallback; - private Dictionary queryParam; - - private string channelName; - private string currentFileId; - private string currentFileName; - private object msg; - private bool storeInHistory = true; - private Dictionary userMetadata; - private int ttl = -1; - - public PublishFileMessageOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public PublishFileMessageOperation Channel(string channel) - { - this.channelName = channel; - return this; - } - - public PublishFileMessageOperation Message(object message) - { - this.msg = message; - return this; - } - - public PublishFileMessageOperation ShouldStore(bool store) - { - this.storeInHistory = store; - return this; - } - - public PublishFileMessageOperation Meta(Dictionary metadata) - { - this.userMetadata = metadata; - return this; - } - - public PublishFileMessageOperation Ttl(int ttl) - { - this.ttl = ttl; - return this; - } - - public PublishFileMessageOperation FileId(string id) - { - this.currentFileId = id; - return this; - } - - public PublishFileMessageOperation FileName(string name) - { - this.currentFileName = name; - return this; - } - - public PublishFileMessageOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - - if (string.IsNullOrEmpty(this.currentFileId) || string.IsNullOrEmpty(this.currentFileName)) - { - throw new ArgumentException("Missing File Id or Name"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - ProcessFileMessagePublish(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - ProcessFileMessagePublish(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await ProcessFileMessagePublish(this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ProcessFileMessagePublish(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ProcessFileMessagePublish(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void ProcessFileMessagePublish(Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim())) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")); - callback.OnResponse(null, status); - return; - } - - Dictionary publishPayload = new Dictionary(); - if (this.msg != null && !string.IsNullOrEmpty(this.msg.ToString())) - { - publishPayload.Add("message", this.msg); - } - publishPayload.Add("file", new Dictionary { - { "id", currentFileId }, - { "name", currentFileName } }); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNPublishFileMessageOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildPublishFileMessageRequest("GET", "", this.channelName, publishPayload, this.storeInHistory, this.ttl, this.userMetadata, null, externalQueryParam); - - string json = ""; - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - json = r.Result.Item1; - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - - if (result != null && result.Count >= 3) - { - int publishStatus; - var _ = Int32.TryParse(result[0].ToString(), out publishStatus); - if (publishStatus == 1) - { - ProcessResponseCallbacks(result, requestState); - } - else - { - PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); - PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishFileMessageOperation, category, requestState, 400, new PNException(json)); - if (requestState.PubnubCallback != null) - { - requestState.PubnubCallback.OnResponse(default(PNPublishFileMessageResult), status); - } - } - } - else - { - ProcessResponseCallbacks(result, requestState); - } - } - } - - private async Task> ProcessFileMessagePublish(Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - if (string.IsNullOrEmpty(this.currentFileId) || string.IsNullOrEmpty(this.currentFileName)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing File Id or Name", new ArgumentException("Missing File Id or Name")) }; - ret.Status = errStatus; - return ret; - } - if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim())) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; - ret.Status = errStatus; - return ret; - } - - Dictionary publishPayload = new Dictionary(); - if (this.msg != null && !string.IsNullOrEmpty(this.msg.ToString())) - { - publishPayload.Add("message", this.msg); - } - publishPayload.Add("file", new Dictionary { - { "id", currentFileId }, - { "name", currentFileName } }); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNPublishFileMessageOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildPublishFileMessageRequest("GET", "", this.channelName, publishPayload, this.storeInHistory, this.ttl, this.userMetadata, null, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - - if (result != null && result.Count >= 3) - { - int publishStatus; - var _ = Int32.TryParse(result[0].ToString(), out publishStatus); - if (publishStatus == 1) - { - List resultList = ProcessJsonResponse(requestState, json); - if (resultList != null && resultList.Count > 0) - { - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNPublishFileMessageResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - } - } - } - - return ret; - } - - } + public class PublishFileMessageOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNCallback savedCallback; + private Dictionary queryParam; + + private string channelName; + private string currentFileId; + private string currentFileName; + private object publishMessageContent; + private bool storeInHistory = true; + private Dictionary userMetadata; + private int ttl = -1; + + public PublishFileMessageOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public PublishFileMessageOperation Channel(string channel) + { + this.channelName = channel; + return this; + } + + public PublishFileMessageOperation Message(object message) + { + this.publishMessageContent = message; + return this; + } + + public PublishFileMessageOperation ShouldStore(bool store) + { + this.storeInHistory = store; + return this; + } + + public PublishFileMessageOperation Meta(Dictionary metadata) + { + this.userMetadata = metadata; + return this; + } + + public PublishFileMessageOperation Ttl(int ttl) + { + this.ttl = ttl; + return this; + } + + public PublishFileMessageOperation FileId(string id) + { + this.currentFileId = id; + return this; + } + + public PublishFileMessageOperation FileName(string name) + { + this.currentFileName = name; + return this; + } + + public PublishFileMessageOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + + if (string.IsNullOrEmpty(this.currentFileId) || string.IsNullOrEmpty(this.currentFileName)) { + throw new ArgumentException("Missing File Id or Name"); + } + this.savedCallback = callback; + ProcessFileMessagePublish(this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + return await ProcessFileMessagePublish(this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + ProcessFileMessagePublish(this.queryParam, savedCallback); + } + + private void ProcessFileMessagePublish(Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim())) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")); + callback.OnResponse(null, status); + return; + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNPublishFileMessageOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNPublishOperation); + + PubnubInstance.transportMiddleware.Send(transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + if (result != null && result.Count >= 3) { + int publishStatus; + var _ = int.TryParse(result[0].ToString(), out publishStatus); + if (publishStatus == 1) { + ProcessResponseCallbacks(result, requestState); + } else { + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishFileMessageOperation, category, requestState, 400, new PNException(responseString)); + requestState.PubnubCallback.OnResponse(default, status); + + } + } else { + ProcessResponseCallbacks(result, requestState); + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishFileMessageOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> ProcessFileMessagePublish(Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + if (string.IsNullOrEmpty(this.currentFileId) || string.IsNullOrEmpty(this.currentFileName)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing File Id or Name", new ArgumentException("Missing File Id or Name")) }; + returnValue.Status = errStatus; + return returnValue; + } + if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim())) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; + returnValue.Status = errStatus; + return returnValue; + } + + var requestParameter = CreateRequestParameter(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNPublishFileMessageOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNPublishFileMessageOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest); + if (transportResponse.Error == null) { + string responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List result = ProcessJsonResponse(requestState, json); + + if (result != null && result.Count >= 3) { + int publishStatus; + var _ = int.TryParse(result[0].ToString(), out publishStatus); + if (publishStatus == 1) { + List resultList = ProcessJsonResponse(requestState, json); + if (resultList != null && resultList.Count > 0) { + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNPublishFileMessageResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishFileMessageOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + Dictionary publishPayload = new Dictionary(); + if (this.publishMessageContent != null && !string.IsNullOrEmpty(this.publishMessageContent.ToString())) { + publishPayload.Add("message", this.publishMessageContent); + } + publishPayload.Add("file", new Dictionary { + { "id", currentFileId }, + { "name", currentFileName } }); + List pathSegments = new List + { + "v1", + "files", + "publish-file", + config.PublishKey, + config.SubscribeKey, + "0", + channelName, + "0", + PrepareContent(publishPayload) + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (userMetadata != null) { + string jsonMetaData = jsonLibrary.SerializeToJsonString(userMetadata); + requestQueryStringParams.Add("meta", UriUtil.EncodeUriComponent(jsonMetaData, PNOperationType.PNPublishFileMessageOperation, false, false, false)); + } + + if (storeInHistory && ttl >= 0) { + requestQueryStringParams.Add("tt1", ttl.ToString(CultureInfo.InvariantCulture)); + } + + if (!storeInHistory) { + requestQueryStringParams.Add("store", "0"); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNPublishFileMessageOperation, false, false, false)); + } + } + } + var requestParameter = new RequestParameter() { + PathSegment = pathSegments, + RequestType = Constants.GET, + Query = requestQueryStringParams + }; + return requestParameter; + } + + private string PrepareContent(object originalMessage) + { + string message = jsonLibrary.SerializeToJsonString(originalMessage); + if (config.CryptoModule != null || config.CipherKey.Length > 0) { + config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, config.UseRandomInitializationVector, pubnubLog), null); + string encryptMessage = config.CryptoModule.Encrypt(message); + message = jsonLibrary.SerializeToJsonString(encryptMessage); + } + return message; + } + + } } diff --git a/src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs b/src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs index b6101ed69..84e6f13a8 100644 --- a/src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs @@ -2,543 +2,574 @@ using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; -using System.Net; using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif using PubnubApi.Security.Crypto; using PubnubApi.Security.Crypto.Cryptors; namespace PubnubApi.EndPoint { - public class SendFileOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private Dictionary queryParam; - - private string channelName; - private object publishMessage; - private string sendFileFullPath; - private string sendFileName = ""; - private byte[] sendFileBytes = null; - private string currentFileCipherKey; - private string currentFileId; - private bool storeInHistory = true; - private Dictionary userMetadata; - private int ttl = -1; - - public SendFileOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public SendFileOperation Channel(string channel) - { - this.channelName = channel; - return this; - } - - public SendFileOperation Message(object message) - { - this.publishMessage = message; - return this; - } - - public SendFileOperation ShouldStore(bool store) - { - this.storeInHistory = store; - return this; - } - - public SendFileOperation Meta(Dictionary metadata) - { - this.userMetadata = metadata; - return this; - } - - public SendFileOperation Ttl(int ttl) - { - this.ttl = ttl; - return this; - } - - public SendFileOperation File(string fileNameWithFullPath) - { - this.sendFileFullPath = fileNameWithFullPath; -#if !NETSTANDARD10 && !NETSTANDARD11 - // manually set filename should take precedence - if (System.IO.File.Exists(fileNameWithFullPath) && string.IsNullOrEmpty(sendFileName)) - { - sendFileName = System.IO.Path.GetFileName(fileNameWithFullPath); - } - return this; -#else - throw new NotSupportedException("FileSystem not supported in NetStandard 1.0/1.1. Consider higher version of .NetStandard."); -#endif - } - - public SendFileOperation File(byte[] byteArray) - { - this.sendFileBytes = byteArray ?? throw new ArgumentException("File byte array not provided."); - return this; - } - - public SendFileOperation FileName(string fileName) - { - if (string.IsNullOrEmpty(fileName)) - { - throw new ArgumentException("File name is missing"); - } - - if (fileName.Trim() != fileName) - { - throw new ArgumentException("File name should not contain leading or trailing whitespace"); - } - - this.sendFileName = fileName; - return this; - } - - public SendFileOperation CipherKey(string cipherKeyForFile) - { - this.currentFileCipherKey = cipherKeyForFile; - return this; - } - - public SendFileOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - - if (string.IsNullOrEmpty(this.sendFileName)) - { - throw new ArgumentException("Missing File"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ProcessFileUpload(this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ProcessFileUpload(this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await ProcessFileUpload(this.queryParam).ConfigureAwait(false); - } - - private void ProcessFileUpload(Dictionary externalQueryParam, PNCallback callback) - { - PNResult generateFileUploadUrl = GenerateFileUploadUrl(externalQueryParam).Result; - PNGenerateFileUploadUrlResult generateFileUploadUrlResult = generateFileUploadUrl.Result; - PNStatus generateFileUploadUrlStatus = generateFileUploadUrl.Status; - if (generateFileUploadUrlStatus.Error || generateFileUploadUrlResult == null) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Error in GenerateFileUploadUrl. Try again.", new ArgumentException("Error in GenerateFileUploadUrl. Try again.")) }; - if (callback != null) - { - callback.OnResponse(null, errStatus); - } - return; - } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNFileUploadOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = true; - - byte[] sendFileByteArray = sendFileBytes ?? GetByteArrayFromFilePath(sendFileFullPath); - - - string dataBoundary = String.Format(CultureInfo.InvariantCulture, "----------{0:N}", Guid.NewGuid()); - string contentType = "multipart/form-data; boundary=" + dataBoundary; - CryptoModule currentCryptoModule = null; - if (!string.IsNullOrEmpty(this.currentFileCipherKey) || !string.IsNullOrEmpty(config.CipherKey) || config.CryptoModule != null) - { - currentCryptoModule = !string.IsNullOrEmpty(this.currentFileCipherKey) ? new CryptoModule(new LegacyCryptor(this.currentFileCipherKey, true, pubnubLog), null) : (config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, true, pubnubLog), null)); - } - byte[] postData = GetMultipartFormData(sendFileByteArray,generateFileUploadUrlResult.FileName, generateFileUploadUrlResult.FileUploadRequest.FormFields, dataBoundary, currentCryptoModule, config, pubnubLog); - - string json; - UrlProcessRequest(new Uri(generateFileUploadUrlResult.FileUploadRequest.Url), requestState, false, postData, contentType).ContinueWith(r => - { - json = r.Result.Item1; - if (!string.IsNullOrEmpty(json) && string.Equals(json,"{}", StringComparison.OrdinalIgnoreCase)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl -> file upload OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); - //do internal publish after successful file upload - - Dictionary publishPayload = new Dictionary(); - if (this.publishMessage != null && !string.IsNullOrEmpty(this.publishMessage.ToString())){ - publishPayload.Add("message", this.publishMessage); - } - publishPayload.Add("file", new Dictionary { - { "id", generateFileUploadUrlResult.FileId }, - { "name", generateFileUploadUrlResult.FileName } }); - - int publishFileRetryLimit = config.FileMessagePublishRetryLimit; - int currentFileRetryCount = 0; - bool publishFailed = false; - do - { - currentFileRetryCount += 1; - PNResult publishFileMessageResponse = PublishFileMessage(publishPayload, queryParam).Result; - PNPublishFileMessageResult publishFileMessage = publishFileMessageResponse.Result; - PNStatus publishFileMessageStatus = publishFileMessageResponse.Status; - if (publishFileMessageStatus != null && !publishFileMessageStatus.Error && publishFileMessage != null) - { - publishFailed = false; - PNFileUploadResult result = new PNFileUploadResult(); - result.Timetoken = publishFileMessage.Timetoken; - result.FileId = generateFileUploadUrlResult.FileId; - result.FileName = generateFileUploadUrlResult.FileName; - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl -> file upload -> PublishFileMessage -> OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); - r.Result.Item2.Error = false; - callback.OnResponse(result, r.Result.Item2); - } - else - { - publishFailed = true; - if (currentFileRetryCount == publishFileRetryLimit) - { - callback.OnResponse(null, publishFileMessageStatus); - } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} PublishFileMessage Failed. currentFileRetryCount={1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentFileRetryCount), config.LogVerbosity); -#if !NET35 && !NET40 - Task.Delay(1000).Wait(); -#else - Thread.Sleep(1000); -#endif - } - } - while (publishFailed && currentFileRetryCount <= publishFileRetryLimit); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> ProcessFileUpload(Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(this.sendFileName)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing File", new ArgumentException("Missing File")) }; - ret.Status = errStatus; - return ret; - } - - - PNResult generateFileUploadUrl = await GenerateFileUploadUrl(externalQueryParam).ConfigureAwait(false); - PNGenerateFileUploadUrlResult generateFileUploadUrlResult = generateFileUploadUrl.Result; - PNStatus generateFileUploadUrlStatus = generateFileUploadUrl.Status; - if (generateFileUploadUrlStatus.Error || generateFileUploadUrlResult == null) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Error in GenerateFileUploadUrl. Try again.", new ArgumentException("Error in GenerateFileUploadUrl. Try again.")) }; - ret.Status = errStatus; - return ret; - } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNFileUploadOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = true; - - byte[] sendFileByteArray = sendFileBytes ?? GetByteArrayFromFilePath(sendFileFullPath); - - string dataBoundary = String.Format(CultureInfo.InvariantCulture, "----------{0:N}", Guid.NewGuid()); - string contentType = "multipart/form-data; boundary=" + dataBoundary; - CryptoModule currentCryptoModule = null; - if (!string.IsNullOrEmpty(this.currentFileCipherKey) || !string.IsNullOrEmpty(config.CipherKey) || config.CryptoModule != null) - { - currentCryptoModule = !string.IsNullOrEmpty(this.currentFileCipherKey) ? new CryptoModule(new LegacyCryptor(this.currentFileCipherKey, true, pubnubLog), null) : (config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, true, pubnubLog), null)); - } - byte[] postData = GetMultipartFormData(sendFileByteArray, generateFileUploadUrlResult.FileName, generateFileUploadUrlResult.FileUploadRequest.FormFields, dataBoundary, currentCryptoModule, config, pubnubLog); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(new Uri(generateFileUploadUrlResult.FileUploadRequest.Url), requestState, false, postData, contentType).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl -> file upload OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); //do internal publish after successful file upload - - Dictionary publishPayload = new Dictionary(); - if (this.publishMessage != null && !string.IsNullOrEmpty(this.publishMessage.ToString())) - { - publishPayload.Add("message", this.publishMessage); - } - currentFileId = generateFileUploadUrlResult.FileId; - publishPayload.Add("file", new Dictionary { - { "id", generateFileUploadUrlResult.FileId }, - { "name", generateFileUploadUrlResult.FileName } }); - - int publishFileRetryLimit = config.FileMessagePublishRetryLimit; - int currentFileRetryCount = 0; - bool publishFailed = false; - do - { - currentFileRetryCount += 1; - PNResult publishFileMessageResponse = await PublishFileMessage(publishPayload, queryParam).ConfigureAwait(false); - PNPublishFileMessageResult publishFileMessage = publishFileMessageResponse.Result; - PNStatus publishFileMessageStatus = publishFileMessageResponse.Status; - if (publishFileMessageStatus != null && !publishFileMessageStatus.Error && publishFileMessage != null) - { - publishFailed = false; - PNFileUploadResult result = new PNFileUploadResult(); - result.Timetoken = publishFileMessage.Timetoken; - result.FileId = generateFileUploadUrlResult.FileId; - result.FileName = generateFileUploadUrlResult.FileName; - ret.Result = result; - ret.Status.Error = false; - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl -> file upload -> PublishFileMessage -> OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); //do internal publish after successful file upload - } - else - { - publishFailed = true; - ret.Status = publishFileMessageStatus; - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} PublishFileMessage Failed. currentFileRetryCount={1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentFileRetryCount), config.LogVerbosity); -#if !NET35 && !NET40 - Task.Delay(1000).Wait(); -#else - Thread.Sleep(1000); -#endif - } - } - while (publishFailed && currentFileRetryCount <= publishFileRetryLimit); - } - - return ret; - } - - private async Task> GenerateFileUploadUrl(Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGenerateFileUploadUrlOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = true; - - Dictionary messageEnvelope = new Dictionary(); - if (!string.IsNullOrEmpty(sendFileName)) - { - messageEnvelope.Add("name", sendFileName); - } - string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGenerateFileUploadUrlRequest("POST", postMessage, this.channelName, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, postData, "application/json").ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNGenerateFileUploadUrlResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private async Task> PublishFileMessage(object message, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildPublishFileMessageRequest("GET", "", this.channelName, message, this.storeInHistory, this.ttl, this.userMetadata, null, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { this.channelName }; - requestState.ResponseType = PNOperationType.PNPublishFileMessageOperation; - requestState.PubnubCallback = null; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - string json = ""; - - await UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNPublishFileMessageResult publishResult = responseBuilder.JsonToObject(result, true); - StatusBuilder statusBuilder = new StatusBuilder(config, jsonLibrary); - if (publishResult != null) - { - ret.Result = publishResult; - PNStatus status = statusBuilder.CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); - ret.Status = status; - } - else - { - PNException ex = new PNException("File has been upload but the notification couldn't be sent to the subscribed users"); - PNStatus status = statusBuilder.CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNUnknownCategory, requestState, (int)HttpStatusCode.BadRequest, ex); - status.AdditonalData = new Dictionary { {"FileId", currentFileId }, {"FileName", sendFileName } }; - ret.Status = status; - } - } - else - { - ret.Status = r.Result.Item2; - if (ret.Status == null) - { - PNException ex = new PNException("PublishFileMessage failed."); - StatusBuilder statusBuilder = new StatusBuilder(config, jsonLibrary); - PNStatus status = statusBuilder.CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNUnknownCategory, requestState, (int)HttpStatusCode.BadRequest, ex); - status.AdditonalData = new Dictionary { { "FileId", currentFileId }, { "FileName", sendFileName } }; - ret.Status = status; - } - } - }, TaskContinuationOptions.ExecuteSynchronously); - - return ret; - } - - private static byte[] GetByteArrayFromFilePath(string filePath) - { -#if !NETSTANDARD10 && !NETSTANDARD11 - byte[] byteArray = null; - if (!string.IsNullOrEmpty(filePath)) - { - byteArray = System.IO.File.ReadAllBytes(filePath); - } - return byteArray; -#else - throw new NotSupportedException("FileSystem not supported in NetStandard 1.0/1.1. Consider higher version of .NetStandard."); -#endif - - } - - private static byte[] GetMultipartFormData(byte[] sendFileByteArray, string fileName, Dictionary formFields, string dataBoundary, CryptoModule currentCryptoModule, PNConfiguration config, IPubnubLog pubnubLog) - { - byte[] ret = null; - string fileContentType = "application/octet-stream"; - using (Stream dataStream = new System.IO.MemoryStream()) - { - foreach (var kvp in formFields) - { - if (kvp.Key == "Content-Type" && kvp.Value != null && !string.IsNullOrEmpty(kvp.Value.ToString())) - { - fileContentType = kvp.Value.ToString(); - } - string postParamData = string.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", - dataBoundary, - kvp.Key, - kvp.Value); - byte[] postParam = Encoding.UTF8.GetBytes(postParamData); - dataStream.Write(postParam, 0, postParam.Length); - - string emptyLine = "\r\n"; - byte[] emptyData = Encoding.UTF8.GetBytes(emptyLine); - dataStream.Write(emptyData, 0, emptyData.Length); - } - string header = string.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n", - dataBoundary, - "file", - fileName, - fileContentType); - byte[] postHeaderData = Encoding.UTF8.GetBytes(header); - - dataStream.Write(postHeaderData, 0, postHeaderData.Length); - if (currentCryptoModule != null) - { - try - { - byte[] encryptBytes = currentCryptoModule.Encrypt(sendFileByteArray); - dataStream.Write(encryptBytes, 0, encryptBytes.Length); - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine(ex.ToString()); - } - } - else - { - dataStream.Write(sendFileByteArray, 0, sendFileByteArray.Length); - } - - string footer = "\r\n--" + dataBoundary + "--\r\n"; - byte[] postFooterData = Encoding.UTF8.GetBytes(footer); - dataStream.Write(postFooterData, 0, postFooterData.Length); - - dataStream.Position = 0; - ret = new byte[dataStream.Length]; - int bytesRead = dataStream.Read(ret, 0, ret.Length); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "MultipartFormData byte count = {0}", bytesRead)); -#if NET35 || NET40 || NET45 || NET461 || NET48 - dataStream.Close(); -#endif - } - return ret; - } - } + public class SendFileOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private Dictionary queryParam; + + private string channelName; + private object publishFileMessageContent; + private string sendFileFullPath; + private string sendFileName = string.Empty; + private byte[] sendFileBytes = null; + private string currentFileCipherKey; + private string currentFileId; + private bool storeInHistory = true; + private Dictionary userMetadata; + private int ttl = -1; + + public SendFileOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public SendFileOperation Channel(string channel) + { + this.channelName = channel; + return this; + } + + public SendFileOperation Message(object message) + { + this.publishFileMessageContent = message; + return this; + } + + public SendFileOperation ShouldStore(bool store) + { + this.storeInHistory = store; + return this; + } + + public SendFileOperation Meta(Dictionary metadata) + { + this.userMetadata = metadata; + return this; + } + + public SendFileOperation Ttl(int ttl) + { + this.ttl = ttl; + return this; + } + + public SendFileOperation File(string fileNameWithFullPath) + { + this.sendFileFullPath = fileNameWithFullPath; + + if (System.IO.File.Exists(fileNameWithFullPath) && string.IsNullOrEmpty(sendFileName)) { + sendFileName = Path.GetFileName(fileNameWithFullPath); + } + return this; + } + + public SendFileOperation File(byte[] byteArray) + { + this.sendFileBytes = byteArray ?? throw new ArgumentException("File byte array not provided."); + return this; + } + + public SendFileOperation FileName(string fileName) + { + if (string.IsNullOrEmpty(fileName)) { + throw new ArgumentException("File name is missing"); + } + + if (fileName.Trim() != fileName) { + throw new ArgumentException("File name should not contain leading or trailing whitespace"); + } + + this.sendFileName = fileName; + return this; + } + + public SendFileOperation CipherKey(string cipherKeyForFile) + { + this.currentFileCipherKey = cipherKeyForFile; + return this; + } + + public SendFileOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + + if (string.IsNullOrEmpty(this.sendFileName)) { + throw new ArgumentException("Missing File"); + } + ProcessFileUpload(this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await ProcessFileUpload(this.queryParam).ConfigureAwait(false); + } + + private void ProcessFileUpload(Dictionary externalQueryParam, PNCallback callback) + { + PNResult generateFileUploadUrl = GenerateFileUploadUrl(externalQueryParam).Result; + PNGenerateFileUploadUrlResult generateFileUploadUrlResult = generateFileUploadUrl.Result; + PNStatus generateFileUploadUrlStatus = generateFileUploadUrl.Status; + + if (generateFileUploadUrlStatus.Error || generateFileUploadUrlResult == null) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Error in GenerateFileUploadUrl. Try again.", new ArgumentException("Error in GenerateFileUploadUrl. Try again.")) }; + if (callback != null) { + callback.OnResponse(null, errStatus); + } + return; + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNFileUploadOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePostMethod = true; + byte[] sendFileByteArray = sendFileBytes ?? GetByteArrayFromFilePath(sendFileFullPath); + string dataBoundary = string.Format(CultureInfo.InvariantCulture, "----------{0:N}", Guid.NewGuid()); + string contentType = "multipart/form-data; boundary=" + dataBoundary; + CryptoModule currentCryptoModule = null; + if (!string.IsNullOrEmpty(this.currentFileCipherKey) || !string.IsNullOrEmpty(config.CipherKey) || config.CryptoModule != null) { + currentCryptoModule = !string.IsNullOrEmpty(this.currentFileCipherKey) ? new CryptoModule(new LegacyCryptor(this.currentFileCipherKey, true, pubnubLog), null) : (config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, true, pubnubLog), null)); + } + byte[] postData = GetMultipartFormData(sendFileByteArray, generateFileUploadUrlResult.FileName, generateFileUploadUrlResult.FileUploadRequest.FormFields, dataBoundary, currentCryptoModule, config, pubnubLog); + var transportRequest = new TransportRequest() { + RequestType = Constants.POST, + RequestUrl = generateFileUploadUrlResult.FileUploadRequest.Url, + BodyContentBytes = postData, + }; + transportRequest.Headers.Add("Content-Type", contentType); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + if (transportResponse.StatusCode == 204 && transportResponse.Error == null) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl -> file upload OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); + Dictionary publishPayload = new Dictionary(); + if (this.publishFileMessageContent != null && !string.IsNullOrEmpty(this.publishFileMessageContent.ToString())) { + publishPayload.Add("message", this.publishFileMessageContent); + } + currentFileId = generateFileUploadUrlResult.FileId; + sendFileName = generateFileUploadUrlResult.FileName; + publishPayload.Add("file", new Dictionary { + { "id", generateFileUploadUrlResult.FileId }, + { "name", generateFileUploadUrlResult.FileName } }); + int publishFileRetryLimit = config.FileMessagePublishRetryLimit; + int currentFileRetryCount = 0; + bool publishFailed = false; + do { + currentFileRetryCount += 1; + PNResult publishFileMessageResponse = PublishFileMessage(publishPayload, queryParam).Result; + PNPublishFileMessageResult publishFileMessage = publishFileMessageResponse.Result; + PNStatus publishFileMessageStatus = publishFileMessageResponse.Status; + if (publishFileMessageStatus != null && !publishFileMessageStatus.Error && publishFileMessage != null) { + publishFailed = false; + PNFileUploadResult result = new PNFileUploadResult(); + result.Timetoken = publishFileMessage.Timetoken; + result.FileId = generateFileUploadUrlResult.FileId; + result.FileName = generateFileUploadUrlResult.FileName; + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl -> file upload -> PublishFileMessage -> OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); + var status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, 200, null); + callback.OnResponse(result, status); + } else { + publishFailed = true; + if (currentFileRetryCount == publishFileRetryLimit) { + callback.OnResponse(null, publishFileMessageStatus); + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} PublishFileMessage Failed. currentFileRetryCount={1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentFileRetryCount), config.LogVerbosity); + Task.Delay(1000).Wait(); + } + } + while (publishFailed && currentFileRetryCount <= publishFileRetryLimit); + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNFileUploadOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + } + }); + } + + private async Task> ProcessFileUpload(Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(this.sendFileName)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing File", new ArgumentException("Missing File")) }; + returnValue.Status = errStatus; + return returnValue; + } + PNResult generateFileUploadUrl = await GenerateFileUploadUrl(externalQueryParam).ConfigureAwait(false); + PNGenerateFileUploadUrlResult generateFileUploadUrlResult = generateFileUploadUrl.Result; + PNStatus generateFileUploadUrlStatus = generateFileUploadUrl.Status; + if (generateFileUploadUrlStatus.Error || generateFileUploadUrlResult == null) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Error in GenerateFileUploadUrl. Try again.", new ArgumentException("Error in GenerateFileUploadUrl. Try again.")) }; + returnValue.Status = errStatus; + return returnValue; + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNFileUploadOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + requestState.UsePostMethod = true; + + byte[] sendFileByteArray = sendFileBytes ?? GetByteArrayFromFilePath(sendFileFullPath); + + string dataBoundary = string.Format(CultureInfo.InvariantCulture, "----------{0:N}", Guid.NewGuid()); + string contentType = "multipart/form-data; boundary=" + dataBoundary; + CryptoModule currentCryptoModule = null; + if (!string.IsNullOrEmpty(currentFileCipherKey) || !string.IsNullOrEmpty(config.CipherKey) || config.CryptoModule != null) { + currentCryptoModule = !string.IsNullOrEmpty(this.currentFileCipherKey) ? new CryptoModule(new LegacyCryptor(this.currentFileCipherKey, true, pubnubLog), null) : (config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, true, pubnubLog), null)); + } + byte[] postData = GetMultipartFormData(sendFileByteArray, generateFileUploadUrlResult.FileName, generateFileUploadUrlResult.FileUploadRequest.FormFields, dataBoundary, currentCryptoModule, config, pubnubLog); + var transportRequest = new TransportRequest() { + RequestType = Constants.POST, + RequestUrl = generateFileUploadUrlResult.FileUploadRequest.Url, + BodyContentBytes = postData, + }; + transportRequest.Headers.Add("Content-Type", contentType); + Tuple JsonAndStatusTuple; + string responseString; + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.StatusCode == 204 && transportResponse.Error == null) { + responseString = "{}"; + PNStatus errStatus = GetStatusIfError(requestState, responseString); + if (errStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, 200, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNFileUploadOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + JsonAndStatusTuple = new Tuple(string.Empty, status); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl -> file upload OK.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); //do internal publish after successful file upload + + Dictionary publishPayload = new Dictionary(); + if (this.publishFileMessageContent != null && !string.IsNullOrEmpty(this.publishFileMessageContent.ToString())) { + publishPayload.Add("message", this.publishFileMessageContent); + } + currentFileId = generateFileUploadUrlResult.FileId; + sendFileName = generateFileUploadUrlResult.FileName; + publishPayload.Add("file", new Dictionary { + { "id", generateFileUploadUrlResult.FileId }, + { "name", generateFileUploadUrlResult.FileName } }); + + int publishFileRetryLimit = config.FileMessagePublishRetryLimit; + int currentFileRetryCount = 0; + bool publishFailed; + do { + currentFileRetryCount += 1; + PNResult publishFileMessageResponse = await PublishFileMessage(publishPayload, queryParam).ConfigureAwait(false); + PNPublishFileMessageResult publishFileMessage = publishFileMessageResponse.Result; + PNStatus publishFileMessageStatus = publishFileMessageResponse.Status; + if (publishFileMessageStatus != null && !publishFileMessageStatus.Error && publishFileMessage != null) { + publishFailed = false; + PNFileUploadResult result = new PNFileUploadResult(); + result.Timetoken = publishFileMessage.Timetoken; + result.FileId = generateFileUploadUrlResult.FileId; + result.FileName = generateFileUploadUrlResult.FileName; + returnValue.Result = result; + returnValue.Status.Error = false; + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} GenerateFileUploadUrl -> file upload -> PublishFileMessage -> Success.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.LogVerbosity); //do internal publish after successful file upload + } else { + publishFailed = true; + returnValue.Status = publishFileMessageStatus; + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} PublishFileMessage Failed. currentFileRetryCount={1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentFileRetryCount), config.LogVerbosity); + Task.Delay(1000).Wait(); + } + } + while (publishFailed && currentFileRetryCount <= publishFileRetryLimit); + } + + return returnValue; + } + + private async Task> GenerateFileUploadUrl(Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + if (string.IsNullOrEmpty(sendFileName)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid file name", new ArgumentException("Invalid file name")) }; + returnValue.Status = errStatus; + return returnValue; + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGenerateFileUploadUrlOperation; + requestState.Reconnect = false; + requestState.UsePostMethod = true; + requestState.EndPointOperation = this; + + var requestParameter = CreateFileUploadUrlRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGenerateFileUploadUrlOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNGenerateFileUploadUrlResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGenerateFileUploadUrlOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private async Task> PublishFileMessage(object message, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + var requestParameter = CreatePublishFileMessageRequestParameter(); + RequestState requestState = new RequestState(); + requestState.Channels = new[] { this.channelName }; + requestState.ResponseType = PNOperationType.PNPublishFileMessageOperation; + requestState.PubnubCallback = null; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNPublishFileMessageOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest); + if (transportResponse.Error == null) { + string responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNPublishFileMessageResult publishResult = responseBuilder.JsonToObject(result, true); + StatusBuilder statusBuilder = new StatusBuilder(config, jsonLibrary); + if (publishResult != null) { + returnValue.Result = publishResult; + PNStatus status = statusBuilder.CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + returnValue.Status = status; + } else { + PNException ex = new PNException("File has been upload but the notification couldn't be sent to the subscribed users"); + PNStatus status = statusBuilder.CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNUnknownCategory, requestState, 400, ex); + status.AdditonalData = new Dictionary { { "FileId", currentFileId }, { "FileName", sendFileName } }; + returnValue.Status = status; + } + } else { + returnValue.Status = GetStatusIfError(requestState, responseString); + if (returnValue.Status == null) { + PNException ex = new PNException("PublishFileMessage failed."); + StatusBuilder statusBuilder = new StatusBuilder(config, jsonLibrary); + PNStatus status = statusBuilder.CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNUnknownCategory, requestState, 400, ex); + status.AdditonalData = new Dictionary { { "FileId", currentFileId }, { "FileName", sendFileName } }; + returnValue.Status = status; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishFileMessageOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private static byte[] GetByteArrayFromFilePath(string filePath) + { + byte[] byteArray = null; + if (!string.IsNullOrEmpty(filePath)) { + byteArray = System.IO.File.ReadAllBytes(filePath); + } + return byteArray; + } + + private static byte[] GetMultipartFormData(byte[] sendFileByteArray, string fileName, Dictionary formFields, string dataBoundary, CryptoModule currentCryptoModule, PNConfiguration config, IPubnubLog pubnubLog) + { + byte[] ret = null; + string fileContentType = "application/octet-stream"; + using (Stream dataStream = new MemoryStream()) { + foreach (var kvp in formFields) { + if (kvp.Key == "Content-Type" && kvp.Value != null && !string.IsNullOrEmpty(kvp.Value.ToString())) { + fileContentType = kvp.Value.ToString(); + } + string postParamData = string.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", + dataBoundary, + kvp.Key, + kvp.Value); + byte[] postParam = Encoding.UTF8.GetBytes(postParamData); + dataStream.Write(postParam, 0, postParam.Length); + + string emptyLine = "\r\n"; + byte[] emptyData = Encoding.UTF8.GetBytes(emptyLine); + dataStream.Write(emptyData, 0, emptyData.Length); + } + string header = string.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n", + dataBoundary, + "file", + fileName, + fileContentType); + byte[] postHeaderData = Encoding.UTF8.GetBytes(header); + + dataStream.Write(postHeaderData, 0, postHeaderData.Length); + if (currentCryptoModule != null) { + try { + byte[] encryptBytes = currentCryptoModule.Encrypt(sendFileByteArray); + dataStream.Write(encryptBytes, 0, encryptBytes.Length); + } catch (Exception ex) { + System.Diagnostics.Debug.WriteLine(ex.ToString()); + } + } else { + dataStream.Write(sendFileByteArray, 0, sendFileByteArray.Length); + } + + string footer = "\r\n--" + dataBoundary + "--\r\n"; + byte[] postFooterData = Encoding.UTF8.GetBytes(footer); + dataStream.Write(postFooterData, 0, postFooterData.Length); + + dataStream.Position = 0; + ret = new byte[dataStream.Length]; + int bytesRead = dataStream.Read(ret, 0, ret.Length); + System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "MultipartFormData byte count = {0}", bytesRead)); + } + return ret; + } + + private RequestParameter CreateFileUploadUrlRequestParameter() + { + List pathSegments = new List + { + "v1", + "files", + config.SubscribeKey, + "channels", + channelName, + "generate-upload-url" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGenerateFileUploadUrlOperation, false, false, false)); + } + } + } + + Dictionary messageEnvelope = new Dictionary(); + if (!string.IsNullOrEmpty(sendFileName)) { + messageEnvelope.Add("name", sendFileName); + } + string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); + + var requestParameter = new RequestParameter() { + RequestType = Constants.POST, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = postMessage + }; + return requestParameter; + } + + private RequestParameter CreatePublishFileMessageRequestParameter() + { + Dictionary publishPayload = new Dictionary(); + if (this.publishFileMessageContent != null && !string.IsNullOrEmpty(this.publishFileMessageContent.ToString())) { + publishPayload.Add("message", this.publishFileMessageContent); + } + publishPayload.Add("file", new Dictionary { + { "id", currentFileId }, + { "name", sendFileName } }); + List pathSegments = new List + { + "v1", + "files", + "publish-file", + config.PublishKey, + config.SubscribeKey, + "0", + channelName, + "0", + PrepareContent(publishPayload) + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (userMetadata != null) { + string jsonMetaData = jsonLibrary.SerializeToJsonString(userMetadata); + requestQueryStringParams.Add("meta", UriUtil.EncodeUriComponent(jsonMetaData, PNOperationType.PNPublishFileMessageOperation, false, false, false)); + } + + if (storeInHistory && ttl >= 0) { + requestQueryStringParams.Add("tt1", ttl.ToString(CultureInfo.InvariantCulture)); + } + + if (!storeInHistory) { + requestQueryStringParams.Add("store", "0"); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNPublishFileMessageOperation, false, false, false)); + } + } + } + var requestParameter = new RequestParameter() { + PathSegment = pathSegments, + RequestType = Constants.GET, + Query = requestQueryStringParams + }; + return requestParameter; + } + + private string PrepareContent(object originalMessage) + { + string message = jsonLibrary.SerializeToJsonString(originalMessage); + if (config.CryptoModule != null || config.CipherKey.Length > 0) { + config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, config.UseRandomInitializationVector, pubnubLog), null); + string encryptMessage = config.CryptoModule.Encrypt(message); + message = jsonLibrary.SerializeToJsonString(encryptMessage); + } + return message; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/GetAllChannelMetadataOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/GetAllChannelMetadataOperation.cs index 530c21fcf..81d1dfe21 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/GetAllChannelMetadataOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/GetAllChannelMetadataOperation.cs @@ -1,202 +1,235 @@ using System; using System.Collections.Generic; -using System.Threading; using System.Net; using System.Threading.Tasks; -#if !NET35 && !NET40 +using System.Globalization; +using System.Text; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class GetAllChannelMetadataOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private int limit = -1; - private bool includeCount; - private bool includeCustom; - private string channelsFilter; - private PNPageObject page; - private List sortField; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public GetAllChannelMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public GetAllChannelMetadataOperation Page(PNPageObject pageObject) - { - this.page = pageObject; - return this; - } - - public GetAllChannelMetadataOperation Limit(int numberOfChannels) - { - this.limit = numberOfChannels; - return this; - } - - public GetAllChannelMetadataOperation IncludeCount(bool includeTotalCount) - { - this.includeCount = includeTotalCount; - return this; - } - - public GetAllChannelMetadataOperation IncludeCustom(bool includeCustomData) - { - this.includeCustom = includeCustomData; - return this; - } - - public GetAllChannelMetadataOperation Filter(string filterExpression) - { - this.channelsFilter = filterExpression; - return this; - } - - public GetAllChannelMetadataOperation Sort(List sortByField) - { - this.sortField = sortByField; - return this; - } - - public GetAllChannelMetadataOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetAllChannelMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.channelsFilter, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetAllChannelMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.channelsFilter, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GetAllChannelMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.channelsFilter, this.sortField, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetAllChannelMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.channelsFilter, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetAllChannelMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.channelsFilter, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void GetAllChannelMetadataList(PNPageObject page, int limit, bool includeCount, bool includeCustom, string filter, List sort, Dictionary externalQueryParam, PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGetAllChannelMetadataRequest("GET", "", internalPage.Next, internalPage.Prev, limit, includeCount, includeCustom, filter, sort, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetAllChannelMetadataOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> GetAllChannelMetadataList(PNPageObject page, int limit, bool includeCount, bool includeCustom, string filter, List sort, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGetAllChannelMetadataRequest("GET", "", internalPage.Next, internalPage.Prev, limit, includeCount, includeCustom, filter, sort, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetAllChannelMetadataOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNGetAllChannelMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - } + public class GetAllChannelMetadataOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private int limit = -1; + private bool includeCount; + private bool includeCustom; + private string channelsFilter; + private PNPageObject page; + private List sortField; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public GetAllChannelMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public GetAllChannelMetadataOperation Page(PNPageObject pageObject) + { + this.page = pageObject; + return this; + } + + public GetAllChannelMetadataOperation Limit(int numberOfChannels) + { + this.limit = numberOfChannels; + return this; + } + + public GetAllChannelMetadataOperation IncludeCount(bool includeTotalCount) + { + this.includeCount = includeTotalCount; + return this; + } + + public GetAllChannelMetadataOperation IncludeCustom(bool includeCustomData) + { + this.includeCustom = includeCustomData; + return this; + } + + public GetAllChannelMetadataOperation Filter(string filterExpression) + { + this.channelsFilter = filterExpression; + return this; + } + + public GetAllChannelMetadataOperation Sort(List sortByField) + { + this.sortField = sortByField; + return this; + } + + public GetAllChannelMetadataOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + GetAllChannelMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.channelsFilter, this.sortField, this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + return await GetAllChannelMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.channelsFilter, this.sortField, this.queryParam); + } + + internal void Retry() + { + GetAllChannelMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.channelsFilter, this.sortField, this.queryParam, savedCallback); + } + + private void GetAllChannelMetadataList(PNPageObject page, int limit, bool includeCount, bool includeCustom, string filter, List sort, Dictionary externalQueryParam, PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetAllChannelMetadataOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePostMethod = false; + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetAllChannelMetadataOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetAllChannelMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNGetAllChannelMetadataResult), status); + } + }); + } + + private async Task> GetAllChannelMetadataList(PNPageObject page, int limit, bool includeCount, bool includeCustom, string filter, List sort, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetAllChannelMetadataOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePostMethod = false; + Tuple JsonAndStatusTuple; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetAllChannelMetadataOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNGetAllChannelMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetAllChannelMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "channels" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) { + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNGetAllChannelMetadataOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(page.Prev)) { + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNGetAllChannelMetadataOperation, false, false, false)); + } + if (limit >= 0) { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + if (includeCount) { + requestQueryStringParams.Add("count", "true"); + } + if (includeCustom) { + requestQueryStringParams.Add("include", "custom"); + } + if (!string.IsNullOrEmpty(channelsFilter)) { + requestQueryStringParams.Add("filter", UriUtil.EncodeUriComponent(channelsFilter, PNOperationType.PNGetAllChannelMetadataOperation, false, false, false)); + } + if (sortField != null && sortField.Count > 0) { + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",", sortField.ToArray()), PNOperationType.PNGetAllChannelMetadataOperation, false, false, false)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGetAllChannelMetadataOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/GetAllUuidMetadataOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/GetAllUuidMetadataOperation.cs index 9770d9f3c..98afc93a7 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/GetAllUuidMetadataOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/GetAllUuidMetadataOperation.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; -using System.Text; using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 +using System.Globalization; +using System.Text; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { @@ -17,7 +15,6 @@ public class GetAllUuidMetadataOperation : PubnubCoreBase private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; private int limit = -1; private bool includeCount; @@ -29,19 +26,18 @@ public class GetAllUuidMetadataOperation : PubnubCoreBase private PNCallback savedCallback; private Dictionary queryParam; - public GetAllUuidMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public GetAllUuidMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; if (instance != null) { if (!ChannelRequest.ContainsKey(instance.InstanceId)) { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); } if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { @@ -96,42 +92,19 @@ public GetAllUuidMetadataOperation QueryParam(Dictionary customQ public void Execute(PNCallback callback) { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetUuidMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.usersFilter, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetUuidMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.usersFilter, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif + this.savedCallback = callback; + GetUuidMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.usersFilter, this.sortField, this.queryParam, savedCallback); } public async Task> ExecuteAsync() { - return await GetUuidMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.usersFilter, this.sortField, this.queryParam).ConfigureAwait(false); + return await GetUuidMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.usersFilter, this.sortField, this.queryParam); } internal void Retry() { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetUuidMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.usersFilter, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetUuidMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.usersFilter, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif + GetUuidMetadataList(this.page, this.limit, this.includeCount, this.includeCustom, this.usersFilter, this.sortField, this.queryParam, savedCallback); } private void GetUuidMetadataList(PNPageObject page, int limit, bool includeCount, bool includeCustom, string filter, List sort, Dictionary externalQueryParam, PNCallback callback) @@ -143,47 +116,59 @@ private void GetUuidMetadataList(PNPageObject page, int limit, bool includeCount PNPageObject internalPage; if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGetAllUuidMetadataRequest("GET", "", internalPage.Next, internalPage.Prev, limit, includeCount, includeCustom, filter, sort, externalQueryParam); - RequestState requestState = new RequestState(); requestState.ResponseType = PNOperationType.PNGetAllUuidMetadataOperation; requestState.PubnubCallback = callback; requestState.Reconnect = false; requestState.EndPointOperation = this; - requestState.UsePostMethod = false; - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetAllUuidMetadataOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetAllUuidMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNGetAllUuidMetadataResult), status); + } + }); } private async Task> GetUuidMetadataList(PNPageObject page, int limit, bool includeCount, bool includeCustom, string filter, List sort, Dictionary externalQueryParam) { - PNResult ret = new PNResult(); + PNResult returnValue = new PNResult(); PNPageObject internalPage; if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildGetAllUuidMetadataRequest("GET", "", internalPage.Next, internalPage.Prev, limit, includeCount, includeCustom, filter, sort, externalQueryParam); - RequestState requestState = new RequestState(); requestState.ResponseType = PNOperationType.PNGetAllUuidMetadataOperation; requestState.Reconnect = false; - requestState.EndPointOperation = this; - requestState.UsePostMethod = false; - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetAllUuidMetadataOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; string json = JsonAndStatusTuple.Item1; if (!string.IsNullOrEmpty(json)) { @@ -192,11 +177,77 @@ private async Task> GetUuidMetadataList(PNP PNGetAllUuidMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); if (responseResult != null) { - ret.Result = responseResult; + returnValue.Result = responseResult; } } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetAllUuidMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } - return ret; + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "uuids" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) + { + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNGetAllUuidMetadataOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(page.Prev)) + { + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNGetAllUuidMetadataOperation, false, false, false)); + } + if (limit >= 0) + { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + if (includeCount) + { + requestQueryStringParams.Add("count", "true"); + } + if (includeCustom) + { + requestQueryStringParams.Add("include", "custom"); + } + if (!string.IsNullOrEmpty(usersFilter)) + { + requestQueryStringParams.Add("filter", UriUtil.EncodeUriComponent(usersFilter, PNOperationType.PNGetAllUuidMetadataOperation, false, false, false)); + } + if (sortField != null && sortField.Count > 0) + { + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",",sortField.ToArray()), PNOperationType.PNGetAllUuidMetadataOperation, false, false, false)); + } + + if (queryParam != null && queryParam.Count > 0) + { + foreach (KeyValuePair kvp in queryParam) + { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) + { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGetAllUuidMetadataOperation, false, false, false)); + } + } + } + string queryString = UriUtil.BuildQueryString(requestQueryStringParams); + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; } } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/GetChannelMembersOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/GetChannelMembersOperation.cs index c4e52998e..d7f2bae75 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/GetChannelMembersOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/GetChannelMembersOperation.cs @@ -1,242 +1,265 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; using System.Net; using System.Threading.Tasks; -#if !NET35 && !NET40 +using System.Globalization; +using System.Text; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class GetChannelMembersOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string channelMetadataId = ""; - private int limit = -1; - private bool includeCount; - private string commandDelimitedIncludeOptions = ""; - private string membersFilter; - private PNPageObject page; - private List sortField; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public GetChannelMembersOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public GetChannelMembersOperation Channel(string channelName) - { - this.channelMetadataId = channelName; - return this; - } - - public GetChannelMembersOperation Page(PNPageObject pageObject) - { - this.page = pageObject; - return this; - } - - public GetChannelMembersOperation Limit(int numberOfObjects) - { - this.limit = numberOfObjects; - return this; - } - - public GetChannelMembersOperation IncludeCount(bool includeTotalCount) - { - this.includeCount = includeTotalCount; - return this; - } - - public GetChannelMembersOperation Include(PNChannelMemberField[] includeOptions) - { - if (includeOptions != null) - { - string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); - this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); - } - return this; - } - - public GetChannelMembersOperation Filter(string filterExpression) - { - this.membersFilter = filterExpression; - return this; - } - - public GetChannelMembersOperation Sort(List sortByField) - { - this.sortField = sortByField; - return this; - } - - public GetChannelMembersOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetMembersList(this.channelMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membersFilter, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetMembersList(this.channelMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membersFilter, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GetMembersList(this.channelMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membersFilter, this.sortField, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetMembersList(this.channelMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membersFilter, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetMembersList(this.channelMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membersFilter, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void GetMembersList(string spaceId, PNPageObject page, int limit, bool includeCount, string includeOptions, string filter, List sort, Dictionary externalQueryParam, PNCallback callback) - { - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetAllMembersRequest("GET", "", spaceId, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, filter, sort, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetChannelMembersOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> GetMembersList(string spaceId, PNPageObject page, int limit, bool includeCount, string includeOptions, string filter, List sort, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetAllMembersRequest("GET", "", spaceId, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, filter, sort, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetChannelMembersOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNChannelMembersResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private static string MapEnumValueToEndpoint(string enumValue) - { - string ret = ""; - if (enumValue.ToLowerInvariant() == "custom") - { - ret = "custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid") - { - ret = "uuid"; - } - else if (enumValue.ToLowerInvariant() == "uuid_custom") - { - ret = "uuid.custom"; - } - return ret; - } - } + public class GetChannelMembersOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelId = ""; + private int limit = -1; + private bool includeCount; + private string commandDelimitedIncludeOptions = ""; + private string membersFilter; + private PNPageObject page; + private List sortField; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public GetChannelMembersOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public GetChannelMembersOperation Channel(string channelName) + { + this.channelId = channelName; + return this; + } + + public GetChannelMembersOperation Page(PNPageObject pageObject) + { + this.page = pageObject; + return this; + } + + public GetChannelMembersOperation Limit(int numberOfObjects) + { + this.limit = numberOfObjects; + return this; + } + + public GetChannelMembersOperation IncludeCount(bool includeTotalCount) + { + this.includeCount = includeTotalCount; + return this; + } + + public GetChannelMembersOperation Include(PNChannelMemberField[] includeOptions) + { + if (includeOptions != null) { + string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); + this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); + } + return this; + } + + public GetChannelMembersOperation Filter(string filterExpression) + { + this.membersFilter = filterExpression; + return this; + } + + public GetChannelMembersOperation Sort(List sortByField) + { + this.sortField = sortByField; + return this; + } + + public GetChannelMembersOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + + this.savedCallback = callback; + GetMembersList(this.channelId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membersFilter, this.sortField, this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + return await GetMembersList(this.channelId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membersFilter, this.sortField, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + GetMembersList(this.channelId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membersFilter, this.sortField, this.queryParam, savedCallback); + } + + private void GetMembersList(string spaceId, PNPageObject page, int limit, bool includeCount, string includeOptions, string filter, List sort, Dictionary externalQueryParam, PNCallback callback) + { + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetChannelMembersOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.UsePostMethod = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetChannelMembersOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(null, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetChannelMembersOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNChannelMembersResult), status); + } + }); + } + + private async Task> GetMembersList(string spaceId, PNPageObject page, int limit, bool includeCount, string includeOptions, string filter, List sort, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetChannelMembersOperation; + requestState.Reconnect = false; + requestState.UsePostMethod = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetChannelMembersOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNChannelMembersResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetChannelMembersOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private static string MapEnumValueToEndpoint(string enumValue) + { + string ret = ""; + if (enumValue.ToLowerInvariant() == "custom") { + ret = "custom"; + } else if (enumValue.ToLowerInvariant() == "uuid") { + ret = "uuid"; + } else if (enumValue.ToLowerInvariant() == "uuid_custom") { + ret = "uuid.custom"; + } + return ret; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegment = new List + { + "v2", + "objects", + config.SubscribeKey, + "channels", + string.IsNullOrEmpty(channelId) ? string.Empty : channelId, + "uuids" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) { + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNGetChannelMembersOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(page.Prev)) { + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNGetChannelMembersOperation, false, false, false)); + } + if (limit >= 0) { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + if (includeCount) { + requestQueryStringParams.Add("count", "true"); + } + if (!string.IsNullOrEmpty(commandDelimitedIncludeOptions)) { + requestQueryStringParams.Add("include", UriUtil.EncodeUriComponent(commandDelimitedIncludeOptions, PNOperationType.PNGetChannelMembersOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(membersFilter)) { + requestQueryStringParams.Add("filter", UriUtil.EncodeUriComponent(membersFilter, PNOperationType.PNGetChannelMembersOperation, false, false, false)); + } + if (sortField != null && sortField.Count > 0) { + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",", sortField.ToArray()), PNOperationType.PNGetChannelMembersOperation, false, false, false)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGetChannelMembersOperation, false, false, false)); + } + } + } + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegment, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/GetChannelMetadataOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/GetChannelMetadataOperation.cs index 0abc78dfd..49a89b4b3 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/GetChannelMetadataOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/GetChannelMetadataOperation.cs @@ -1,188 +1,196 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Text; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class GetChannelMetadataOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string chMetadataId = ""; - private bool includeCustom; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public GetChannelMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public GetChannelMetadataOperation Channel(string channelName) - { - this.chMetadataId = channelName; - return this; - } - - public GetChannelMetadataOperation IncludeCustom(bool includeCustomData) - { - this.includeCustom = includeCustomData; - return this; - } - - public GetChannelMetadataOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - if (string.IsNullOrEmpty(this.chMetadataId)) - { - throw new ArgumentException("Missing Channel"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetSingleChannelMetadata(this.chMetadataId, this.includeCustom, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetSingleChannelMetadata(this.chMetadataId, this.includeCustom, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GetSingleChannelMetadata(this.chMetadataId, this.includeCustom, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetSingleChannelMetadata(this.chMetadataId, this.includeCustom, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetSingleChannelMetadata(this.chMetadataId, this.includeCustom, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void GetSingleChannelMetadata(string spaceId, bool includeCustom, Dictionary externalQueryParam, PNCallback callback) - { - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetSingleChannelMetadataRequest("GET", "", spaceId, includeCustom, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetChannelMetadataOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> GetSingleChannelMetadata(string spaceId, bool includeCustom, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(this.chMetadataId)) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; - ret.Status = errStatus; - return ret; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetSingleChannelMetadataRequest("GET", "", spaceId, includeCustom, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetChannelMetadataOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNGetChannelMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - } + public class GetChannelMetadataOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelId = ""; + private bool includeCustom; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public GetChannelMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public GetChannelMetadataOperation Channel(string channelName) + { + this.channelId = channelName; + return this; + } + + public GetChannelMetadataOperation IncludeCustom(bool includeCustomData) + { + this.includeCustom = includeCustomData; + return this; + } + + public GetChannelMetadataOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + if (string.IsNullOrEmpty(this.channelId)) { + throw new ArgumentException("Missing Channel"); + } + + this.savedCallback = callback; + GetSingleChannelMetadata(this.channelId, this.includeCustom, this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + return await GetSingleChannelMetadata(this.channelId, this.includeCustom, this.queryParam); + } + + internal void Retry() + { + GetSingleChannelMetadata(this.channelId, this.includeCustom, this.queryParam, savedCallback); + } + + private void GetSingleChannelMetadata(string spaceId, bool includeCustom, Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetChannelMetadataOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.UsePostMethod = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetChannelMetadataOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(null, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetChannelMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNGetChannelMetadataResult), status); + } + }); + } + + private async Task> GetSingleChannelMetadata(string spaceId, bool includeCustom, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(this.channelId)) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; + returnValue.Status = errStatus; + return returnValue; + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetChannelMetadataOperation; + requestState.Reconnect = false; + requestState.UsePostMethod = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetChannelMetadataOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNGetChannelMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetChannelMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "channels", + string.IsNullOrEmpty(channelId) ? string.Empty : channelId + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (includeCustom) { + requestQueryStringParams.Add("include", "custom"); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGetChannelMetadataOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } + diff --git a/src/Api/PubnubApi/EndPoint/Objects/GetMembershipsOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/GetMembershipsOperation.cs index 6ffd8db66..bf14aaccb 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/GetMembershipsOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/GetMembershipsOperation.cs @@ -1,253 +1,260 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; using System.Net; using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Globalization; +using System.Text; namespace PubnubApi.EndPoint { - public class GetMembershipsOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string uuidMetadataId = ""; - private int limit = -1; - private bool includeCount; - private string commandDelimitedIncludeOptions = ""; - private string membershipsFilter; - private PNPageObject page; - private List sortField; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public GetMembershipsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public GetMembershipsOperation Uuid(string id) - { - this.uuidMetadataId = id; - return this; - } - - public GetMembershipsOperation Page(PNPageObject pageObject) - { - this.page = pageObject; - return this; - } - - public GetMembershipsOperation Limit(int numberOfObjects) - { - this.limit = numberOfObjects; - return this; - } - - public GetMembershipsOperation IncludeCount(bool includeTotalCount) - { - this.includeCount = includeTotalCount; - return this; - } - - public GetMembershipsOperation Include(PNMembershipField[] includeOptions) - { - if (includeOptions != null) - { - string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); - this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); - } - return this; - } - - public GetMembershipsOperation Filter(string filterExpression) - { - this.membershipsFilter = filterExpression; - return this; - } - - public GetMembershipsOperation Sort(List sortByField) - { - this.sortField = sortByField; - return this; - } - - public GetMembershipsOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetMembershipsList(this.uuidMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membershipsFilter, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetMembershipsList(this.uuidMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membershipsFilter, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GetMembershipsList(this.uuidMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membershipsFilter, this.sortField, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetMembershipsList(this.uuidMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membershipsFilter, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetMembershipsList(this.uuidMetadataId, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membershipsFilter, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void GetMembershipsList(string uuid, PNPageObject page, int limit, bool includeCount, string includeOptions, string filter, List sort, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetAllMembershipsRequest("GET", "", uuid, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, filter, sort, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetMembershipsOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - - } - - private async Task> GetMembershipsList(string uuid, PNPageObject page, int limit, bool includeCount, string includeOptions, string filter, List sort, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetAllMembershipsRequest("GET", "", uuid, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, filter, sort, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetMembershipsOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNMembershipsResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private static string MapEnumValueToEndpoint(string enumValue) - { - string ret = ""; - if (enumValue.ToLowerInvariant() == "custom") - { - ret = "custom"; - } - else if (enumValue.ToLowerInvariant() == "channel") - { - ret = "channel"; - } - else if (enumValue.ToLowerInvariant() == "channel_custom") - { - ret = "channel.custom"; - } - return ret; - } - } + public class GetMembershipsOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string uuid = string.Empty; + private int limit = -1; + private bool includeCount; + private string commandDelimitedIncludeOptions = ""; + private string membershipsFilter; + private PNPageObject page; + private List sortField; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public GetMembershipsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public GetMembershipsOperation Uuid(string id) + { + this.uuid = id; + return this; + } + + public GetMembershipsOperation Page(PNPageObject pageObject) + { + this.page = pageObject; + return this; + } + + public GetMembershipsOperation Limit(int numberOfObjects) + { + this.limit = numberOfObjects; + return this; + } + + public GetMembershipsOperation IncludeCount(bool includeTotalCount) + { + this.includeCount = includeTotalCount; + return this; + } + + public GetMembershipsOperation Include(PNMembershipField[] includeOptions) + { + if (includeOptions != null) { + string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); + this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); + } + return this; + } + + public GetMembershipsOperation Filter(string filterExpression) + { + this.membershipsFilter = filterExpression; + return this; + } + + public GetMembershipsOperation Sort(List sortByField) + { + this.sortField = sortByField; + return this; + } + + public GetMembershipsOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + this.savedCallback = callback; + GetMembershipsList(this.uuid, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membershipsFilter, this.sortField, this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + return await GetMembershipsList(this.uuid, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membershipsFilter, this.sortField, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + GetMembershipsList(this.uuid, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.membershipsFilter, this.sortField, this.queryParam, savedCallback); + } + + private void GetMembershipsList(string uuid, PNPageObject page, int limit, bool includeCount, string includeOptions, string filter, List sort, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetMembershipsOperation; + requestState.PubnubCallback = callback; + requestState.UsePostMethod = false; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetMembershipsOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(null, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetMembershipsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNMembershipsResult), status); + } + }); + } + + private async Task> GetMembershipsList(string uuid, PNPageObject page, int limit, bool includeCount, string includeOptions, string filter, List sort, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetMembershipsOperation; + requestState.UsePostMethod = false; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetMembershipsOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNMembershipsResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetMembershipsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private static string MapEnumValueToEndpoint(string enumValue) + { + string ret = ""; + if (enumValue.ToLowerInvariant() == "custom") { + ret = "custom"; + } else if (enumValue.ToLowerInvariant() == "channel") { + ret = "channel"; + } else if (enumValue.ToLowerInvariant() == "channel_custom") { + ret = "channel.custom"; + } + return ret; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "uuids", + string.IsNullOrEmpty(uuid) ? string.Empty : uuid, + "channels" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) { + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNGetMembershipsOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(page.Prev)) { + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNGetMembershipsOperation, false, false, false)); + } + if (limit >= 0) { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + if (includeCount) { + requestQueryStringParams.Add("count", "true"); + } + if (!string.IsNullOrEmpty(commandDelimitedIncludeOptions)) { + requestQueryStringParams.Add("include", UriUtil.EncodeUriComponent(commandDelimitedIncludeOptions, PNOperationType.PNGetMembershipsOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(membershipsFilter)) { + requestQueryStringParams.Add("filter", UriUtil.EncodeUriComponent(membershipsFilter, PNOperationType.PNGetMembershipsOperation, false, false, false)); + } + if (sortField != null && sortField.Count > 0) { + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",", sortField.ToArray()), PNOperationType.PNGetMembershipsOperation, false, false, false)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGetMembershipsOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/GetUuidMetadataOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/GetUuidMetadataOperation.cs index ebb029bab..5f14ce6f7 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/GetUuidMetadataOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/GetUuidMetadataOperation.cs @@ -1,185 +1,193 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; +using System.Threading.Tasks; using System.Text; using System.Threading; -using System.Threading.Tasks; -#if !NET35 && !NET40 using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class GetUuidMetadataOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private bool includeCustom; - private string usrUuid = ""; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public GetUuidMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public GetUuidMetadataOperation Uuid(string uuid) - { - this.usrUuid = uuid; - return this; - } - - public GetUuidMetadataOperation IncludeCustom(bool includeCustomData) - { - this.includeCustom = includeCustomData; - return this; - } - - public GetUuidMetadataOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetSingleUuidMetadata(this.usrUuid, this.includeCustom, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetSingleUuidMetadata(this.usrUuid, this.includeCustom, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GetSingleUuidMetadata(this.usrUuid, this.includeCustom, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetSingleUuidMetadata(this.usrUuid, this.includeCustom, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetSingleUuidMetadata(this.usrUuid, this.includeCustom, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void GetSingleUuidMetadata(string uuid, bool includeCustom, Dictionary externalQueryParam, PNCallback callback) - { - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetSingleUuidMetadataRequest("GET", "", uuid, includeCustom, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetUuidMetadataOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> GetSingleUuidMetadata(string uuid, bool includeCustom, Dictionary externalQueryParam) - { - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetSingleUuidMetadataRequest("GET", "", uuid, includeCustom, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNGetUuidMetadataOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePostMethod = false; - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNGetUuidMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - } + public class GetUuidMetadataOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private bool includeCustom; + private string uuid = string.Empty; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public GetUuidMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public GetUuidMetadataOperation Uuid(string uuid) + { + this.uuid = uuid; + return this; + } + + public GetUuidMetadataOperation IncludeCustom(bool includeCustomData) + { + this.includeCustom = includeCustomData; + return this; + } + + public GetUuidMetadataOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + GetSingleUuidMetadata(this.uuid, this.includeCustom, this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + return await GetSingleUuidMetadata(this.uuid, this.includeCustom, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + GetSingleUuidMetadata(this.uuid, this.includeCustom, this.queryParam, savedCallback); + } + + private void GetSingleUuidMetadata(string uuid, bool includeCustom, Dictionary externalQueryParam, PNCallback callback) + { + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetUuidMetadataOperation; + requestState.PubnubCallback = callback; + requestState.UsePostMethod = false; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetUuidMetadataOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(null, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetUuidMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNGetUuidMetadataResult), status); + } + }); + } + + private async Task> GetSingleUuidMetadata(string uuid, bool includeCustom, Dictionary externalQueryParam) + { + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNGetUuidMetadataOperation; + requestState.Reconnect = false; + requestState.UsePostMethod = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetUuidMetadataOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNGetUuidMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetUuidMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "uuids", + string.IsNullOrEmpty(uuid) ? string.Empty : uuid + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (includeCustom) { + requestQueryStringParams.Add("include", "custom"); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGetUuidMetadataOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/ManageChannelMembersOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/ManageChannelMembersOperation.cs index 82002c736..460783b3a 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/ManageChannelMembersOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/ManageChannelMembersOperation.cs @@ -3,27 +3,24 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -using Newtonsoft.Json; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class ManageChannelMembersOperation : PubnubCoreBase + public class ManageChannelMembersOperation : PubnubCoreBase { private readonly PNConfiguration config; private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - private string chMetadataId = ""; + private string channelId = string.Empty; private List setMember; private List delMember; - private string commandDelimitedIncludeOptions = ""; + private string commandDelimitedIncludeOptions = string.Empty; private PNPageObject page; private int limit = -1; private bool includeCount; @@ -32,19 +29,18 @@ public class ManageChannelMembersOperation : PubnubCoreBase private PNCallback savedCallback; private Dictionary queryParam; - public ManageChannelMembersOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public ManageChannelMembersOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; if (instance != null) { if (!ChannelRequest.ContainsKey(instance.InstanceId)) { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); } if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { @@ -59,7 +55,7 @@ public ManageChannelMembersOperation(PNConfiguration pubnubConfig, IJsonPluggabl public ManageChannelMembersOperation Channel(string channelName) { - this.chMetadataId = channelName; + this.channelId = channelName; return this; } @@ -117,7 +113,7 @@ public ManageChannelMembersOperation QueryParam(Dictionary custo public void Execute(PNCallback callback) { - if (string.IsNullOrEmpty(this.chMetadataId) || string.IsNullOrEmpty(chMetadataId.Trim())) + if (string.IsNullOrEmpty(this.channelId) || string.IsNullOrEmpty(channelId.Trim())) { throw new ArgumentException("Missing Channel"); } @@ -132,41 +128,18 @@ public void Execute(PNCallback callback) throw new ArgumentException("Missing callback"); } -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif + this.savedCallback = callback; + ProcessMembersOperationRequest(this.channelId, this.setMember, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); } public async Task> ExecuteAsync() { - return await ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); + return await ProcessMembersOperationRequest(this.channelId, this.setMember, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); } internal void Retry() { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif + ProcessMembersOperationRequest(this.channelId, this.setMember, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); } private void ProcessMembersOperationRequest(string spaceId, List setMemberList, List removeMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) @@ -179,85 +152,48 @@ private void ProcessMembersOperationRequest(string spaceId, List messageEnvelope = new Dictionary(); - if (setMemberList != null) - { - List> setMemberFormatList = new List>(); - for (int index = 0; index < setMemberList.Count; index++) - { - Dictionary currentMemberFormat = new Dictionary(); - currentMemberFormat.Add("uuid", new Dictionary { { "id", setMemberList[index].Uuid } }); - if (setMemberList[index].Custom != null) - { - currentMemberFormat.Add("custom", setMemberList[index].Custom); - } - setMemberFormatList.Add(currentMemberFormat); - } - if (setMemberFormatList.Count > 0) - { - messageEnvelope.Add("set", setMemberFormatList); - } - } - if (removeMemberList != null) - { - List>> removeMemberFormatList = new List>>(); - for (int index = 0; index < removeMemberList.Count; index++) - { - Dictionary> currentMemberFormat = new Dictionary>(); - if (!string.IsNullOrEmpty(removeMemberList[index])) - { - currentMemberFormat.Add("uuid", new Dictionary { { "id", removeMemberList[index] } }); - removeMemberFormatList.Add(currentMemberFormat); - } - } - if (removeMemberFormatList.Count > 0) - { - messageEnvelope.Add("delete", removeMemberFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMemberAddUpdateRemoveChannelRequest("PATCH", patchMessage, spaceId, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); + requestState.EndPointOperation = this; - UrlProcessRequest(request, requestState, false, patchData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNManageChannelMembersOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNManageChannelMembersOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); } private async Task> ProcessMembersOperationRequest(string channel, List setMemberList, List removeMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) { - PNResult ret = new PNResult(); + PNResult returnValue = new PNResult(); if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) { PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; - ret.Status = errStatus; - return ret; + returnValue.Status = errStatus; + return returnValue; } if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; - ret.Status = errStatus; - return ret; + returnValue.Status = errStatus; + return returnValue; } PNPageObject internalPage; @@ -268,20 +204,82 @@ private async Task> ProcessMembersOperationRequ requestState.ResponseType = PNOperationType.PNManageChannelMembersOperation; requestState.Reconnect = false; requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; requestState.UsePatchMethod = true; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNManageChannelMembersOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) + { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNChannelMembersResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) + { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNManageChannelMembersOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private static string MapEnumValueToEndpoint(string enumValue) + { + string ret = ""; + if (enumValue.ToLowerInvariant() == "custom") + { + ret = "custom"; + } + else if (enumValue.ToLowerInvariant() == "uuid") + { + ret = "uuid"; + } + else if (enumValue.ToLowerInvariant() == "channel") + { + ret = "channel"; + } + else if (enumValue.ToLowerInvariant() == "channel_custom") + { + ret = "channel.custom"; + } + else if (enumValue.ToLowerInvariant() == "uuid_custom") + { + ret = "uuid.custom"; + } + return ret; + } + + private RequestParameter CreateRequestParameter() + { Dictionary messageEnvelope = new Dictionary(); - if (setMemberList != null) + if (setMember != null) { List> setMemberFormatList = new List>(); - for (int index = 0; index < setMemberList.Count; index++) + for (int index = 0; index < setMember.Count; index++) { - Dictionary currentMemberFormat = new Dictionary(); - currentMemberFormat.Add("uuid", new Dictionary { { "id", setMemberList[index].Uuid } }); - if (setMemberList[index].Custom != null) + Dictionary currentMemberFormat = new Dictionary + { + { "uuid", new Dictionary { { "id", setMember[index].Uuid } } } + }; + if (setMember[index].Custom != null) { - currentMemberFormat.Add("custom", setMemberList[index].Custom); + currentMemberFormat.Add("custom", setMember[index].Custom); } setMemberFormatList.Add(currentMemberFormat); } @@ -290,15 +288,15 @@ private async Task> ProcessMembersOperationRequ messageEnvelope.Add("set", setMemberFormatList); } } - if (removeMemberList != null) + if (delMember != null) { List>> removeMemberFormatList = new List>>(); - for (int index = 0; index < removeMemberList.Count; index++) + for (int index = 0; index < delMember.Count; index++) { Dictionary> currentMemberFormat = new Dictionary>(); - if (!string.IsNullOrEmpty(removeMemberList[index])) + if (!string.IsNullOrEmpty(delMember[index])) { - currentMemberFormat.Add("uuid", new Dictionary { { "id", removeMemberList[index] } }); + currentMemberFormat.Add("uuid", new Dictionary { { "id", delMember[index] } }); removeMemberFormatList.Add(currentMemberFormat); } } @@ -308,53 +306,60 @@ private async Task> ProcessMembersOperationRequ } } string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMemberAddUpdateRemoveChannelRequest("PATCH", patchMessage, channel, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, patchData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "channels", + string.IsNullOrEmpty(channelId) ? "" : channelId, + "uuids" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNChannelMembersResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNManageChannelMembersOperation, false, false, false)); } - - return ret; - } - - private static string MapEnumValueToEndpoint(string enumValue) - { - string ret = ""; - if (enumValue.ToLowerInvariant() == "custom") + if (!string.IsNullOrEmpty(page.Prev)) { - ret = "custom"; + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNManageChannelMembersOperation, false, false, false)); } - else if (enumValue.ToLowerInvariant() == "uuid") + if (limit >= 0) { - ret = "uuid"; + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); } - else if (enumValue.ToLowerInvariant() == "channel") + if (includeCount) { - ret = "channel"; + requestQueryStringParams.Add("count", "true"); } - else if (enumValue.ToLowerInvariant() == "channel_custom") + if (!string.IsNullOrEmpty(commandDelimitedIncludeOptions)) { - ret = "channel.custom"; + requestQueryStringParams.Add("include", UriUtil.EncodeUriComponent(commandDelimitedIncludeOptions, PNOperationType.PNManageChannelMembersOperation, false, false, false)); } - else if (enumValue.ToLowerInvariant() == "uuid_custom") + if (sortField != null && sortField.Count > 0) { - ret = "uuid.custom"; + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",", sortField.ToArray()), PNOperationType.PNManageChannelMembersOperation, false, false, false)); + } + if (queryParam != null && queryParam.Count > 0) + { + foreach (KeyValuePair kvp in queryParam) + { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) + { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNManageChannelMembersOperation, false, false, false)); + } + } } - return ret; - } + var requestParameter = new RequestParameter() { + RequestType = Constants.PATCH, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = patchMessage + }; + return requestParameter; + } } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/ManageMembershipsOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/ManageMembershipsOperation.cs index 134f81e59..07808fbce 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/ManageMembershipsOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/ManageMembershipsOperation.cs @@ -3,355 +3,323 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -using Newtonsoft.Json; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class ManageMembershipsOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string uuidMetadataId = ""; - private List addMembership; - private List delMembership; - private string commandDelimitedIncludeOptions = ""; - private PNPageObject page; - private int limit = -1; - private bool includeCount; - private List sortField; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public ManageMembershipsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public ManageMembershipsOperation Uuid(string id) - { - this.uuidMetadataId = id; - return this; - } - - public ManageMembershipsOperation Set(List membership) - { - this.addMembership = membership; - return this; - } - - public ManageMembershipsOperation Remove(List channelIdList) - { - this.delMembership = channelIdList; - return this; - } - - public ManageMembershipsOperation Include(PNMembershipField[] includeOptions) - { - if (includeOptions != null) - { - string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); - this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); - } - return this; - } - - public ManageMembershipsOperation Page(PNPageObject pageObject) - { - this.page = pageObject; - return this; - } - - public ManageMembershipsOperation Limit(int numberOfObjects) - { - this.limit = numberOfObjects; - return this; - } - - public ManageMembershipsOperation IncludeCount(bool includeTotalCount) - { - this.includeCount = includeTotalCount; - return this; - } - - public ManageMembershipsOperation Sort(List sortByField) - { - this.sortField = sortByField; - return this; - } - - public ManageMembershipsOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - throw new MissingMemberException("Invalid subscribe key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - ManageChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - ManageChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await ManageChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ManageChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ManageChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void ManageChannelMembershipWithUuid(string uuid, List setMembership, List removeMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNManageMembershipsOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (setMembership != null) - { - List> setMembershipFormatList = new List>(); - for (int index=0; index < setMembership.Count; index++) - { - Dictionary currentMembershipFormat = new Dictionary(); - currentMembershipFormat.Add("channel", new Dictionary { { "id", setMembership[index].Channel } }); - if (setMembership[index].Custom != null) - { - currentMembershipFormat.Add("custom", setMembership[index].Custom); - } - setMembershipFormatList.Add(currentMembershipFormat); - } - if (setMembershipFormatList.Count > 0) - { - messageEnvelope.Add("set", setMembershipFormatList); - } - } - if (removeMembership != null) - { - List>> removeMembershipFormatList = new List>>(); - for (int index=0; index < removeMembership.Count; index++) - { - Dictionary> currentMembershipFormat = new Dictionary>(); - if (!string.IsNullOrEmpty(removeMembership[index])) - { - currentMembershipFormat.Add("channel", new Dictionary { { "id", removeMembership[index] } }); - removeMembershipFormatList.Add(currentMembershipFormat); - } - } - if (removeMembershipFormatList.Count > 0) - { - messageEnvelope.Add("delete", removeMembershipFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMembershipSetRemoveManageUserRequest(requestState.ResponseType, "PATCH", patchMessage, uuid, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - UrlProcessRequest(request, requestState, false, patchData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> ManageChannelMembershipWithUuid(string uuid, List setMembership, List removeMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; - ret.Status = errStatus; - return ret; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNManageMembershipsOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (setMembership != null) - { - List> setMembershipFormatList = new List>(); - for (int index = 0; index < setMembership.Count; index++) - { - Dictionary currentMembershipFormat = new Dictionary(); - currentMembershipFormat.Add("channel", new Dictionary { { "id", setMembership[index].Channel } }); - if (setMembership[index].Custom != null) - { - currentMembershipFormat.Add("custom", setMembership[index].Custom); - } - setMembershipFormatList.Add(currentMembershipFormat); - } - if (setMembershipFormatList.Count > 0) - { - messageEnvelope.Add("set", setMembershipFormatList); - } - } - if (removeMembership != null) - { - List>> removeMembershipFormatList = new List>>(); - for (int index = 0; index < removeMembership.Count; index++) - { - Dictionary> currentMembershipFormat = new Dictionary>(); - if (!string.IsNullOrEmpty(removeMembership[index])) - { - currentMembershipFormat.Add("channel", new Dictionary { { "id", removeMembership[index] } }); - removeMembershipFormatList.Add(currentMembershipFormat); - } - } - if (removeMembershipFormatList.Count > 0) - { - messageEnvelope.Add("delete", removeMembershipFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMembershipSetRemoveManageUserRequest(requestState.ResponseType, "PATCH", patchMessage, uuid, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, patchData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNMembershipsResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private static string MapEnumValueToEndpoint(string enumValue) - { - string ret = ""; - if (enumValue.ToLowerInvariant() == "custom") - { - ret = "custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid") - { - ret = "uuid"; - } - else if (enumValue.ToLowerInvariant() == "channel") - { - ret = "channel"; - } - else if (enumValue.ToLowerInvariant() == "channel_custom") - { - ret = "channel.custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid_custom") - { - ret = "uuid.custom"; - } - return ret; - } - - } + public class ManageMembershipsOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string uuid = string.Empty; + private List addMembership; + private List delMembership; + private string commandDelimitedIncludeOptions = string.Empty; + private PNPageObject page; + private int limit = -1; + private bool includeCount; + private List sortField; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public ManageMembershipsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public ManageMembershipsOperation Uuid(string id) + { + this.uuid = id; + return this; + } + + public ManageMembershipsOperation Set(List membership) + { + this.addMembership = membership; + return this; + } + + public ManageMembershipsOperation Remove(List channelIdList) + { + this.delMembership = channelIdList; + return this; + } + + public ManageMembershipsOperation Include(PNMembershipField[] includeOptions) + { + if (includeOptions != null) { + string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); + this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); + } + return this; + } + + public ManageMembershipsOperation Page(PNPageObject pageObject) + { + this.page = pageObject; + return this; + } + + public ManageMembershipsOperation Limit(int numberOfObjects) + { + this.limit = numberOfObjects; + return this; + } + + public ManageMembershipsOperation IncludeCount(bool includeTotalCount) + { + this.includeCount = includeTotalCount; + return this; + } + + public ManageMembershipsOperation Sort(List sortByField) + { + this.sortField = sortByField; + return this; + } + + public ManageMembershipsOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + throw new MissingMemberException("Invalid subscribe key"); + } + + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + + this.savedCallback = callback; + ManageChannelMembershipWithUuid(this.uuid, this.addMembership, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await ManageChannelMembershipWithUuid(this.uuid, this.addMembership, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + ManageChannelMembershipWithUuid(this.uuid, this.addMembership, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); + } + + private void ManageChannelMembershipWithUuid(string uuid, List setMembership, List removeMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNManageMembershipsOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePatchMethod = true; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNManageMembershipsOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(null, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNManageMembershipsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNMembershipsResult), status); + } + }); + } + + private async Task> ManageChannelMembershipWithUuid(string uuid, List setMembership, List removeMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNManageMembershipsOperation; + requestState.Reconnect = false; + requestState.UsePatchMethod = true; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNManageMembershipsOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNMembershipsResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNManageMembershipsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private static string MapEnumValueToEndpoint(string enumValue) + { + string ret = ""; + if (enumValue.ToLowerInvariant() == "custom") { + ret = "custom"; + } else if (enumValue.ToLowerInvariant() == "uuid") { + ret = "uuid"; + } else if (enumValue.ToLowerInvariant() == "channel") { + ret = "channel"; + } else if (enumValue.ToLowerInvariant() == "channel_custom") { + ret = "channel.custom"; + } else if (enumValue.ToLowerInvariant() == "uuid_custom") { + ret = "uuid.custom"; + } + return ret; + } + + private RequestParameter CreateRequestParameter() + { + Dictionary messageEnvelope = new Dictionary(); + if (addMembership != null) { + List> setMembershipFormatList = new List>(); + for (int index = 0; index < addMembership.Count; index++) { + Dictionary currentMembershipFormat = new Dictionary(); + currentMembershipFormat.Add("channel", new Dictionary { { "id", addMembership[index].Channel } }); + if (addMembership[index].Custom != null) { + currentMembershipFormat.Add("custom", addMembership[index].Custom); + } + setMembershipFormatList.Add(currentMembershipFormat); + } + if (setMembershipFormatList.Count > 0) { + messageEnvelope.Add("set", setMembershipFormatList); + } + } + if (delMembership != null) { + List>> removeMembershipFormatList = new List>>(); + for (int index = 0; index < delMembership.Count; index++) { + Dictionary> currentMembershipFormat = new Dictionary>(); + if (!string.IsNullOrEmpty(delMembership[index])) { + currentMembershipFormat.Add("channel", new Dictionary { { "id", delMembership[index] } }); + removeMembershipFormatList.Add(currentMembershipFormat); + } + } + if (removeMembershipFormatList.Count > 0) { + messageEnvelope.Add("delete", removeMembershipFormatList); + } + } + string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); + + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "uuids", + string.IsNullOrEmpty(uuid) ? string.Empty : uuid, + "channels" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) { + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNManageMembershipsOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(page.Prev)) { + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNManageMembershipsOperation, false, false, false)); + } + if (limit >= 0) { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + if (includeCount) { + requestQueryStringParams.Add("count", "true"); + } + if (!string.IsNullOrEmpty(commandDelimitedIncludeOptions)) { + requestQueryStringParams.Add("include", UriUtil.EncodeUriComponent(commandDelimitedIncludeOptions, PNOperationType.PNManageMembershipsOperation, false, false, false)); + } + if (sortField != null && sortField.Count > 0) { + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",", sortField.ToArray()), PNOperationType.PNManageMembershipsOperation, false, false, false)); + } + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNManageMembershipsOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.PATCH, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = patchMessage + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/RemoveChannelMembersOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/RemoveChannelMembersOperation.cs index 3cfa60ced..f9037c3b3 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/RemoveChannelMembersOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/RemoveChannelMembersOperation.cs @@ -3,315 +3,301 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -using Newtonsoft.Json; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class RemoveChannelMembersOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string chMetadataId = ""; - private List delMember; - private string commandDelimitedIncludeOptions = ""; - private PNPageObject page; - private int limit = -1; - private bool includeCount; - private List sortField; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public RemoveChannelMembersOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public RemoveChannelMembersOperation Channel(string channelName) - { - this.chMetadataId = channelName; - return this; - } - - public RemoveChannelMembersOperation Uuids(List uuidList) - { - this.delMember = uuidList; - return this; - } - - public RemoveChannelMembersOperation Include(PNChannelMemberField[] includeOptions) - { - if (includeOptions != null) - { - string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); - this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); - } - return this; - } - - public RemoveChannelMembersOperation Page(PNPageObject pageObject) - { - this.page = pageObject; - return this; - } - - public RemoveChannelMembersOperation Limit(int numberOfObjects) - { - this.limit = numberOfObjects; - return this; - } - - public RemoveChannelMembersOperation IncludeCount(bool includeTotalCount) - { - this.includeCount = includeTotalCount; - return this; - } - - public RemoveChannelMembersOperation Sort(List sortByField) - { - this.sortField = sortByField; - return this; - } - - public RemoveChannelMembersOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(this.chMetadataId) || string.IsNullOrEmpty(chMetadataId.Trim())) - { - throw new ArgumentException("Missing Channel"); - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - throw new MissingMemberException("Invalid subscribe key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - ProcessRemoveChannelMembersOperationRequest(this.chMetadataId, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - ProcessRemoveChannelMembersOperationRequest(this.chMetadataId, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await ProcessRemoveChannelMembersOperationRequest(this.chMetadataId, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ProcessRemoveChannelMembersOperationRequest(this.chMetadataId, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ProcessRemoveChannelMembersOperationRequest(this.chMetadataId, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void ProcessRemoveChannelMembersOperationRequest(string spaceId, List removeMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) - { - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNRemoveChannelMembersOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (removeMemberList != null) - { - List>> removeMemberFormatList = new List>>(); - for (int index = 0; index < removeMemberList.Count; index++) - { - Dictionary> currentMemberFormat = new Dictionary>(); - if (!string.IsNullOrEmpty(removeMemberList[index])) - { - currentMemberFormat.Add("uuid", new Dictionary { { "id", removeMemberList[index] } }); - removeMemberFormatList.Add(currentMemberFormat); - } - } - if (removeMemberFormatList.Count > 0) - { - messageEnvelope.Add("delete", removeMemberFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMemberAddUpdateRemoveChannelRequest("PATCH", patchMessage, spaceId, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - UrlProcessRequest(request, requestState, false, patchData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> ProcessRemoveChannelMembersOperationRequest(string channel, List removeMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; - ret.Status = errStatus; - return ret; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNRemoveChannelMembersOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (removeMemberList != null) - { - List>> removeMemberFormatList = new List>>(); - for (int index = 0; index < removeMemberList.Count; index++) - { - Dictionary> currentMemberFormat = new Dictionary>(); - if (!string.IsNullOrEmpty(removeMemberList[index])) - { - currentMemberFormat.Add("uuid", new Dictionary { { "id", removeMemberList[index] } }); - removeMemberFormatList.Add(currentMemberFormat); - } - } - if (removeMemberFormatList.Count > 0) - { - messageEnvelope.Add("delete", removeMemberFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMemberAddUpdateRemoveChannelRequest("PATCH", patchMessage, channel, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, patchData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNChannelMembersResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private static string MapEnumValueToEndpoint(string enumValue) - { - string ret = ""; - if (enumValue.ToLowerInvariant() == "custom") - { - ret = "custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid") - { - ret = "uuid"; - } - else if (enumValue.ToLowerInvariant() == "channel") - { - ret = "channel"; - } - else if (enumValue.ToLowerInvariant() == "channel_custom") - { - ret = "channel.custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid_custom") - { - ret = "uuid.custom"; - } - return ret; - } - - } + public class RemoveChannelMembersOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelId = string.Empty; + private List delMember; + private string commandDelimitedIncludeOptions = string.Empty; + private PNPageObject page; + private int limit = -1; + private bool includeCount; + private List sortField; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public RemoveChannelMembersOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public RemoveChannelMembersOperation Channel(string channelName) + { + this.channelId = channelName; + return this; + } + + public RemoveChannelMembersOperation Uuids(List uuidList) + { + this.delMember = uuidList; + return this; + } + + public RemoveChannelMembersOperation Include(PNChannelMemberField[] includeOptions) + { + if (includeOptions != null) { + string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); + this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); + } + return this; + } + + public RemoveChannelMembersOperation Page(PNPageObject pageObject) + { + this.page = pageObject; + return this; + } + + public RemoveChannelMembersOperation Limit(int numberOfObjects) + { + this.limit = numberOfObjects; + return this; + } + + public RemoveChannelMembersOperation IncludeCount(bool includeTotalCount) + { + this.includeCount = includeTotalCount; + return this; + } + + public RemoveChannelMembersOperation Sort(List sortByField) + { + this.sortField = sortByField; + return this; + } + + public RemoveChannelMembersOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(this.channelId) || string.IsNullOrEmpty(channelId.Trim())) { + throw new ArgumentException("Missing Channel"); + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + throw new MissingMemberException("Invalid subscribe key"); + } + + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + + this.savedCallback = callback; + ProcessRemoveChannelMembersOperationRequest(this.channelId, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await ProcessRemoveChannelMembersOperationRequest(this.channelId, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + ProcessRemoveChannelMembersOperationRequest(this.channelId, this.delMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); + } + + private void ProcessRemoveChannelMembersOperationRequest(string spaceId, List removeMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) + { + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNRemoveChannelMembersOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePatchMethod = true; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveChannelMembersOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveChannelMembersOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> ProcessRemoveChannelMembersOperationRequest(string channel, List removeMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNRemoveChannelMembersOperation; + requestState.Reconnect = false; + requestState.UsePatchMethod = true; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveChannelMembersOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNChannelMembersResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveChannelMembersOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private static string MapEnumValueToEndpoint(string enumValue) + { + string ret = string.Empty; + if (enumValue.ToLowerInvariant() == "custom") { + ret = "custom"; + } else if (enumValue.ToLowerInvariant() == "uuid") { + ret = "uuid"; + } else if (enumValue.ToLowerInvariant() == "channel") { + ret = "channel"; + } else if (enumValue.ToLowerInvariant() == "channel_custom") { + ret = "channel.custom"; + } else if (enumValue.ToLowerInvariant() == "uuid_custom") { + ret = "uuid.custom"; + } + return ret; + } + + private RequestParameter CreateRequestParameter() + { + Dictionary messageEnvelope = new Dictionary(); + if (delMember != null) { + List>> removeMemberFormatList = new List>>(); + for (int index = 0; index < delMember.Count; index++) { + Dictionary> currentMemberFormat = new Dictionary>(); + if (!string.IsNullOrEmpty(delMember[index])) { + currentMemberFormat.Add("uuid", new Dictionary { { "id", delMember[index] } }); + removeMemberFormatList.Add(currentMemberFormat); + } + } + if (removeMemberFormatList.Count > 0) { + messageEnvelope.Add("delete", removeMemberFormatList); + } + } + string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); + + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "channels", + string.IsNullOrEmpty(channelId) ? string.Empty : channelId, + "uuids" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) { + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNRemoveChannelMembersOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(page.Prev)) { + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNRemoveChannelMembersOperation, false, false, false)); + } + if (limit >= 0) { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + if (includeCount) { + requestQueryStringParams.Add("count", "true"); + } + if (!string.IsNullOrEmpty(commandDelimitedIncludeOptions)) { + requestQueryStringParams.Add("include", UriUtil.EncodeUriComponent(commandDelimitedIncludeOptions, PNOperationType.PNRemoveChannelMembersOperation, false, false, false)); + } + if (sortField != null && sortField.Count > 0) { + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",", sortField.ToArray()), PNOperationType.PNRemoveChannelMembersOperation, false, false, false)); + } + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNRemoveChannelMembersOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.PATCH, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = patchMessage + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/RemoveChannelMetadataOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/RemoveChannelMetadataOperation.cs index 7529a38e2..bc06dc3c4 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/RemoveChannelMetadataOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/RemoveChannelMetadataOperation.cs @@ -1,188 +1,195 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class RemoveChannelMetadataOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - - private string chMetadataId = ""; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public RemoveChannelMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public RemoveChannelMetadataOperation Channel(string channelName) - { - this.chMetadataId = channelName; - return this; - } - - public RemoveChannelMetadataOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(this.chMetadataId) || string.IsNullOrEmpty(this.chMetadataId.Trim())) - { - throw new ArgumentException("Missing Channel"); - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - throw new MissingMemberException("Invalid Subscribe key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing userCallback"); - } - - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - RemoveChannelMetadata(this.chMetadataId, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - RemoveChannelMetadata(this.chMetadataId, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await RemoveChannelMetadata(this.chMetadataId, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - RemoveChannelMetadata(this.chMetadataId, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - RemoveChannelMetadata(this.chMetadataId, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void RemoveChannelMetadata(string spaceId, Dictionary externalQueryParam, PNCallback callback) - { - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildDeleteChannelMetadataRequest("DELETE", "", spaceId, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNDeleteChannelMetadataOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> RemoveChannelMetadata(string spaceId, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(this.chMetadataId) || string.IsNullOrEmpty(this.chMetadataId.Trim())) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; - ret.Status = errStatus; - return ret; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildDeleteChannelMetadataRequest("DELETE", "", spaceId, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNDeleteChannelMetadataOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNRemoveChannelMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - } + public class RemoveChannelMetadataOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + + private string channelId = string.Empty; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public RemoveChannelMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public RemoveChannelMetadataOperation Channel(string channelName) + { + this.channelId = channelName; + return this; + } + + public RemoveChannelMetadataOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(this.channelId) || string.IsNullOrEmpty(this.channelId.Trim())) { + throw new ArgumentException("Missing Channel"); + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + throw new MissingMemberException("Invalid Subscribe key"); + } + + if (callback == null) { + throw new ArgumentException("Missing userCallback"); + } + this.savedCallback = callback; + RemoveChannelMetadata(this.channelId, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await RemoveChannelMetadata(this.channelId, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + RemoveChannelMetadata(this.channelId, this.queryParam, savedCallback); + } + + private void RemoveChannelMetadata(string spaceId, Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNDeleteChannelMetadataOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNDeleteChannelMetadataOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNDeleteChannelMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> RemoveChannelMetadata(string spaceId, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(this.channelId) || string.IsNullOrEmpty(this.channelId.Trim())) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; + returnValue.Status = errStatus; + return returnValue; + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNDeleteChannelMetadataOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNDeleteChannelMetadataOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNRemoveChannelMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNDeleteChannelMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "channels", + string.IsNullOrEmpty(channelId) ? string.Empty : channelId + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNDeleteChannelMetadataOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.DELETE, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/RemoveMembershipsOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/RemoveMembershipsOperation.cs index 6cde2d341..c016c06b2 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/RemoveMembershipsOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/RemoveMembershipsOperation.cs @@ -3,311 +3,299 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -using Newtonsoft.Json; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class RemoveMembershipsOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string uuidMetadataId = ""; - private List delMembership; - private string commandDelimitedIncludeOptions = ""; - private PNPageObject page; - private int limit = -1; - private bool includeCount; - private List sortField; - - private PNCallback savedCallback; - private Dictionary queryParam; - public RemoveMembershipsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public RemoveMembershipsOperation Uuid(string id) - { - this.uuidMetadataId = id; - return this; - } - - public RemoveMembershipsOperation Channels(List channelIdList) - { - this.delMembership = channelIdList; - return this; - } - - public RemoveMembershipsOperation Include(PNMembershipField[] includeOptions) - { - if (includeOptions != null) - { - string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); - this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); - } - return this; - } - - public RemoveMembershipsOperation Page(PNPageObject pageObject) - { - this.page = pageObject; - return this; - } - - public RemoveMembershipsOperation Limit(int numberOfObjects) - { - this.limit = numberOfObjects; - return this; - } - - public RemoveMembershipsOperation IncludeCount(bool includeTotalCount) - { - this.includeCount = includeTotalCount; - return this; - } - - public RemoveMembershipsOperation Sort(List sortByField) - { - this.sortField = sortByField; - return this; - } - - public RemoveMembershipsOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - throw new MissingMemberException("Invalid subscribe key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - RemoveUuidMemberships(this.uuidMetadataId, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - RemoveUuidMemberships(this.uuidMetadataId, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await RemoveUuidMemberships(this.uuidMetadataId, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - RemoveUuidMemberships(this.uuidMetadataId, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - RemoveUuidMemberships(this.uuidMetadataId, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void RemoveUuidMemberships(string uuid, List removeMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNRemoveMembershipsOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (removeMembership != null) - { - List>> removeMembershipFormatList = new List>>(); - for (int index = 0; index < removeMembership.Count; index++) - { - Dictionary> currentMembershipFormat = new Dictionary>(); - if (!string.IsNullOrEmpty(removeMembership[index])) - { - currentMembershipFormat.Add("channel", new Dictionary { { "id", removeMembership[index] } }); - removeMembershipFormatList.Add(currentMembershipFormat); - } - } - if (removeMembershipFormatList.Count > 0) - { - messageEnvelope.Add("delete", removeMembershipFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMembershipSetRemoveManageUserRequest(requestState.ResponseType, "PATCH", patchMessage, uuid, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - UrlProcessRequest(request, requestState, false, patchData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> RemoveUuidMemberships(string uuid, List removeMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; - ret.Status = errStatus; - return ret; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNRemoveMembershipsOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (removeMembership != null) - { - List>> removeMembershipFormatList = new List>>(); - for (int index = 0; index < removeMembership.Count; index++) - { - Dictionary> currentMembershipFormat = new Dictionary>(); - if (!string.IsNullOrEmpty(removeMembership[index])) - { - currentMembershipFormat.Add("channel", new Dictionary { { "id", removeMembership[index] } }); - removeMembershipFormatList.Add(currentMembershipFormat); - } - } - if (removeMembershipFormatList.Count > 0) - { - messageEnvelope.Add("delete", removeMembershipFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMembershipSetRemoveManageUserRequest(requestState.ResponseType, "PATCH", patchMessage, uuid, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, patchData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNMembershipsResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private static string MapEnumValueToEndpoint(string enumValue) - { - string ret = ""; - if (enumValue.ToLowerInvariant() == "custom") - { - ret = "custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid") - { - ret = "uuid"; - } - else if (enumValue.ToLowerInvariant() == "channel") - { - ret = "channel"; - } - else if (enumValue.ToLowerInvariant() == "channel_custom") - { - ret = "channel.custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid_custom") - { - ret = "uuid.custom"; - } - return ret; - } - - } + public class RemoveMembershipsOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string uuid = string.Empty; + private List delMembership; + private string commandDelimitedIncludeOptions = string.Empty; + private PNPageObject page; + private int limit = -1; + private bool includeCount; + private List sortField; + + private PNCallback savedCallback; + private Dictionary queryParam; + public RemoveMembershipsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public RemoveMembershipsOperation Uuid(string id) + { + this.uuid = id; + return this; + } + + public RemoveMembershipsOperation Channels(List channelIdList) + { + this.delMembership = channelIdList; + return this; + } + + public RemoveMembershipsOperation Include(PNMembershipField[] includeOptions) + { + if (includeOptions != null) { + string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); + this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); + } + return this; + } + + public RemoveMembershipsOperation Page(PNPageObject pageObject) + { + this.page = pageObject; + return this; + } + + public RemoveMembershipsOperation Limit(int numberOfObjects) + { + this.limit = numberOfObjects; + return this; + } + + public RemoveMembershipsOperation IncludeCount(bool includeTotalCount) + { + this.includeCount = includeTotalCount; + return this; + } + + public RemoveMembershipsOperation Sort(List sortByField) + { + this.sortField = sortByField; + return this; + } + + public RemoveMembershipsOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + throw new MissingMemberException("Invalid subscribe key"); + } + + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + this.savedCallback = callback; + RemoveUuidMemberships(this.uuid, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await RemoveUuidMemberships(this.uuid, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + RemoveUuidMemberships(this.uuid, this.delMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); + } + + private void RemoveUuidMemberships(string uuid, List removeMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNRemoveMembershipsOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.UsePatchMethod = true; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveMembershipsOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveMembershipsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> RemoveUuidMemberships(string uuid, List removeMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNRemoveMembershipsOperation; + requestState.Reconnect = false; + requestState.UsePatchMethod = true; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveMembershipsOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNMembershipsResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveMembershipsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private static string MapEnumValueToEndpoint(string enumValue) + { + string ret = ""; + if (enumValue.ToLowerInvariant() == "custom") { + ret = "custom"; + } else if (enumValue.ToLowerInvariant() == "uuid") { + ret = "uuid"; + } else if (enumValue.ToLowerInvariant() == "channel") { + ret = "channel"; + } else if (enumValue.ToLowerInvariant() == "channel_custom") { + ret = "channel.custom"; + } else if (enumValue.ToLowerInvariant() == "uuid_custom") { + ret = "uuid.custom"; + } + return ret; + } + + private RequestParameter CreateRequestParameter() + { + Dictionary messageEnvelope = new Dictionary(); + if (delMembership != null) { + List>> removeMembershipFormatList = new List>>(); + for (int index = 0; index < delMembership.Count; index++) { + Dictionary> currentMembershipFormat = new Dictionary>(); + if (!string.IsNullOrEmpty(delMembership[index])) { + currentMembershipFormat.Add("channel", new Dictionary { { "id", delMembership[index] } }); + removeMembershipFormatList.Add(currentMembershipFormat); + } + } + if (removeMembershipFormatList.Count > 0) { + messageEnvelope.Add("delete", removeMembershipFormatList); + } + } + string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); + byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); + + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "uuids", + string.IsNullOrEmpty(uuid) ? string.Empty : uuid, + "channels" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) { + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNRemoveMembershipsOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(page.Prev)) { + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNRemoveMembershipsOperation, false, false, false)); + } + if (limit >= 0) { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + if (includeCount) { + requestQueryStringParams.Add("count", "true"); + } + if (!string.IsNullOrEmpty(commandDelimitedIncludeOptions)) { + requestQueryStringParams.Add("include", UriUtil.EncodeUriComponent(commandDelimitedIncludeOptions, PNOperationType.PNRemoveMembershipsOperation, false, false, false)); + } + if (sortField != null && sortField.Count > 0) { + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",", sortField.ToArray()), PNOperationType.PNRemoveMembershipsOperation, false, false, false)); + } + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNRemoveMembershipsOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.PATCH, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = patchMessage + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/RemoveUuidMetadataOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/RemoveUuidMetadataOperation.cs index c68183d31..d857265fa 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/RemoveUuidMetadataOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/RemoveUuidMetadataOperation.cs @@ -1,187 +1,194 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class RemoveUuidMetadataOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string usrUuid = ""; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public RemoveUuidMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public RemoveUuidMetadataOperation Uuid(string uuid) - { - this.usrUuid = uuid; - return this; - } - - public RemoveUuidMetadataOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - throw new MissingMemberException("Invalid Subscribe key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing userCallback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - RemoveUuidMetadata(this.usrUuid, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - RemoveUuidMetadata(this.usrUuid, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - - public async Task> ExecuteAsync() - { - return await RemoveUuidMetadata(this.usrUuid, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - RemoveUuidMetadata(this.usrUuid, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - RemoveUuidMetadata(this.usrUuid, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void RemoveUuidMetadata(string uuid, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildDeleteUuidMetadataRequest("DELETE", "", uuid, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNDeleteUuidMetadataOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - - } - - - private async Task> RemoveUuidMetadata(string uuid, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; - ret.Status = errStatus; - return ret; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildDeleteUuidMetadataRequest("DELETE", "", uuid, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNDeleteUuidMetadataOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNRemoveUuidMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - - } - } + public class RemoveUuidMetadataOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string uuid = string.Empty; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public RemoveUuidMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public RemoveUuidMetadataOperation Uuid(string uuid) + { + this.uuid = uuid; + return this; + } + + public RemoveUuidMetadataOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + throw new MissingMemberException("Invalid Subscribe key"); + } + + if (callback == null) { + throw new ArgumentException("Missing userCallback"); + } + + this.savedCallback = callback; + RemoveUuidMetadata(this.uuid, this.queryParam, callback); + } + + + public async Task> ExecuteAsync() + { + return await RemoveUuidMetadata(this.uuid, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + + RemoveUuidMetadata(this.uuid, this.queryParam, savedCallback); + } + + private void RemoveUuidMetadata(string uuid, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNDeleteUuidMetadataOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNDeleteUuidMetadataOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNDeleteUuidMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + + private async Task> RemoveUuidMetadata(string uuid, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNDeleteUuidMetadataOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveMembershipsOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNRemoveUuidMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveMembershipsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "uuids", + string.IsNullOrEmpty(uuid) ? string.Empty : uuid + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNDeleteUuidMetadataOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.DELETE, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/SetChannelMembersOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/SetChannelMembersOperation.cs index 0f0cdb95c..585185a00 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/SetChannelMembersOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/SetChannelMembersOperation.cs @@ -3,317 +3,304 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -using Newtonsoft.Json; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class SetChannelMembersOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string chMetadataId = ""; - private List setMember; - private string commandDelimitedIncludeOptions = ""; - private PNPageObject page; - private int limit = -1; - private bool includeCount; - private List sortField; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public SetChannelMembersOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public SetChannelMembersOperation Channel(string channelName) - { - this.chMetadataId = channelName; - return this; - } - - public SetChannelMembersOperation Uuids(List channelMembers) - { - this.setMember = channelMembers; - return this; - } - - public SetChannelMembersOperation Include(PNChannelMemberField[] includeOptions) - { - if (includeOptions != null) - { - string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); - this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); - } - return this; - } - - public SetChannelMembersOperation Page(PNPageObject pageObject) - { - this.page = pageObject; - return this; - } - - public SetChannelMembersOperation Limit(int numberOfObjects) - { - this.limit = numberOfObjects; - return this; - } - - public SetChannelMembersOperation IncludeCount(bool includeTotalCount) - { - this.includeCount = includeTotalCount; - return this; - } - - public SetChannelMembersOperation Sort(List sortByField) - { - this.sortField = sortByField; - return this; - } - - public SetChannelMembersOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(this.chMetadataId) || string.IsNullOrEmpty(chMetadataId.Trim())) - { - throw new ArgumentException("Missing Channel"); - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - throw new MissingMemberException("Invalid subscribe key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - ProcessMembersOperationRequest(this.chMetadataId, this.setMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void ProcessMembersOperationRequest(string spaceId, List setMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) - { - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNSetChannelMembersOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (setMemberList != null) - { - List> setMemberFormatList = new List>(); - for (int index = 0; index < setMemberList.Count; index++) - { - Dictionary currentMemberFormat = new Dictionary(); - currentMemberFormat.Add("uuid", new Dictionary { { "id", setMemberList[index].Uuid } }); - if (setMemberList[index].Custom != null) - { - currentMemberFormat.Add("custom", setMemberList[index].Custom); - } - setMemberFormatList.Add(currentMemberFormat); - } - if (setMemberFormatList.Count > 0) - { - messageEnvelope.Add("set", setMemberFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMemberAddUpdateRemoveChannelRequest("PATCH", patchMessage, spaceId, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - UrlProcessRequest(request, requestState, false, patchData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> ProcessMembersOperationRequest(string channel, List setMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; - ret.Status = errStatus; - return ret; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNSetChannelMembersOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (setMemberList != null) - { - List> setMemberFormatList = new List>(); - for (int index = 0; index < setMemberList.Count; index++) - { - Dictionary currentMemberFormat = new Dictionary(); - currentMemberFormat.Add("uuid", new Dictionary { { "id", setMemberList[index].Uuid } }); - if (setMemberList[index].Custom != null) - { - currentMemberFormat.Add("custom", setMemberList[index].Custom); - } - setMemberFormatList.Add(currentMemberFormat); - } - if (setMemberFormatList.Count > 0) - { - messageEnvelope.Add("set", setMemberFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMemberAddUpdateRemoveChannelRequest("PATCH", patchMessage, channel, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, patchData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNChannelMembersResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private static string MapEnumValueToEndpoint(string enumValue) - { - string ret = ""; - if (enumValue.ToLowerInvariant() == "custom") - { - ret = "custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid") - { - ret = "uuid"; - } - else if (enumValue.ToLowerInvariant() == "channel") - { - ret = "channel"; - } - else if (enumValue.ToLowerInvariant() == "channel_custom") - { - ret = "channel.custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid_custom") - { - ret = "uuid.custom"; - } - return ret; - } - - } + public class SetChannelMembersOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelId = string.Empty; + private List setMember; + private string commandDelimitedIncludeOptions = string.Empty; + private PNPageObject page; + private int limit = -1; + private bool includeCount; + private List sortField; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public SetChannelMembersOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + if (instance != null) { + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + } + + public SetChannelMembersOperation Channel(string channelId) + { + this.channelId = channelId; + return this; + } + + public SetChannelMembersOperation Uuids(List channelMembers) + { + this.setMember = channelMembers; + return this; + } + + public SetChannelMembersOperation Include(PNChannelMemberField[] includeOptions) + { + if (includeOptions != null) { + string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); + this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); + } + return this; + } + + public SetChannelMembersOperation Page(PNPageObject pageObject) + { + this.page = pageObject; + return this; + } + + public SetChannelMembersOperation Limit(int numberOfObjects) + { + this.limit = numberOfObjects; + return this; + } + + public SetChannelMembersOperation IncludeCount(bool includeTotalCount) + { + this.includeCount = includeTotalCount; + return this; + } + + public SetChannelMembersOperation Sort(List sortByField) + { + this.sortField = sortByField; + return this; + } + + public SetChannelMembersOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(this.channelId) || string.IsNullOrEmpty(channelId.Trim())) { + throw new ArgumentException("Missing Channel"); + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + throw new MissingMemberException("Invalid subscribe key"); + } + + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + this.savedCallback = callback; + ProcessMembersOperationRequest(this.channelId, this.setMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await ProcessMembersOperationRequest(this.channelId, this.setMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + ProcessMembersOperationRequest(this.channelId, this.setMember, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); + } + + private void ProcessMembersOperationRequest(string spaceId, List setMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) + { + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNSetChannelMembersOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.UsePatchMethod = true; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetChannelMembersOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetChannelMembersOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> ProcessMembersOperationRequest(string channel, List setMemberList, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNSetChannelMembersOperation; + requestState.Reconnect = false; + requestState.UsePatchMethod = true; + requestState.EndPointOperation = this; + + + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetChannelMembersOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNChannelMembersResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetChannelMembersOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private static string MapEnumValueToEndpoint(string enumValue) + { + string ret = ""; + if (enumValue.ToLowerInvariant() == "custom") { + ret = "custom"; + } else if (enumValue.ToLowerInvariant() == "uuid") { + ret = "uuid"; + } else if (enumValue.ToLowerInvariant() == "channel") { + ret = "channel"; + } else if (enumValue.ToLowerInvariant() == "channel_custom") { + ret = "channel.custom"; + } else if (enumValue.ToLowerInvariant() == "uuid_custom") { + ret = "uuid.custom"; + } + return ret; + } + + private RequestParameter CreateRequestParameter() + { + Dictionary messageEnvelope = new Dictionary(); + if (setMember != null) { + List> setMemberFormatList = new List>(); + for (int index = 0; index < setMember.Count; index++) { + Dictionary currentMemberFormat = new Dictionary + { + { "uuid", new Dictionary { { "id", setMember[index].Uuid } } } + }; + if (setMember[index].Custom != null) { + currentMemberFormat.Add("custom", setMember[index].Custom); + } + setMemberFormatList.Add(currentMemberFormat); + } + if (setMemberFormatList.Count > 0) { + messageEnvelope.Add("set", setMemberFormatList); + } + } + string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); + + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "channels", + string.IsNullOrEmpty(channelId) ? string.Empty : channelId, + "uuids" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) { + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNSetChannelMembersOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(page.Prev)) { + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNSetChannelMembersOperation, false, false, false)); + } + if (limit >= 0) { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + if (includeCount) { + requestQueryStringParams.Add("count", "true"); + } + if (!string.IsNullOrEmpty(commandDelimitedIncludeOptions)) { + requestQueryStringParams.Add("include", UriUtil.EncodeUriComponent(commandDelimitedIncludeOptions, PNOperationType.PNSetChannelMembersOperation, false, false, false)); + } + if (sortField != null && sortField.Count > 0) { + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",", sortField.ToArray()), PNOperationType.PNSetChannelMembersOperation, false, false, false)); + } + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNSetChannelMembersOperation, false, false, false)); + } + } + } + var requestParameter = new RequestParameter() { + RequestType = Constants.PATCH, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = patchMessage + }; + return requestParameter; + } + + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/SetChannelMetadataOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/SetChannelMetadataOperation.cs index 7a54951a1..c131519a9 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/SetChannelMetadataOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/SetChannelMetadataOperation.cs @@ -1,252 +1,231 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; -using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class SetChannelMetadataOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string chMetaId = ""; - private string chMetaName; - private string chMetaDesc; - private Dictionary chMetaCustom; - private bool includeCustom; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public SetChannelMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public SetChannelMetadataOperation Channel(string channelName) - { - this.chMetaId = channelName; - return this; - } - - public SetChannelMetadataOperation Name(string channelMetadataName) - { - this.chMetaName = channelMetadataName; - return this; - } - - public SetChannelMetadataOperation Description(string channelMetadataDescription) - { - this.chMetaDesc = channelMetadataDescription; - return this; - } - - public SetChannelMetadataOperation Custom(Dictionary channelMetadataCustomObject) - { - this.chMetaCustom = channelMetadataCustomObject; - return this; - } - - public SetChannelMetadataOperation IncludeCustom(bool includeCustomData) - { - this.includeCustom = includeCustomData; - return this; - } - - - public SetChannelMetadataOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(chMetaId) || string.IsNullOrEmpty(chMetaId.Trim())) - { - throw new ArgumentException("Missing Channel"); - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - throw new MissingMemberException("Invalid subscribe key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing userCallback"); - } - - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - SetChannelMetadata(this.chMetaId, this.includeCustom, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - SetChannelMetadata(this.chMetaId, this.includeCustom, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await SetChannelMetadata(this.chMetaId, this.includeCustom, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - SetChannelMetadata(this.chMetaId, this.includeCustom, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - SetChannelMetadata(this.chMetaId, this.includeCustom, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void SetChannelMetadata(string channelMetaId, bool includeCustom, Dictionary externalQueryParam, PNCallback callback) - { - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNSetChannelMetadataOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - - Dictionary messageEnvelope = new Dictionary(); - if (this.chMetaName != null) - { - messageEnvelope.Add("name", chMetaName); - } - if (this.chMetaDesc != null) - { - messageEnvelope.Add("description", chMetaDesc); - } - if (this.chMetaCustom != null) - { - messageEnvelope.Add("custom", chMetaCustom); - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildSetChannelMetadataRequest("PATCH", patchMessage, channelMetaId, includeCustom, externalQueryParam); - - UrlProcessRequest(request, requestState, false, patchData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> SetChannelMetadata(string channelMetaId, bool includeCustom, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(channelMetaId) || string.IsNullOrEmpty(channelMetaId.Trim())) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; - ret.Status = errStatus; - return ret; - } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNSetChannelMetadataOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - - Dictionary messageEnvelope = new Dictionary(); - if (this.chMetaName != null) - { - messageEnvelope.Add("name", chMetaName); - } - if (this.chMetaDesc != null) - { - messageEnvelope.Add("description", chMetaDesc); - } - if (this.chMetaCustom != null) - { - messageEnvelope.Add("custom", chMetaCustom); - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildSetChannelMetadataRequest("PATCH", patchMessage, channelMetaId, includeCustom, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, patchData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNSetChannelMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - } + public class SetChannelMetadataOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelId = string.Empty; + private string channelName; + private string channelDescription; + private Dictionary custom; + private bool includeCustom; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public SetChannelMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public SetChannelMetadataOperation Channel(string channelName) + { + this.channelId = channelName; + return this; + } + + public SetChannelMetadataOperation Name(string channelMetadataName) + { + this.channelName = channelMetadataName; + return this; + } + + public SetChannelMetadataOperation Description(string channelMetadataDescription) + { + this.channelDescription = channelMetadataDescription; + return this; + } + + public SetChannelMetadataOperation Custom(Dictionary channelMetadataCustomObject) + { + this.custom = channelMetadataCustomObject; + return this; + } + + public SetChannelMetadataOperation IncludeCustom(bool includeCustomData) + { + this.includeCustom = includeCustomData; + return this; + } + + + public SetChannelMetadataOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(channelId) || string.IsNullOrEmpty(channelId.Trim())) { + throw new ArgumentException("Missing Channel"); + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + throw new MissingMemberException("Invalid subscribe key"); + } + + if (callback == null) { + throw new ArgumentException("Missing userCallback"); + } + + this.savedCallback = callback; + SetChannelMetadata(this.channelId, this.includeCustom, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await SetChannelMetadata(this.channelId, this.includeCustom, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + SetChannelMetadata(this.channelId, this.includeCustom, this.queryParam, savedCallback); + } + + private void SetChannelMetadata(string channelMetaId, bool includeCustom, Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNSetChannelMetadataOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePatchMethod = true; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetChannelMetadataOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetChannelMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> SetChannelMetadata(string channelMetaId, bool includeCustom, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(channelMetaId) || string.IsNullOrEmpty(channelMetaId.Trim())) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel", new ArgumentException("Missing Channel")) }; + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNSetChannelMetadataOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePatchMethod = true; + + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetChannelMetadataOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, 200, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNSetChannelMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetChannelMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + Dictionary messageEnvelope = new Dictionary(); + if (this.channelName != null) { + messageEnvelope.Add("name", channelName); + } + if (this.channelDescription != null) { + messageEnvelope.Add("description", channelDescription); + } + if (this.custom != null) { + messageEnvelope.Add("custom", custom); + } + string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); + + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "channels", + string.IsNullOrEmpty(channelId) ? string.Empty : channelId + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (includeCustom) { + requestQueryStringParams.Add("include", "custom"); + } + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNSetChannelMetadataOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.PATCH, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = patchMessage + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/SetMembershipsOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/SetMembershipsOperation.cs index 34c0c6495..e645271ef 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/SetMembershipsOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/SetMembershipsOperation.cs @@ -3,314 +3,290 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -using Newtonsoft.Json; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Globalization; namespace PubnubApi.EndPoint { - public class SetMembershipsOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string uuidMetadataId = ""; - private List addMembership; - private string commandDelimitedIncludeOptions = ""; - private PNPageObject page; - private int limit = -1; - private bool includeCount; - private List sortField; - - private PNCallback savedCallback; - private Dictionary queryParam; - - public SetMembershipsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public SetMembershipsOperation Uuid(string id) - { - this.uuidMetadataId = id; - return this; - } - - public SetMembershipsOperation Channels(List memberships) - { - this.addMembership = memberships; - return this; - } - - public SetMembershipsOperation Include(PNMembershipField[] includeOptions) - { - if (includeOptions != null) - { - string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); - this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); - } - return this; - } - - public SetMembershipsOperation Page(PNPageObject pageObject) - { - this.page = pageObject; - return this; - } - - public SetMembershipsOperation Limit(int numberOfObjects) - { - this.limit = numberOfObjects; - return this; - } - - public SetMembershipsOperation IncludeCount(bool includeTotalCount) - { - this.includeCount = includeTotalCount; - return this; - } - - public SetMembershipsOperation Sort(List sortByField) - { - this.sortField = sortByField; - return this; - } - - public SetMembershipsOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - throw new MissingMemberException("Invalid subscribe key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing callback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - SetChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - SetChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await SetChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - SetChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - SetChannelMembershipWithUuid(this.uuidMetadataId, this.addMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void SetChannelMembershipWithUuid(string uuid, List setMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNSetMembershipsOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (setMembership != null) - { - List> setMembershipFormatList = new List>(); - for (int index = 0; index < setMembership.Count; index++) - { - Dictionary currentMembershipFormat = new Dictionary(); - currentMembershipFormat.Add("channel", new Dictionary { { "id", setMembership[index].Channel } }); - if (setMembership[index].Custom != null) - { - currentMembershipFormat.Add("custom", setMembership[index].Custom); - } - setMembershipFormatList.Add(currentMembershipFormat); - } - if (setMembershipFormatList.Count > 0) - { - messageEnvelope.Add("set", setMembershipFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMembershipSetRemoveManageUserRequest(requestState.ResponseType, "PATCH", patchMessage, uuid, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - UrlProcessRequest(request, requestState, false, patchData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - else - { - if (r.Result.Item2 != null) - { - callback.OnResponse(null, r.Result.Item2); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> SetChannelMembershipWithUuid(string uuid, List setMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(uuid)) - { - uuid = config.UserId; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; - ret.Status = errStatus; - return ret; - } - - PNPageObject internalPage; - if (page == null) { internalPage = new PNPageObject(); } - else { internalPage = page; } - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PNSetMembershipsOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - requestState.UsePatchMethod = true; - Dictionary messageEnvelope = new Dictionary(); - if (setMembership != null) - { - List> setMembershipFormatList = new List>(); - for (int index = 0; index < setMembership.Count; index++) - { - Dictionary currentMembershipFormat = new Dictionary(); - currentMembershipFormat.Add("channel", new Dictionary { { "id", setMembership[index].Channel } }); - if (setMembership[index].Custom != null) - { - currentMembershipFormat.Add("custom", setMembership[index].Custom); - } - setMembershipFormatList.Add(currentMembershipFormat); - } - if (setMembershipFormatList.Count > 0) - { - messageEnvelope.Add("set", setMembershipFormatList); - } - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMembershipSetRemoveManageUserRequest(requestState.ResponseType, "PATCH", patchMessage, uuid, internalPage.Next, internalPage.Prev, limit, includeCount, includeOptions, sort, externalQueryParam); - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, patchData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNMembershipsResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private static string MapEnumValueToEndpoint(string enumValue) - { - string ret = ""; - if (enumValue.ToLowerInvariant() == "custom") - { - ret = "custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid") - { - ret = "uuid"; - } - else if (enumValue.ToLowerInvariant() == "channel") - { - ret = "channel"; - } - else if (enumValue.ToLowerInvariant() == "channel_custom") - { - ret = "channel.custom"; - } - else if (enumValue.ToLowerInvariant() == "uuid_custom") - { - ret = "uuid.custom"; - } - return ret; - } - - } + public class SetMembershipsOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string uuid = ""; + private List addMembership; + private string commandDelimitedIncludeOptions = ""; + private PNPageObject page; + private int limit = -1; + private bool includeCount; + private List sortField; + + private PNCallback savedCallback; + private Dictionary queryParam; + + public SetMembershipsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public SetMembershipsOperation Uuid(string id) + { + this.uuid = id; + return this; + } + + public SetMembershipsOperation Channels(List memberships) + { + this.addMembership = memberships; + return this; + } + + public SetMembershipsOperation Include(PNMembershipField[] includeOptions) + { + if (includeOptions != null) { + string[] arrayInclude = includeOptions.Select(x => MapEnumValueToEndpoint(x.ToString())).ToArray(); + this.commandDelimitedIncludeOptions = string.Join(",", arrayInclude); + } + return this; + } + + public SetMembershipsOperation Page(PNPageObject pageObject) + { + this.page = pageObject; + return this; + } + + public SetMembershipsOperation Limit(int numberOfObjects) + { + this.limit = numberOfObjects; + return this; + } + + public SetMembershipsOperation IncludeCount(bool includeTotalCount) + { + this.includeCount = includeTotalCount; + return this; + } + + public SetMembershipsOperation Sort(List sortByField) + { + this.sortField = sortByField; + return this; + } + + public SetMembershipsOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + throw new MissingMemberException("Invalid subscribe key"); + } + + if (callback == null) { + throw new ArgumentException("Missing callback"); + } + + this.savedCallback = callback; + SetChannelMembershipWithUuid(this.uuid, this.addMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await SetChannelMembershipWithUuid(this.uuid, this.addMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + SetChannelMembershipWithUuid(this.uuid, this.addMembership, this.page, this.limit, this.includeCount, this.commandDelimitedIncludeOptions, this.sortField, this.queryParam, savedCallback); + } + + private void SetChannelMembershipWithUuid(string uuid, List setMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNSetMembershipsOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePatchMethod = true; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetMembershipsOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetMembershipsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> SetChannelMembershipWithUuid(string uuid, List setMembership, PNPageObject page, int limit, bool includeCount, string includeOptions, List sort, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(uuid)) { + uuid = config.UserId; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid Subscribe key", new ArgumentException("Invalid Subscribe key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + PNPageObject internalPage; + if (page == null) { internalPage = new PNPageObject(); } else { internalPage = page; } + + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNSetMembershipsOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePatchMethod = true; + + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetMembershipsOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNMembershipsResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetMembershipsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private static string MapEnumValueToEndpoint(string enumValue) + { + string ret = ""; + if (enumValue.ToLowerInvariant() == "custom") { + ret = "custom"; + } else if (enumValue.ToLowerInvariant() == "uuid") { + ret = "uuid"; + } else if (enumValue.ToLowerInvariant() == "channel") { + ret = "channel"; + } else if (enumValue.ToLowerInvariant() == "channel_custom") { + ret = "channel.custom"; + } else if (enumValue.ToLowerInvariant() == "uuid_custom") { + ret = "uuid.custom"; + } + return ret; + } + + private RequestParameter CreateRequestParameter() + { + Dictionary messageEnvelope = new Dictionary(); + if (addMembership != null) { + List> setMembershipFormatList = new List>(); + for (int index = 0; index < addMembership.Count; index++) { + Dictionary currentMembershipFormat = new Dictionary + { + { "channel", new Dictionary { { "id", addMembership[index].Channel } } } + }; + if (addMembership[index].Custom != null) { + currentMembershipFormat.Add("custom", addMembership[index].Custom); + } + setMembershipFormatList.Add(currentMembershipFormat); + } + if (setMembershipFormatList.Count > 0) { + messageEnvelope.Add("set", setMembershipFormatList); + } + } + string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); + byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); + + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "uuids", + string.IsNullOrEmpty(uuid) ? "" : uuid, + "channels" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (!string.IsNullOrEmpty(page.Next)) { + requestQueryStringParams.Add("start", UriUtil.EncodeUriComponent(page.Next, PNOperationType.PNSetMembershipsOperation, false, false, false)); + } + if (!string.IsNullOrEmpty(page.Prev)) { + requestQueryStringParams.Add("end", UriUtil.EncodeUriComponent(page.Prev, PNOperationType.PNSetMembershipsOperation, false, false, false)); + } + if (limit >= 0) { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + if (includeCount) { + requestQueryStringParams.Add("count", "true"); + } + if (!string.IsNullOrEmpty(commandDelimitedIncludeOptions)) { + requestQueryStringParams.Add("include", UriUtil.EncodeUriComponent(commandDelimitedIncludeOptions, PNOperationType.PNSetMembershipsOperation, false, false, false)); + } + if (sortField != null && sortField.Count > 0) { + requestQueryStringParams.Add("sort", UriUtil.EncodeUriComponent(string.Join(",", sortField.ToArray()), PNOperationType.PNSetMembershipsOperation, false, false, false)); + } + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNSetMembershipsOperation, false, false, false)); + } + } + } + string queryString = UriUtil.BuildQueryString(requestQueryStringParams); + + var requestParameter = new RequestParameter() { + RequestType = Constants.PATCH, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = patchMessage + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Objects/SetUuidMetadataOperation.cs b/src/Api/PubnubApi/EndPoint/Objects/SetUuidMetadataOperation.cs index 539378e5d..1518320a9 100644 --- a/src/Api/PubnubApi/EndPoint/Objects/SetUuidMetadataOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Objects/SetUuidMetadataOperation.cs @@ -1,23 +1,19 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class SetUuidMetadataOperation : PubnubCoreBase + public class SetUuidMetadataOperation : PubnubCoreBase { private readonly PNConfiguration config; private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; private string uuidId; private string uuidName; @@ -31,19 +27,18 @@ public class SetUuidMetadataOperation : PubnubCoreBase private PNCallback savedCallback; private Dictionary queryParam; - public SetUuidMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public SetUuidMetadataOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; if (instance != null) { if (!ChannelRequest.ContainsKey(instance.InstanceId)) { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); } if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { @@ -113,20 +108,8 @@ public void Execute(PNCallback callback) throw new ArgumentException("Missing callback"); } -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { this.savedCallback = callback; SetUuidMetadata(this.uuidId, this.includeCustom, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - SetUuidMetadata(this.uuidId, this.includeCustom, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif } public async Task> ExecuteAsync() @@ -136,18 +119,7 @@ public async Task> ExecuteAsync() internal void Retry() { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - SetUuidMetadata(this.uuidId, this.includeCustom, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - SetUuidMetadata(this.uuidId, this.includeCustom, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif + SetUuidMetadata(this.uuidId, this.includeCustom, this.queryParam, savedCallback); } private void SetUuidMetadata(string uuid, bool includeCustom, Dictionary externalQueryParam, PNCallback callback) @@ -162,45 +134,29 @@ private void SetUuidMetadata(string uuid, bool includeCustom, Dictionary messageEnvelope = new Dictionary(); - if (uuidName != null) - { - messageEnvelope.Add("name", uuidName); - } - if (uuidExternalId != null) - { - messageEnvelope.Add("externalId", uuidExternalId); - } - if (uuidProfileUrl != null) - { - messageEnvelope.Add("profileUrl", uuidProfileUrl); - } - if (uuidEmail != null) - { - messageEnvelope.Add("email", uuidEmail); - } - if (uuidCustom != null) - { - messageEnvelope.Add("custom", uuidCustom); - } - string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildSetUuidMetadataRequest("PATCH", patchMessage, uuid, includeCustom, externalQueryParam); - - UrlProcessRequest(request, requestState, false, patchData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetUuidMetadataOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetUuidMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); } private async Task> SetUuidMetadata(string uuid, bool includeCustom, Dictionary externalQueryParam) @@ -209,17 +165,56 @@ private async Task> SetUuidMetadata(string uui { uuid = config.UserId; } - PNResult ret = new PNResult(); + + PNResult returnValue = new PNResult(); RequestState requestState = new RequestState(); requestState.ResponseType = PNOperationType.PNSetUuidMetadataOperation; requestState.Reconnect = false; requestState.EndPointOperation = this; - requestState.UsePatchMethod = true; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetUuidMetadataOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) + { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNSetUuidMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) + { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetUuidMetadataOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { Dictionary messageEnvelope = new Dictionary(); - messageEnvelope.Add("name", uuidName); + if (uuidName != null) + { + messageEnvelope.Add("name", uuidName); + } if (uuidExternalId != null) { messageEnvelope.Add("externalId", uuidExternalId); @@ -237,26 +232,39 @@ private async Task> SetUuidMetadata(string uui messageEnvelope.Add("custom", uuidCustom); } string patchMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] patchData = Encoding.UTF8.GetBytes(patchMessage); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildSetUuidMetadataRequest("PATCH", patchMessage, uuid, includeCustom, externalQueryParam); - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, patchData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) + List pathSegments = new List + { + "v2", + "objects", + config.SubscribeKey, + "uuids", + string.IsNullOrEmpty(uuidId) ? "" : uuidId + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (includeCustom) { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNSetUuidMetadataResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) + requestQueryStringParams.Add("include", "custom"); + } + if (queryParam != null && queryParam.Count > 0) + { + foreach (KeyValuePair kvp in queryParam) { - ret.Result = responseResult; + if (!requestQueryStringParams.ContainsKey(kvp.Key)) + { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNSetUuidMetadataOperation, false, false, false)); + } } } - return ret; + var requestParameter = new RequestParameter() { + RequestType = Constants.PATCH, + PathSegment = pathSegments, + Query = requestQueryStringParams, + BodyContentString = patchMessage + }; + return requestParameter; } } } diff --git a/src/Api/PubnubApi/EndPoint/OtherOperation.cs b/src/Api/PubnubApi/EndPoint/OtherOperation.cs index 67e7efb8b..28c78d6d0 100644 --- a/src/Api/PubnubApi/EndPoint/OtherOperation.cs +++ b/src/Api/PubnubApi/EndPoint/OtherOperation.cs @@ -1,31 +1,25 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; using System.Threading; -using System.Net; -#if !NET35 && !NET40 using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - internal class OtherOperation : PubnubCoreBase + internal class OtherOperation : PubnubCoreBase { private readonly PNConfiguration config; private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - public OtherOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public OtherOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; } public void ChangeUserId(UserId newUserId) @@ -53,9 +47,9 @@ public void ChangeUserId(UserId newUserId) if (channels.Length > 0 || channelGroups.Length > 0) { string channelsJsonState = BuildJsonUserState(channels.ToArray(), channelGroups.ToArray(), false); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); + IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - Uri request = urlBuilder.BuildMultiChannelLeaveRequest("GET", "", channels, channelGroups, channelsJsonState, null); + Uri request = urlBuilder.BuildMultiChannelLeaveRequest(Constants.GET, "", channels, channelGroups, channelsJsonState, null); RequestState requestState = new RequestState(); requestState.Channels = channels; @@ -177,7 +171,7 @@ internal void CurrentPubnubInstance(Pubnub instance) if (!ChannelRequest.ContainsKey(instance.InstanceId)) { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); } if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { diff --git a/src/Api/PubnubApi/EndPoint/Presence/GetStateOperation.cs b/src/Api/PubnubApi/EndPoint/Presence/GetStateOperation.cs index d3673c217..6a9f302d5 100644 --- a/src/Api/PubnubApi/EndPoint/Presence/GetStateOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Presence/GetStateOperation.cs @@ -3,214 +3,226 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class GetStateOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string[] channelNames; - private string[] channelGroupNames; - private string channelUUID = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public GetStateOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public GetStateOperation Channels(string[] channels) - { - this.channelNames = channels; - return this; - } - - public GetStateOperation ChannelGroups(string[] channelGroups) - { - this.channelGroupNames = channelGroups; - return this; - } - - public GetStateOperation Uuid(string uuid) - { - this.channelUUID = uuid; - return this; - } - - public GetStateOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void GetUserState(string[] channels, string[] channelGroups, string uuid, Dictionary externalQueryParam, PNCallback callback) - { - if ((channels == null && channelGroups == null) - || (channels != null && channelGroups != null && channels.Length == 0 && channelGroups.Length == 0)) - { - throw new ArgumentException("Either Channel Or Channel Group or Both should be provided"); - } - string internalUuid; - if (string.IsNullOrEmpty(uuid) || uuid.Trim().Length == 0) - { - internalUuid = config.UserId; - } - else { - internalUuid = uuid; - } - - string channelsCommaDelimited = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ""; - string channelGroupsCommaDelimited = (channelGroups != null && channelGroups.Length > 0) ? string.Join(",", channelGroups.OrderBy(x => x).ToArray()) : ""; - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetUserStateRequest("GET", "", channelsCommaDelimited, channelGroupsCommaDelimited, internalUuid, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = channels; - requestState.ChannelGroups = channelGroups; - requestState.ResponseType = PNOperationType.PNGetStateOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> GetUserState(string[] channels, string[] channelGroups, string uuid, Dictionary externalQueryParam) - { - if ((channels == null && channelGroups == null) - || (channels != null && channelGroups != null && channels.Length == 0 && channelGroups.Length == 0)) - { - throw new ArgumentException("Either Channel Or Channel Group or Both should be provided"); - } - PNResult ret = new PNResult(); - - string internalUuid; - if (string.IsNullOrEmpty(uuid) || uuid.Trim().Length == 0) - { - internalUuid = config.UserId; - } - else - { - internalUuid = uuid; - } - - string channelsCommaDelimited = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ""; - string channelGroupsCommaDelimited = (channelGroups != null && channelGroups.Length > 0) ? string.Join(",", channelGroups.OrderBy(x => x).ToArray()) : ""; - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetUserStateRequest("GET", "", channelsCommaDelimited, channelGroupsCommaDelimited, internalUuid, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = channels; - requestState.ChannelGroups = channelGroups; - requestState.ResponseType = PNOperationType.PNGetStateOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNGetStateResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class GetStateOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string[] channelNames; + private string[] channelGroupNames; + private string channelUUID = ""; + private PNCallback savedCallback; + private Dictionary queryParam; + + public GetStateOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public GetStateOperation Channels(string[] channels) + { + this.channelNames = channels; + return this; + } + + public GetStateOperation ChannelGroups(string[] channelGroups) + { + this.channelGroupNames = channelGroups; + return this; + } + + public GetStateOperation Uuid(string uuid) + { + this.channelUUID = uuid; + return this; + } + + public GetStateOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + GetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await GetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + GetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, this.queryParam, savedCallback); + } + + internal void GetUserState(string[] channels, string[] channelGroups, string uuid, Dictionary externalQueryParam, PNCallback callback) + { + if ((channels == null && channelGroups == null) + || (channels != null && channelGroups != null && channels.Length == 0 && channelGroups.Length == 0)) { + throw new ArgumentException("Either Channel Or Channel Group or Both should be provided"); + } + string internalUuid; + if (string.IsNullOrEmpty(uuid) || uuid.Trim().Length == 0) { + internalUuid = config.UserId; + } else { + internalUuid = uuid; + } + RequestState requestState = new RequestState(); + requestState.Channels = channels; + requestState.ChannelGroups = channelGroups; + requestState.ResponseType = PNOperationType.PNGetStateOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetStateOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetStateOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + internal async Task> GetUserState(string[] channels, string[] channelGroups, string uuid, Dictionary externalQueryParam) + { + if ((channels == null && channelGroups == null) + || (channels != null && channelGroups != null && channels.Length == 0 && channelGroups.Length == 0)) { + throw new ArgumentException("Either Channel Or Channel Group or Both should be provided"); + } + PNResult returnValue = new PNResult(); + + string internalUuid; + if (string.IsNullOrEmpty(uuid) || uuid.Trim().Length == 0) { + internalUuid = config.UserId; + } else { + internalUuid = uuid; + } + RequestState requestState = new RequestState(); + requestState.Channels = channels; + requestState.ChannelGroups = channelGroups; + requestState.ResponseType = PNOperationType.PNGetStateOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetStateOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNGetStateResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetStateOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + + private RequestParameter CreateRequestParameter() + { + string requestUuid = string.IsNullOrEmpty(channelUUID) || channelUUID.Trim().Length == 0 ? config.UserId : channelUUID; + + string channelsCommaDelimited = (channelNames != null && channelNames.Length > 0) ? string.Join(",", channelNames.OrderBy(x => x).ToArray()) : string.Empty; + string channelGroupsCommaDelimited = (channelGroupNames != null && channelGroupNames.Length > 0) ? string.Join(",", channelGroupNames.OrderBy(x => x).ToArray()) : string.Empty; + + List pathSegments = new List + { + "v2", + "presence", + "sub_key", + config.SubscribeKey, + "channel", + string.IsNullOrEmpty(channelsCommaDelimited) || channelsCommaDelimited.Trim().Length <= 0 ? "," : channelsCommaDelimited, + "uuid", + requestUuid + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (!string.IsNullOrEmpty(channelGroupsCommaDelimited) && channelGroupsCommaDelimited.Trim().Length > 0) { + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(channelGroupsCommaDelimited, PNOperationType.PNGetStateOperation, false, false, false)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGetStateOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Presence/HeartbeatOperation.cs b/src/Api/PubnubApi/EndPoint/Presence/HeartbeatOperation.cs index 23493811f..783b38f1c 100644 --- a/src/Api/PubnubApi/EndPoint/Presence/HeartbeatOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Presence/HeartbeatOperation.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Net; +using System.Text; using System.Threading.Tasks; namespace PubnubApi.EndPoint @@ -12,44 +14,90 @@ public class HeartbeatOperation : PubnubCoreBase private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly TelemetryManager pubnubTelemetryMgr; - public HeartbeatOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public HeartbeatOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - PubnubInstance = instance; } internal async Task HeartbeatRequest(string[] channels, string[] channelGroups) { - PNStatus resp = null; + PNStatus responseStatus = null; try { string presenceState = string.Empty; if (config.MaintainPresenceState) presenceState = BuildJsonUserState(channels, channelGroups, true); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, ""); - Uri request = urlBuilder.BuildPresenceHeartbeatRequest("GET", "", channels, channelGroups, presenceState); RequestState pubnubRequestState = new RequestState(); pubnubRequestState.Channels = channels; pubnubRequestState.ChannelGroups = channelGroups; pubnubRequestState.ResponseType = PNOperationType.PNHeartbeatOperation; pubnubRequestState.TimeQueued = DateTime.Now; - await UrlProcessRequest(request, pubnubRequestState, false).ContinueWith(r => { - resp = r.Result.Item2; - }, TaskContinuationOptions.ExecuteSynchronously).ConfigureAwait(false); + var requestParameter = CreateRequestParameter(channels: channels, channelGroups: channelGroups); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNHeartbeatOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(pubnubRequestState, responseString); + if (errorStatus == null) { + responseStatus = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(pubnubRequestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, pubnubRequestState, (int)HttpStatusCode.OK, null); + } else { + responseStatus = errorStatus; + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + responseStatus = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNHeartbeatOperation, category, pubnubRequestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + } } catch (Exception ex) { LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} HeartbeatOperation=> HeartbeatRequest \n channel(s)={1} \n cg(s)={2} \n Exception Details={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", channels.OrderBy(x => x).ToArray()), string.Join(",", channelGroups.OrderBy(x => x).ToArray()), ex), config.LogVerbosity); return new PNStatus(ex, PNOperationType.PNHeartbeatOperation, PNStatusCategory.PNUnknownCategory, channels, channelGroups); } - return resp; + return responseStatus; } + private RequestParameter CreateRequestParameter(string[] channels, string[] channelGroups) + { + string channelString = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; + List pathSegments = new List + { + "v2", + "presence", + "sub_key", + config.SubscribeKey, + "channel", + channelString, + "heartbeat" + }; + string presenceState = string.Empty; + + if (config.MaintainPresenceState) presenceState = BuildJsonUserState(channels, channelGroups, true); + Dictionary requestQueryStringParams = new Dictionary(); + + string channelsJsonState = presenceState; + if (channelsJsonState != "{}" && channelsJsonState != string.Empty) { + requestQueryStringParams.Add("state", UriUtil.EncodeUriComponent(channelsJsonState, PNOperationType.PNHeartbeatOperation, false, false, false)); + } + + if (channelGroups != null && channelGroups.Length > 0) { + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(string.Join(",", channelGroups.OrderBy(x => x).ToArray()), PNOperationType.PNHeartbeatOperation, false, false, false)); + } + + if (config.PresenceTimeout != 0) { + requestQueryStringParams.Add("heartbeat", config.PresenceTimeout.ToString(CultureInfo.InvariantCulture)); + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } } } diff --git a/src/Api/PubnubApi/EndPoint/Presence/HereNowOperation.cs b/src/Api/PubnubApi/EndPoint/Presence/HereNowOperation.cs index d872b2e31..94484c9fa 100644 --- a/src/Api/PubnubApi/EndPoint/Presence/HereNowOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Presence/HereNowOperation.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Linq; +using System.Globalization; +using System.Text; namespace PubnubApi.EndPoint { @@ -15,7 +14,7 @@ public class HereNowOperation : PubnubCoreBase private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; + private string[] channelNames; private string[] channelGroupNames; private bool includeUserState; @@ -23,13 +22,12 @@ public class HereNowOperation : PubnubCoreBase private PNCallback savedCallback; private Dictionary queryParam; - public HereNowOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public HereNowOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; } public HereNowOperation Channels(string[] channels) @@ -70,18 +68,7 @@ public void Async(PNCallback callback) public void Execute(PNCallback callback) { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - HereNow(this.channelNames, this.channelGroupNames, this.includeChannelUUIDs, this.includeUserState, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => { - this.savedCallback = callback; - HereNow(this.channelNames, this.channelGroupNames, this.includeChannelUUIDs, this.includeUserState, this.queryParam, callback); - }) { IsBackground = true }.Start(); -#endif + HereNow(this.channelNames, this.channelGroupNames, this.includeChannelUUIDs, this.includeUserState, this.queryParam, callback); } public async Task> ExecuteAsync() @@ -92,86 +79,130 @@ public async Task> ExecuteAsync() internal void Retry() { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - HereNow(this.channelNames, this.channelGroupNames, this.includeChannelUUIDs, this.includeUserState, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => { - HereNow(this.channelNames, this.channelGroupNames, this.includeChannelUUIDs, this.includeUserState, this.queryParam, savedCallback); - }) { IsBackground = true }.Start(); -#endif + HereNow(this.channelNames, this.channelGroupNames, this.includeChannelUUIDs, this.includeUserState, this.queryParam, savedCallback); } internal void HereNow(string[] channels, string[] channelGroups, bool showUUIDList, bool includeUserState, Dictionary externalQueryParam, PNCallback callback) { - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildHereNowRequest("GET", "", channels, channelGroups, showUUIDList, includeUserState, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = channels; - requestState.ChannelGroups = channelGroups; - requestState.ResponseType = PNOperationType.PNHereNowOperation; - requestState.Reconnect = false; - requestState.PubnubCallback = callback; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); + RequestState requestState = new RequestState { + Channels = channels, + ChannelGroups = channelGroups, + ResponseType = PNOperationType.PNHereNowOperation, + Reconnect = false, + PubnubCallback = callback, + EndPointOperation = this + }; + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNHereNowOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNHereNowOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); + }); } internal async Task> HereNow(string[] channels, string[] channelGroups, bool showUUIDList, bool includeUserState, Dictionary externalQueryParam) { - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildHereNowRequest("GET", "", channels, channelGroups, showUUIDList, includeUserState, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = channels; - requestState.ChannelGroups = channelGroups; - requestState.ResponseType = PNOperationType.PNHereNowOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNHereNowResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) { - ret.Result = responseResult; + PNResult returnValue = new PNResult(); + + RequestState requestState = new RequestState { + Channels = channels, + ChannelGroups = channelGroups, + ResponseType = PNOperationType.PNHereNowOperation, + Reconnect = false, + EndPointOperation = this + }; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNHereNowOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + Tuple JsonAndStatusTuple; + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNHereNowResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNHereNowOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; } - return ret; + return returnValue; } + private RequestParameter CreateRequestParameter() + { + string channel = (channelNames != null && channelNames.Length > 0) ? string.Join(",", channelNames.OrderBy(x => x).ToArray()) : ","; + List pathSegments = new List() { + "v2", + "presence", + "sub_key", + config.SubscribeKey, + "channel", + channel + }; + + int disableUUID = includeChannelUUIDs ? 0 : 1; + int userState = includeUserState ? 1 : 0; + + Dictionary requestQueryStringParams = new Dictionary(); + + string commaDelimitedchannelGroup = (channelGroupNames != null) ? string.Join(",", channelGroupNames.OrderBy(x => x).ToArray()) : ""; + if (!string.IsNullOrEmpty(commaDelimitedchannelGroup) && commaDelimitedchannelGroup.Trim().Length > 0) { + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(commaDelimitedchannelGroup, PNOperationType.PNHereNowOperation, false, false, false)); + } + + requestQueryStringParams.Add("disable_uuids", disableUUID.ToString(CultureInfo.InvariantCulture)); + requestQueryStringParams.Add("state", userState.ToString(CultureInfo.InvariantCulture)); + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNHereNowOperation, false, false, false)); + } + } + } + var queryString = UriUtil.BuildQueryString(requestQueryStringParams); + var requestParameter = new RequestParameter { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } internal void CurrentPubnubInstance(Pubnub instance) { PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } } } diff --git a/src/Api/PubnubApi/EndPoint/Presence/LeaveOperation.cs b/src/Api/PubnubApi/EndPoint/Presence/LeaveOperation.cs index 6fdd8d250..e9b979c94 100644 --- a/src/Api/PubnubApi/EndPoint/Presence/LeaveOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Presence/LeaveOperation.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Net; +using System.Text; using System.Threading.Tasks; namespace PubnubApi.EndPoint @@ -11,37 +14,74 @@ public class LeaveOperation : PubnubCoreBase private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly TelemetryManager pubnubTelemetryManager; - public LeaveOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public LeaveOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryManager = telemetryManager; PubnubInstance = instance; } internal async Task LeaveRequest(string[] channels, string[] channelGroups) { - PNStatus resp = null; + PNStatus responseStatus = null; try { - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryManager, null, string.Empty); - Uri request = urlBuilder.BuildMultiChannelLeaveRequest("GET", string.Empty, channels, channelGroups, string.Empty, null); + RequestState pubnubRequestState = new RequestState(); pubnubRequestState.Channels = channels; pubnubRequestState.ChannelGroups = channelGroups; pubnubRequestState.ResponseType = PNOperationType.Leave; pubnubRequestState.TimeQueued = DateTime.Now; - await UrlProcessRequest(request, pubnubRequestState, false).ContinueWith(r => { - resp = r.Result.Item2; - }, TaskContinuationOptions.ExecuteSynchronously).ConfigureAwait(false); + + var requestParameter = CreateRequestParameter(channels: channels, channelGroups: channelGroups); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.Leave); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(pubnubRequestState, responseString); + if (errorStatus == null) { + responseStatus = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(pubnubRequestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, pubnubRequestState, (int)HttpStatusCode.OK, null); + } else { + responseStatus = errorStatus; + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + responseStatus = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.Leave, category, pubnubRequestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + } } catch (Exception ex) { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} Leave=> LeaveRequest \n channel(s)={1} \n cg(s)={2} \n Exception Details={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", channels.OrderBy(x => x).ToArray()), string.Join(",", channelGroups.OrderBy(x => x).ToArray()), ex), config.LogVerbosity); + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} HeartbeatOperation=> HeartbeatRequest \n channel(s)={1} \n cg(s)={2} \n Exception Details={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", channels.OrderBy(x => x).ToArray()), string.Join(",", channelGroups.OrderBy(x => x).ToArray()), ex), config.LogVerbosity); return new PNStatus(ex, PNOperationType.Leave, PNStatusCategory.PNUnknownCategory, channels, channelGroups); } - return resp; + return responseStatus; + } + private RequestParameter CreateRequestParameter(string[] channels, string[] channelGroups) + { + string channleString = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; + List pathSegments = new List + { + "v2", + "presence", + "sub_key", + config.SubscribeKey, + "channel", + channleString, + "leave" + }; + + var requestQueryStringParams = new Dictionary(); + + if (channelGroups != null && channelGroups.Length > 0) { + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(string.Join(",", channelGroups.OrderBy(x => x).ToArray()), PNOperationType.Leave, false, false, false)); + } + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; } } } diff --git a/src/Api/PubnubApi/EndPoint/Presence/PresenceOperation.cs b/src/Api/PubnubApi/EndPoint/Presence/PresenceOperation.cs index d09a8c9c4..6d5c02b7e 100644 --- a/src/Api/PubnubApi/EndPoint/Presence/PresenceOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Presence/PresenceOperation.cs @@ -15,7 +15,7 @@ public class PresenceOperation private IPubnubUnitTest unit; private IPubnubLog pubnubLog; - public PresenceOperation(Pubnub instance, string instanceId, IPubnubLog pubnubLog, PNConfiguration configuration, TelemetryManager telemetryManager, TokenManager tokenManager, IPubnubUnitTest unit, PresenceEventEngineFactory presenceEventEngineFactory) + public PresenceOperation(Pubnub instance, string instanceId, IPubnubLog pubnubLog, PNConfiguration configuration, TokenManager tokenManager, IPubnubUnitTest unit, PresenceEventEngineFactory presenceEventEngineFactory) { this.pubnubLog = pubnubLog; this.unit = unit; @@ -26,7 +26,7 @@ public PresenceOperation(Pubnub instance, string instanceId, IPubnubLog pubnubLo if (this.presenceEventEngineFactory.HasEventEngine(instanceId)) { presenceEventEngine = this.presenceEventEngineFactory.GetEventEngine(instanceId); } else { - presenceEventEngine = this.presenceEventEngineFactory.InitializeEventEngine(instanceId, instance, pubnubLog, telemetryManager, tokenManager); + presenceEventEngine = this.presenceEventEngineFactory.InitializeEventEngine(instanceId, instance, pubnubLog, tokenManager); presenceEventEngine.OnEffectDispatch += OnEffectDispatch; presenceEventEngine.OnEventQueued += OnEventQueued; } diff --git a/src/Api/PubnubApi/EndPoint/Presence/SetStateOperation.cs b/src/Api/PubnubApi/EndPoint/Presence/SetStateOperation.cs index 3889f196a..8a78e0b46 100644 --- a/src/Api/PubnubApi/EndPoint/Presence/SetStateOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Presence/SetStateOperation.cs @@ -3,560 +3,496 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; using System.Globalization; -#if !NET35 && !NET40 +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class SetStateOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string[] channelNames; - private string[] channelGroupNames; - private Dictionary userState; - private string channelUUID = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public SetStateOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelUserState.ContainsKey(instance.InstanceId)) - { - ChannelUserState.GetOrAdd(instance.InstanceId, new ConcurrentDictionary>()); - } - if (!ChannelGroupUserState.ContainsKey(instance.InstanceId)) - { - ChannelGroupUserState.GetOrAdd(instance.InstanceId, new ConcurrentDictionary>()); - } - if (!ChannelLocalUserState.ContainsKey(instance.InstanceId)) - { - ChannelLocalUserState.GetOrAdd(instance.InstanceId, new ConcurrentDictionary>()); - } - if (!ChannelGroupLocalUserState.ContainsKey(instance.InstanceId)) - { - ChannelGroupLocalUserState.GetOrAdd(instance.InstanceId, new ConcurrentDictionary>()); - } - } - - public SetStateOperation Channels(string[] channels) - { - this.channelNames = channels; - return this; - } - - public SetStateOperation ChannelGroups(string[] channelGroups) - { - this.channelGroupNames = channelGroups; - return this; - } - - public SetStateOperation State(Dictionary state) - { - this.userState = state; - return this; - } - - public SetStateOperation Uuid(string uuid) - { - this.channelUUID = uuid; - return this; - } - - public SetStateOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - string serializedState = jsonLibrary.SerializeToJsonString(this.userState); - SetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, serializedState, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - string serializedState = jsonLibrary.SerializeToJsonString(this.userState); - SetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, serializedState, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { + public class SetStateOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string[] channelNames; + private string[] channelGroupNames; + private Dictionary userState; + private string channelUUID = ""; + private PNCallback savedCallback; + private Dictionary queryParam; + + public SetStateOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelUserState.ContainsKey(instance.InstanceId)) { + ChannelUserState.GetOrAdd(instance.InstanceId, new ConcurrentDictionary>()); + } + if (!ChannelGroupUserState.ContainsKey(instance.InstanceId)) { + ChannelGroupUserState.GetOrAdd(instance.InstanceId, new ConcurrentDictionary>()); + } + if (!ChannelLocalUserState.ContainsKey(instance.InstanceId)) { + ChannelLocalUserState.GetOrAdd(instance.InstanceId, new ConcurrentDictionary>()); + } + if (!ChannelGroupLocalUserState.ContainsKey(instance.InstanceId)) { + ChannelGroupLocalUserState.GetOrAdd(instance.InstanceId, new ConcurrentDictionary>()); + } + } + + public SetStateOperation Channels(string[] channels) + { + this.channelNames = channels; + return this; + } + + public SetStateOperation ChannelGroups(string[] channelGroups) + { + this.channelGroupNames = channelGroups; + return this; + } + + public SetStateOperation State(Dictionary state) + { + this.userState = state; + return this; + } + + public SetStateOperation Uuid(string uuid) + { + this.channelUUID = uuid; + return this; + } + + public SetStateOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + string serializedState = jsonLibrary.SerializeToJsonString(this.userState); + SetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, serializedState, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + string serializedState = jsonLibrary.SerializeToJsonString(this.userState); + return await SetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, serializedState, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { string serializedState = jsonLibrary.SerializeToJsonString(this.userState); - return await SetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, serializedState, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - string serializedState = jsonLibrary.SerializeToJsonString(this.userState); - SetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, serializedState, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - string serializedState = jsonLibrary.SerializeToJsonString(this.userState); - SetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, serializedState, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void SetUserState(string[] channels, string[] channelGroups, string uuid, string jsonUserState, Dictionary externalQueryParam, PNCallback callback) - { - if ((channels == null && channelGroups == null) - || (channels != null && channelGroups != null && channels.Length == 0 && channelGroups.Length == 0)) - { - throw new ArgumentException("Either Channel Or Channel Group or Both should be provided"); - } - - if (string.IsNullOrEmpty(jsonUserState) || string.IsNullOrEmpty(jsonUserState.Trim())) - { - throw new ArgumentException("Missing User State"); - } - - List channelList = new List(); - List channelGroupList = new List(); - string[] filteredChannels = channels; - string[] filteredChannelGroups = channelGroups; - - if (channels != null && channels.Length > 0) - { - channelList = new List(channels); - channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); - filteredChannels = channelList.ToArray(); - } - - if (channelGroups != null && channelGroups.Length > 0) - { - channelGroupList = new List(channelGroups); - channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); - filteredChannelGroups = channelGroupList.ToArray(); - } - - if (!jsonLibrary.IsDictionaryCompatible(jsonUserState, PNOperationType.PNSetStateOperation)) - { - throw new MissingMemberException("Missing json format for user state"); - } - else - { - Dictionary deserializeUserState = jsonLibrary.DeserializeToDictionaryOfObject(jsonUserState); - if (deserializeUserState == null) - { - throw new MissingMemberException("Missing json format user state"); - } - else - { - bool stateChanged = false; - - for (int channelIndex = 0; channelIndex < channelList.Count; channelIndex++) - { - string currentChannel = channelList[channelIndex]; - - string oldJsonChannelState = GetLocalUserState(currentChannel, ""); - - if (oldJsonChannelState != jsonUserState) - { - stateChanged = true; - break; - } - } - - if (!stateChanged) - { - for (int channelGroupIndex = 0; channelGroupIndex < channelGroupList.Count; channelGroupIndex++) - { - string currentChannelGroup = channelGroupList[channelGroupIndex]; - - string oldJsonChannelGroupState = GetLocalUserState("", currentChannelGroup); - - if (oldJsonChannelGroupState != jsonUserState) - { - stateChanged = true; - break; - } - } - } - - if (!stateChanged) - { - StatusBuilder statusBuilder = new StatusBuilder(config, jsonLibrary); - PNStatus status = statusBuilder.CreateStatusResponse< PNSetStateResult>(PNOperationType.PNSetStateOperation, PNStatusCategory.PNUnknownCategory, null, (int)System.Net.HttpStatusCode.NotModified, null); - - Announce(status); - return; - } - - } - } - - SharedSetUserState(filteredChannels, filteredChannelGroups, uuid, jsonUserState, jsonUserState, externalQueryParam, callback); - } - - internal async Task> SetUserState(string[] channels, string[] channelGroups, string uuid, string jsonUserState, Dictionary externalQueryParam) - { - if ((channels == null && channelGroups == null) - || (channels != null && channelGroups != null && channels.Length == 0 && channelGroups.Length == 0)) - { - throw new ArgumentException("Either Channel Or Channel Group or Both should be provided"); - } - - if (string.IsNullOrEmpty(jsonUserState) || string.IsNullOrEmpty(jsonUserState.Trim())) - { - throw new ArgumentException("Missing User State"); - } - - List channelList = new List(); - List channelGroupList = new List(); - string[] filteredChannels = channels; - string[] filteredChannelGroups = channelGroups; - - if (channels != null && channels.Length > 0) - { - channelList = new List(channels); - channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); - filteredChannels = channelList.ToArray(); - } - - if (channelGroups != null && channelGroups.Length > 0) - { - channelGroupList = new List(channelGroups); - channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); - filteredChannelGroups = channelGroupList.ToArray(); - } - - if (!jsonLibrary.IsDictionaryCompatible(jsonUserState, PNOperationType.PNSetStateOperation)) - { - throw new MissingMemberException("Missing json format for user state"); - } - else - { - Dictionary deserializeUserState = jsonLibrary.DeserializeToDictionaryOfObject(jsonUserState); - if (deserializeUserState == null) - { - throw new MissingMemberException("Missing json format user state"); - } - else - { - bool stateChanged = false; - - for (int channelIndex = 0; channelIndex < channelList.Count; channelIndex++) - { - string currentChannel = channelList[channelIndex]; - - string oldJsonChannelState = GetLocalUserState(currentChannel, ""); - - if (oldJsonChannelState != jsonUserState) - { - stateChanged = true; - break; - } - } - - if (!stateChanged) - { - for (int channelGroupIndex = 0; channelGroupIndex < channelGroupList.Count; channelGroupIndex++) - { - string currentChannelGroup = channelGroupList[channelGroupIndex]; - - string oldJsonChannelGroupState = GetLocalUserState("", currentChannelGroup); - - if (oldJsonChannelGroupState != jsonUserState) - { - stateChanged = true; - break; - } - } - } - - if (!stateChanged) - { - PNResult errRet = new PNResult(); - - StatusBuilder statusBuilder = new StatusBuilder(config, jsonLibrary); - PNStatus status = statusBuilder.CreateStatusResponse(PNOperationType.PNSetStateOperation, PNStatusCategory.PNUnknownCategory, null, (int)System.Net.HttpStatusCode.NotModified, null); - errRet.Status = status; - return errRet; - } - - } - } - - return await SharedSetUserState(filteredChannels, filteredChannelGroups, uuid, jsonUserState, jsonUserState, externalQueryParam).ConfigureAwait(false); - } - - private void SharedSetUserState(string[] channels, string[] channelGroups, string uuid, string jsonChannelUserState, string jsonChannelGroupUserState, Dictionary externalQueryParam, PNCallback callback) - { - List channelList; - List channelGroupList; - string currentUuid = uuid; - - string[] channelArray = null; - if (channels != null && channels.Length > 0) - { - channelList = new List(channels); - channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); - channelArray = channelList.ToArray(); - } - - string[] channelGroupsArray = null; - if (channelGroups != null && channelGroups.Length > 0) - { - channelGroupList = new List(channelGroups); - channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); - channelGroupsArray = channelGroupList.ToArray(); - } - - string commaDelimitedChannels = (channelArray != null && channelArray.Length > 0) ? string.Join(",", channelArray.OrderBy(x => x).ToArray()) : ""; - string commaDelimitedChannelGroups = (channelGroupsArray != null && channelGroupsArray.Length > 0) ? string.Join(",", channelGroupsArray.OrderBy(x => x).ToArray()) : ""; - - if (string.IsNullOrEmpty(uuid)) - { - currentUuid = config.UserId; - } - - string jsonUserState = GetJsonSharedSetUserStateInternal(channels, channelGroups, jsonChannelUserState, jsonChannelGroupUserState); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildSetUserStateRequest("GET", "", commaDelimitedChannels, commaDelimitedChannelGroups, currentUuid, jsonUserState, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = channelArray; - requestState.ChannelGroups = channelGroupsArray; - requestState.ResponseType = PNOperationType.PNSetStateOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - //Set TerminateSubRequest to true to bounce the long-polling subscribe requests to update user state - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> SharedSetUserState(string[] channels, string[] channelGroups, string uuid, string jsonChannelUserState, string jsonChannelGroupUserState, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - List channelList; - List channelGroupList; - string currentUuid = uuid; - - string[] channelArray = null; - if (channels != null && channels.Length > 0) - { - channelList = new List(channels); - channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); - channelArray = channelList.ToArray(); - } - - string[] channelGroupsArray = null; - if (channelGroups != null && channelGroups.Length > 0) - { - channelGroupList = new List(channelGroups); - channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); - channelGroupsArray = channelGroupList.ToArray(); - } - - string commaDelimitedChannels = (channelArray != null && channelArray.Length > 0) ? string.Join(",", channelArray.OrderBy(x => x).ToArray()) : ""; - string commaDelimitedChannelGroups = (channelGroupsArray != null && channelGroupsArray.Length > 0) ? string.Join(",", channelGroupsArray.OrderBy(x => x).ToArray()) : ""; - - if (string.IsNullOrEmpty(uuid)) - { - currentUuid = config.UserId; - } - - string jsonUserState = GetJsonSharedSetUserStateInternal(channels, channelGroups, jsonChannelUserState, jsonChannelGroupUserState); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildSetUserStateRequest("GET", "", commaDelimitedChannels, commaDelimitedChannelGroups, currentUuid, jsonUserState, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = channelArray; - requestState.ChannelGroups = channelGroupsArray; - requestState.ResponseType = PNOperationType.PNSetStateOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - //Set TerminateSubRequest to true to bounce the long-polling subscribe requests to update user state - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNSetStateResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private string GetJsonSharedSetUserStateInternal(string[] channels, string[] channelGroups, string jsonChannelUserState, string jsonChannelGroupUserState) - { - List channelList = new List(); - List channelGroupList = new List(); - - if (channels != null && channels.Length > 0) - { - channelList = new List(channels); - channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); - } - - if (channelGroups != null && channelGroups.Length > 0) - { - channelGroupList = new List(channelGroups); - channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); - } - - Dictionary deserializeChannelUserState = jsonLibrary.DeserializeToDictionaryOfObject(jsonChannelUserState); - Dictionary deserializeChannelGroupUserState = jsonLibrary.DeserializeToDictionaryOfObject(jsonChannelGroupUserState); - - for (int channelIndex = 0; channelIndex < channelList.Count; channelIndex++) - { - string currentChannel = channelList[channelIndex]; - - ChannelUserState[PubnubInstance.InstanceId].AddOrUpdate(currentChannel.Trim(), deserializeChannelUserState, (oldState, newState) => deserializeChannelUserState); - ChannelLocalUserState[PubnubInstance.InstanceId].AddOrUpdate(currentChannel.Trim(), deserializeChannelUserState, (oldState, newState) => deserializeChannelUserState); - } - - for (int channelGroupIndex = 0; channelGroupIndex < channelGroupList.Count; channelGroupIndex++) - { - string currentChannelGroup = channelGroupList[channelGroupIndex]; - - ChannelGroupUserState[PubnubInstance.InstanceId].AddOrUpdate(currentChannelGroup.Trim(), deserializeChannelGroupUserState, (oldState, newState) => deserializeChannelGroupUserState); - ChannelGroupLocalUserState[PubnubInstance.InstanceId].AddOrUpdate(currentChannelGroup.Trim(), deserializeChannelGroupUserState, (oldState, newState) => deserializeChannelGroupUserState); - } - - string jsonUserState = "{}"; - - if ((jsonChannelUserState == jsonChannelGroupUserState) || (jsonChannelUserState != "{}" && jsonChannelGroupUserState == "{}")) - { - jsonUserState = jsonChannelUserState; - } - else if (jsonChannelUserState == "{}" && jsonChannelGroupUserState != "{}") - { - jsonUserState = jsonChannelGroupUserState; - } - else if (jsonChannelUserState != "{}" && jsonChannelGroupUserState != "{}") - { - jsonUserState = ""; - for (int channelIndex = 0; channelIndex < channelList.Count; channelIndex++) - { - string currentChannel = channelList[channelIndex]; - - if (jsonUserState == "") - { - jsonUserState = string.Format(CultureInfo.InvariantCulture, "\"{0}\":{{{1}}}", currentChannel, jsonChannelUserState); - } - else - { - jsonUserState = string.Format(CultureInfo.InvariantCulture, "{0},\"{1}\":{{{2}}}", jsonUserState, currentChannel, jsonChannelUserState); - } - } - for (int channelGroupIndex = 0; channelGroupIndex < channelGroupList.Count; channelGroupIndex++) - { - string currentChannelGroup = channelGroupList[channelGroupIndex]; - - if (jsonUserState == "") - { - jsonUserState = string.Format(CultureInfo.InvariantCulture, "\"{0}\":{{{1}}}", currentChannelGroup, jsonChannelGroupUserState); - } - else - { - jsonUserState = string.Format(CultureInfo.InvariantCulture, "{0},\"{1}\":{{{2}}}", jsonUserState, currentChannelGroup, jsonChannelGroupUserState); - } - } - jsonUserState = string.Format(CultureInfo.InvariantCulture, "{{{0}}}", jsonUserState); - } - - return jsonUserState; - } - - private string GetLocalUserState(string channel, string channelGroup) - { - string retJsonUserState = ""; - StringBuilder jsonStateBuilder = new StringBuilder(); - - string channelJsonUserState = BuildJsonUserState(channel, "", false); - string channelGroupJsonUserState = BuildJsonUserState("", channelGroup, false); - - if (channelJsonUserState.Trim().Length > 0 && channelGroupJsonUserState.Trim().Length <= 0) - { - jsonStateBuilder.Append(channelJsonUserState); - } - else if (channelJsonUserState.Trim().Length <= 0 && channelGroupJsonUserState.Trim().Length > 0) - { - jsonStateBuilder.Append(channelGroupJsonUserState); - } - else if (channelJsonUserState.Trim().Length > 0 && channelGroupJsonUserState.Trim().Length > 0) - { - jsonStateBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}:{1},{2}:{3}", channel, channelJsonUserState, channelGroup, channelGroupJsonUserState); - } - - if (jsonStateBuilder.Length > 0) - { - retJsonUserState = string.Format(CultureInfo.InvariantCulture, "{{{0}}}", jsonStateBuilder); - } - - return retJsonUserState; - } - } + SetUserState(this.channelNames, this.channelGroupNames, this.channelUUID, serializedState, this.queryParam, savedCallback); + } + + internal void SetUserState(string[] channels, string[] channelGroups, string uuid, string jsonUserState, Dictionary externalQueryParam, PNCallback callback) + { + if ((channels == null && channelGroups == null) + || (channels != null && channelGroups != null && channels.Length == 0 && channelGroups.Length == 0)) { + throw new ArgumentException("Either Channel Or Channel Group or Both should be provided"); + } + + if (string.IsNullOrEmpty(jsonUserState) || string.IsNullOrEmpty(jsonUserState.Trim())) { + throw new ArgumentException("Missing User State"); + } + + List channelList = new List(); + List channelGroupList = new List(); + string[] filteredChannels = channels; + string[] filteredChannelGroups = channelGroups; + + if (channels != null && channels.Length > 0) { + channelList = new List(channels); + channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); + filteredChannels = channelList.ToArray(); + } + + if (channelGroups != null && channelGroups.Length > 0) { + channelGroupList = new List(channelGroups); + channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); + filteredChannelGroups = channelGroupList.ToArray(); + } + + if (!jsonLibrary.IsDictionaryCompatible(jsonUserState, PNOperationType.PNSetStateOperation)) { + throw new MissingMemberException("Missing json format for user state"); + } else { + Dictionary deserializeUserState = jsonLibrary.DeserializeToDictionaryOfObject(jsonUserState); + if (deserializeUserState == null) { + throw new MissingMemberException("Missing json format user state"); + } else { + bool stateChanged = false; + + for (int channelIndex = 0; channelIndex < channelList.Count; channelIndex++) { + string currentChannel = channelList[channelIndex]; + + string oldJsonChannelState = GetLocalUserState(currentChannel, ""); + + if (oldJsonChannelState != jsonUserState) { + stateChanged = true; + break; + } + } + + if (!stateChanged) { + for (int channelGroupIndex = 0; channelGroupIndex < channelGroupList.Count; channelGroupIndex++) { + string currentChannelGroup = channelGroupList[channelGroupIndex]; + + string oldJsonChannelGroupState = GetLocalUserState("", currentChannelGroup); + + if (oldJsonChannelGroupState != jsonUserState) { + stateChanged = true; + break; + } + } + } + + if (!stateChanged) { + StatusBuilder statusBuilder = new StatusBuilder(config, jsonLibrary); + PNStatus status = statusBuilder.CreateStatusResponse(PNOperationType.PNSetStateOperation, PNStatusCategory.PNUnknownCategory, null, (int)System.Net.HttpStatusCode.NotModified, null); + + Announce(status); + return; + } + + } + } + + SharedSetUserState(filteredChannels, filteredChannelGroups, uuid, jsonUserState, jsonUserState, externalQueryParam, callback); + } + + internal async Task> SetUserState(string[] channels, string[] channelGroups, string uuid, string jsonUserState, Dictionary externalQueryParam) + { + if ((channels == null && channelGroups == null) + || (channels != null && channelGroups != null && channels.Length == 0 && channelGroups.Length == 0)) { + throw new ArgumentException("Either Channel Or Channel Group or Both should be provided"); + } + + if (string.IsNullOrEmpty(jsonUserState) || string.IsNullOrEmpty(jsonUserState.Trim())) { + throw new ArgumentException("Missing User State"); + } + + List channelList = new List(); + List channelGroupList = new List(); + string[] filteredChannels = channels; + string[] filteredChannelGroups = channelGroups; + + if (channels != null && channels.Length > 0) { + channelList = new List(channels); + channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); + filteredChannels = channelList.ToArray(); + } + + if (channelGroups != null && channelGroups.Length > 0) { + channelGroupList = new List(channelGroups); + channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); + filteredChannelGroups = channelGroupList.ToArray(); + } + + if (!jsonLibrary.IsDictionaryCompatible(jsonUserState, PNOperationType.PNSetStateOperation)) { + throw new MissingMemberException("Missing json format for user state"); + } else { + Dictionary deserializeUserState = jsonLibrary.DeserializeToDictionaryOfObject(jsonUserState); + if (deserializeUserState == null) { + throw new MissingMemberException("Missing json format user state"); + } else { + bool stateChanged = false; + + for (int channelIndex = 0; channelIndex < channelList.Count; channelIndex++) { + string currentChannel = channelList[channelIndex]; + + string oldJsonChannelState = GetLocalUserState(currentChannel, ""); + + if (oldJsonChannelState != jsonUserState) { + stateChanged = true; + break; + } + } + + if (!stateChanged) { + for (int channelGroupIndex = 0; channelGroupIndex < channelGroupList.Count; channelGroupIndex++) { + string currentChannelGroup = channelGroupList[channelGroupIndex]; + + string oldJsonChannelGroupState = GetLocalUserState("", currentChannelGroup); + + if (oldJsonChannelGroupState != jsonUserState) { + stateChanged = true; + break; + } + } + } + + if (!stateChanged) { + PNResult errRet = new PNResult(); + + StatusBuilder statusBuilder = new StatusBuilder(config, jsonLibrary); + PNStatus status = statusBuilder.CreateStatusResponse(PNOperationType.PNSetStateOperation, PNStatusCategory.PNUnknownCategory, null, (int)System.Net.HttpStatusCode.NotModified, null); + errRet.Status = status; + return errRet; + } + + } + } + + return await SharedSetUserState(filteredChannels, filteredChannelGroups, uuid, jsonUserState, jsonUserState, externalQueryParam).ConfigureAwait(false); + } + + private void SharedSetUserState(string[] channels, string[] channelGroups, string uuid, string jsonChannelUserState, string jsonChannelGroupUserState, Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.Channels = channelNames; + requestState.ChannelGroups = channelGroupNames; + requestState.ResponseType = PNOperationType.PNSetStateOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetStateOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetStateOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + private async Task> SharedSetUserState(string[] channels, string[] channelGroups, string uuid, string jsonChannelUserState, string jsonChannelGroupUserState, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.Channels = channelNames; + requestState.ChannelGroups = channelGroupNames; + requestState.ResponseType = PNOperationType.PNSetStateOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSetStateOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNSetStateResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSetStateOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private string GetJsonSharedSetUserStateInternal(string[] channels, string[] channelGroups, string jsonChannelUserState, string jsonChannelGroupUserState) + { + List channelList = new List(); + List channelGroupList = new List(); + + if (channels != null && channels.Length > 0) { + channelList = new List(channels); + channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); + } + + if (channelGroups != null && channelGroups.Length > 0) { + channelGroupList = new List(channelGroups); + channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); + } + + Dictionary deserializeChannelUserState = jsonLibrary.DeserializeToDictionaryOfObject(jsonChannelUserState); + Dictionary deserializeChannelGroupUserState = jsonLibrary.DeserializeToDictionaryOfObject(jsonChannelGroupUserState); + + for (int channelIndex = 0; channelIndex < channelList.Count; channelIndex++) { + string currentChannel = channelList[channelIndex]; + + ChannelUserState[PubnubInstance.InstanceId].AddOrUpdate(currentChannel.Trim(), deserializeChannelUserState, (oldState, newState) => deserializeChannelUserState); + ChannelLocalUserState[PubnubInstance.InstanceId].AddOrUpdate(currentChannel.Trim(), deserializeChannelUserState, (oldState, newState) => deserializeChannelUserState); + } + + for (int channelGroupIndex = 0; channelGroupIndex < channelGroupList.Count; channelGroupIndex++) { + string currentChannelGroup = channelGroupList[channelGroupIndex]; + + ChannelGroupUserState[PubnubInstance.InstanceId].AddOrUpdate(currentChannelGroup.Trim(), deserializeChannelGroupUserState, (oldState, newState) => deserializeChannelGroupUserState); + ChannelGroupLocalUserState[PubnubInstance.InstanceId].AddOrUpdate(currentChannelGroup.Trim(), deserializeChannelGroupUserState, (oldState, newState) => deserializeChannelGroupUserState); + } + + string jsonUserState = "{}"; + + if ((jsonChannelUserState == jsonChannelGroupUserState) || (jsonChannelUserState != "{}" && jsonChannelGroupUserState == "{}")) { + jsonUserState = jsonChannelUserState; + } else if (jsonChannelUserState == "{}" && jsonChannelGroupUserState != "{}") { + jsonUserState = jsonChannelGroupUserState; + } else if (jsonChannelUserState != "{}" && jsonChannelGroupUserState != "{}") { + jsonUserState = ""; + for (int channelIndex = 0; channelIndex < channelList.Count; channelIndex++) { + string currentChannel = channelList[channelIndex]; + + if (jsonUserState == "") { + jsonUserState = string.Format(CultureInfo.InvariantCulture, "\"{0}\":{{{1}}}", currentChannel, jsonChannelUserState); + } else { + jsonUserState = string.Format(CultureInfo.InvariantCulture, "{0},\"{1}\":{{{2}}}", jsonUserState, currentChannel, jsonChannelUserState); + } + } + for (int channelGroupIndex = 0; channelGroupIndex < channelGroupList.Count; channelGroupIndex++) { + string currentChannelGroup = channelGroupList[channelGroupIndex]; + + if (jsonUserState == "") { + jsonUserState = string.Format(CultureInfo.InvariantCulture, "\"{0}\":{{{1}}}", currentChannelGroup, jsonChannelGroupUserState); + } else { + jsonUserState = string.Format(CultureInfo.InvariantCulture, "{0},\"{1}\":{{{2}}}", jsonUserState, currentChannelGroup, jsonChannelGroupUserState); + } + } + jsonUserState = string.Format(CultureInfo.InvariantCulture, "{{{0}}}", jsonUserState); + } + + return jsonUserState; + } + + private string GetLocalUserState(string channel, string channelGroup) + { + string retJsonUserState = ""; + StringBuilder jsonStateBuilder = new StringBuilder(); + + string channelJsonUserState = BuildJsonUserState(channel, "", false); + string channelGroupJsonUserState = BuildJsonUserState("", channelGroup, false); + + if (channelJsonUserState.Trim().Length > 0 && channelGroupJsonUserState.Trim().Length <= 0) { + jsonStateBuilder.Append(channelJsonUserState); + } else if (channelJsonUserState.Trim().Length <= 0 && channelGroupJsonUserState.Trim().Length > 0) { + jsonStateBuilder.Append(channelGroupJsonUserState); + } else if (channelJsonUserState.Trim().Length > 0 && channelGroupJsonUserState.Trim().Length > 0) { + jsonStateBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}:{1},{2}:{3}", channel, channelJsonUserState, channelGroup, channelGroupJsonUserState); + } + + if (jsonStateBuilder.Length > 0) { + retJsonUserState = string.Format(CultureInfo.InvariantCulture, "{{{0}}}", jsonStateBuilder); + } + + return retJsonUserState; + } + + private RequestParameter CreateRequestParameter() + { + List channelList; + List channelGroupList; + string requestUuid = string.IsNullOrEmpty(channelUUID) ? config.UserId : channelUUID; + + string[] channelArray = null; + if (channelNames != null && channelNames.Length > 0) { + channelList = new List(channelNames); + channelList = channelList.Where(ch => !string.IsNullOrEmpty(ch) && ch.Trim().Length > 0).Distinct().ToList(); + channelArray = channelList.ToArray(); + } + + string[] channelGroupsArray = null; + if (channelGroupNames != null && channelGroupNames.Length > 0) { + channelGroupList = new List(channelGroupNames); + channelGroupList = channelGroupList.Where(cg => !string.IsNullOrEmpty(cg) && cg.Trim().Length > 0).Distinct().ToList(); + channelGroupsArray = channelGroupList.ToArray(); + } + + string commaDelimitedChannels = (channelArray != null && channelArray.Length > 0) ? string.Join(",", channelArray.OrderBy(x => x).ToArray()) : ""; + string commaDelimitedChannelGroups = (channelGroupsArray != null && channelGroupsArray.Length > 0) ? string.Join(",", channelGroupsArray.OrderBy(x => x).ToArray()) : ""; + + string serialisedState = jsonLibrary.SerializeToJsonString(userState); + string jsonUserState = GetJsonSharedSetUserStateInternal(channelArray, channelGroupsArray, serialisedState, serialisedState); + + string internalChannelsCommaDelimited; + + if (string.IsNullOrEmpty(commaDelimitedChannels) || commaDelimitedChannels.Trim().Length <= 0) { + internalChannelsCommaDelimited = ","; + } else { + internalChannelsCommaDelimited = commaDelimitedChannels; + } + + List pathSegments = new List + { + "v2", + "presence", + "sub_key", + config.SubscribeKey, + "channel", + internalChannelsCommaDelimited, + "uuid", + requestUuid, + "data" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (!string.IsNullOrEmpty(commaDelimitedChannelGroups) && commaDelimitedChannelGroups.Trim().Length > 0) { + requestQueryStringParams.Add("state", UriUtil.EncodeUriComponent(jsonUserState, PNOperationType.PNSetStateOperation, false, false, false)); + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(commaDelimitedChannelGroups, PNOperationType.PNSetStateOperation, false, false, false)); + } else { + requestQueryStringParams.Add("state", UriUtil.EncodeUriComponent(jsonUserState, PNOperationType.PNSetStateOperation, false, false, false)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNSetStateOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Presence/WhereNowOperation.cs b/src/Api/PubnubApi/EndPoint/Presence/WhereNowOperation.cs index e8056d7e4..5bd870d68 100644 --- a/src/Api/PubnubApi/EndPoint/Presence/WhereNowOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Presence/WhereNowOperation.cs @@ -1,195 +1,175 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class WhereNowOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string whereNowUUID = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public WhereNowOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public WhereNowOperation Uuid(string uuid) - { - this.whereNowUUID = uuid; - return this; - } - - public WhereNowOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - WhereNow(this.whereNowUUID, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - WhereNow(this.whereNowUUID, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await WhereNow(this.whereNowUUID, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - WhereNow(this.whereNowUUID, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - WhereNow(this.whereNowUUID, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void WhereNow(string uuid, Dictionary externalQueryParam, PNCallback callback) - { - if (jsonLibrary == null) - { - throw new MissingMemberException("Missing Json Pluggable Library for Pubnub Instance"); - } - - string currentUuid = ""; - if (string.IsNullOrEmpty(uuid)) - { - currentUuid = config.UserId; - } - else - { - currentUuid = uuid; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildWhereNowRequest("GET", "", currentUuid, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new [] { currentUuid }; - requestState.ResponseType = PNOperationType.PNWhereNowOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> WhereNow(string uuid, Dictionary externalQueryParam) - { - if (jsonLibrary == null) - { - throw new MissingMemberException("Missing Json Pluggable Library for Pubnub Instance"); - } - - PNResult ret = new PNResult(); - string currentUuid = ""; - if (string.IsNullOrEmpty(uuid)) - { - currentUuid = config.UserId; - } - else - { - currentUuid = uuid; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildWhereNowRequest("GET", "", currentUuid, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { currentUuid }; - requestState.ResponseType = PNOperationType.PNWhereNowOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNWhereNowResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class WhereNowOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string whereNowUUID = string.Empty; + private PNCallback savedCallback; + private Dictionary queryParam; + + public WhereNowOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public WhereNowOperation Uuid(string uuid) + { + this.whereNowUUID = uuid; + return this; + } + + public WhereNowOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + WhereNow(this.whereNowUUID, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await WhereNow(this.whereNowUUID, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + WhereNow(this.whereNowUUID, this.queryParam, savedCallback); + } + + internal void WhereNow(string uuid, Dictionary externalQueryParam, PNCallback callback) + { + if (jsonLibrary == null) { + throw new MissingMemberException("Missing Json Pluggable Library for Pubnub Instance"); + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { whereNowUUID ?? config.UserId }; + requestState.ResponseType = PNOperationType.PNWhereNowOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNWhereNowOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNWhereNowOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + internal async Task> WhereNow(string uuid, Dictionary externalQueryParam) + { + if (jsonLibrary == null) { + throw new MissingMemberException("Missing Json Pluggable Library for Pubnub Instance"); + } + + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.Channels = new[] { whereNowUUID ?? config.UserId }; + requestState.ResponseType = PNOperationType.PNWhereNowOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNWhereNowOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNWhereNowResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNWhereNowOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + } + private RequestParameter CreateRequestParameter() + { + + List pathSegments = new List + { + "v2", + "presence", + "sub_key", + config.SubscribeKey, + "uuid", + string.IsNullOrEmpty(whereNowUUID) ? config.UserId : whereNowUUID + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNWhereNowOperation, false, false, false)); + } + } + } + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/AddMessageActionOperation.cs b/src/Api/PubnubApi/EndPoint/PubSub/AddMessageActionOperation.cs index 926036467..21b516fd8 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/AddMessageActionOperation.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/AddMessageActionOperation.cs @@ -1,249 +1,247 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Globalization; namespace PubnubApi.EndPoint { - public class AddMessageActionOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string msgActionChannelName = ""; - private long messageTimetoken; - private PNMessageAction addMessageAction; - private PNCallback savedCallback; - private Dictionary queryParam; - - public AddMessageActionOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - - - public AddMessageActionOperation Channel(string channelName) - { - msgActionChannelName = channelName; - return this; - } - - /// - /// The publish timetoken of a parent message - /// - /// - /// - public AddMessageActionOperation MessageTimetoken(long timetoken) - { - messageTimetoken = timetoken; - return this; - } - - public AddMessageActionOperation Action(PNMessageAction messageAction) - { - addMessageAction = messageAction; - return this; - } - - public AddMessageActionOperation QueryParam(Dictionary customQueryParam) - { - queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) - { - throw new MissingMemberException("subscribe key is required"); - } - - if (callback == null) - { - throw new ArgumentException("Missing userCallback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - Publish(this.msgActionChannelName, this.messageTimetoken, this.addMessageAction, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - Publish(this.msgActionChannelName, this.messageTimetoken, this.addMessageAction, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) - { - throw new MissingMemberException("subscribe key is required"); - } - - return await Publish(this.msgActionChannelName, this.messageTimetoken, this.addMessageAction, this.queryParam).ConfigureAwait(false); - } - - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - Publish(this.msgActionChannelName, this.messageTimetoken, this.addMessageAction, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - Publish(this.msgActionChannelName, this.messageTimetoken, this.addMessageAction, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void Publish(string channel, long messageTimetoken, PNMessageAction messageAction, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || messageAction == null) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); - callback.OnResponse(null, status); - return; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); - callback.OnResponse(null, status); - return; - } - - if (callback == null) - { - return; - } - - string requestMethodName = "POST"; - string postMessage = jsonLibrary.SerializeToJsonString(messageAction); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildAddMessageActionRequest(requestMethodName, postMessage, channel, messageTimetoken, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNAddMessageActionOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - requestState.UsePostMethod = true; - - UrlProcessRequest(request, requestState, false, postData).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - - ProcessResponseCallbacks(result, requestState); - } - CleanUp(); - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> Publish(string channel, long messageTimetoken, PNMessageAction messageAction, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || messageAction == null) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); - ret.Status = status; - return ret; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); - ret.Status = status; - return ret; - } - - string requestMethodName = "POST"; - string postMessage = jsonLibrary.SerializeToJsonString(messageAction); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildAddMessageActionRequest(requestMethodName, postMessage, channel, messageTimetoken, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNAddMessageActionOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - requestState.UsePostMethod = true; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, postData).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNAddMessageActionResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private void CleanUp() - { - this.savedCallback = null; - } - } - + public class AddMessageActionOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelName = ""; + private long messageTimetoken; + private PNMessageAction messageAction; + private PNCallback savedCallback; + private Dictionary queryParam; + + public AddMessageActionOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + PubnubInstance = instance; + } + + + public AddMessageActionOperation Channel(string channel) + { + channelName = channel; + return this; + } + + /// + /// The publish timetoken of a parent message + /// + /// + /// + public AddMessageActionOperation MessageTimetoken(long timetoken) + { + messageTimetoken = timetoken; + return this; + } + + public AddMessageActionOperation Action(PNMessageAction messageAction) + { + this.messageAction = messageAction; + return this; + } + + public AddMessageActionOperation QueryParam(Dictionary customQueryParam) + { + queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) { + throw new MissingMemberException("subscribe key is required"); + } + + if (callback == null) { + throw new ArgumentException("Missing userCallback"); + } + + savedCallback = callback; + Publish(channelName, messageTimetoken, messageAction, queryParam, callback); + } + + public async Task> ExecuteAsync() + { + if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) { + throw new MissingMemberException("subscribe key is required"); + } + + return await Publish(this.channelName, this.messageTimetoken, this.messageAction, this.queryParam); + } + + + internal void Retry() + { + Publish(this.channelName, this.messageTimetoken, this.messageAction, this.queryParam, savedCallback); + } + + private void Publish(string channel, long messageTimetoken, PNMessageAction messageAction, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(channelName) || string.IsNullOrEmpty(channelName.Trim()) || messageAction == null) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); + callback.OnResponse(null, status); + return; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); + callback.OnResponse(null, status); + return; + } + + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channelName }; + requestState.ResponseType = PNOperationType.PNAddMessageActionOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePostMethod = true; + Tuple JsonAndStatusTuple; + + var requestParameters = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameters, PNOperationType.PNPublishOperation); + + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + if (t.Result.Error == null) { + var responseString = Encoding.UTF8.GetString(t.Result.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple("", errorStatus); + } + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List result = ProcessJsonResponse(requestState, json); + ProcessResponseCallbacks(result, requestState); + } else { + requestState.PubnubCallback.OnResponse(default(PNAddMessageActionResult), errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishOperation, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNAddMessageActionResult), status); + } + CleanUp(); + }); + } + + private async Task> Publish(string channel, long messageTimetoken, PNMessageAction messageAction, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || messageAction == null) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); + returnValue.Status = status; + return returnValue; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); + returnValue.Status = status; + return returnValue; + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNAddMessageActionOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + requestState.UsePostMethod = true; + + Tuple JsonAndStatusTuple; + + var requestParams = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParams, operationType: PNOperationType.PNAddMessageActionOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple("", errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNAddMessageActionResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } else { + returnValue.Status = errorStatus; + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNAddMessageActionOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List urlSegments = new List() { + "v1", + "message-actions", + config.SubscribeKey, + "channel", + this.channelName, + "message", + messageTimetoken.ToString(CultureInfo.InvariantCulture) + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (this.queryParam != null && this.queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNAddMessageActionOperation, false, false, false)); + } + } + } + + string postMessage = jsonLibrary.SerializeToJsonString(messageAction); + var requestParam = new RequestParameter() { + RequestType = Constants.POST, + PathSegment = urlSegments, + BodyContentString = postMessage, + Query = requestQueryStringParams + }; + return requestParam; + } + + private void CleanUp() + { + this.savedCallback = null; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/FireOperation.cs b/src/Api/PubnubApi/EndPoint/PubSub/FireOperation.cs index e51c10e30..8c5bb5829 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/FireOperation.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/FireOperation.cs @@ -1,337 +1,307 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; using System.Net; -#if !NET35 && !NET40 +using PubnubApi.Security.Crypto; +using PubnubApi.Security.Crypto.Cryptors; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class FireOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private object msg; - private string channelName = ""; - private bool httpPost; - private Dictionary userMetadata; - private readonly int ttl = -1; - private PNCallback savedCallback; - private bool syncRequest; - private Dictionary queryParam; - - public FireOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public FireOperation Message(object message) - { - this.msg = message; - return this; - } - - public FireOperation Channel(string channelName) - { - this.channelName = channelName; - return this; - } - - public FireOperation Meta(Dictionary metadata) - { - this.userMetadata = metadata; - return this; - } - - public FireOperation UsePOST(bool post) - { - this.httpPost = post; - return this; - } - - public FireOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim()) || this.msg == null) - { - throw new ArgumentException("Missing Channel or Message"); - } - - if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) - { - throw new MissingMemberException("Invalid publish key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing userCallback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - syncRequest = false; - this.savedCallback = callback; - Fire(this.channelName, this.msg, false, this.ttl, this.userMetadata, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - syncRequest = false; - this.savedCallback = callback; - Fire(this.channelName, this.msg, false, this.ttl, this.userMetadata, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - syncRequest = false; - return await Fire(this.channelName, this.msg, false, this.ttl, this.userMetadata, this.queryParam).ConfigureAwait(false); - } - - public PNPublishResult Sync() - { - System.Threading.ManualResetEvent syncEvent = new System.Threading.ManualResetEvent(false); - Task task = Task.Factory.StartNew(() => - { - syncRequest = true; - syncEvent = new System.Threading.ManualResetEvent(false); - Fire(this.channelName, this.msg, false, this.ttl, this.userMetadata, this.queryParam, new PNPublishResultExt((r,s)=> { SyncResult = r; syncEvent.Set(); })); - syncEvent.WaitOne(config.NonSubscribeRequestTimeout * 1000); - - return SyncResult; - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default); - return task.Result; - } - - private static PNPublishResult SyncResult { get; set; } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - if (!syncRequest) - { - Fire(this.channelName, this.msg, false, this.ttl, this.userMetadata, this.queryParam, savedCallback); - } - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - if (!syncRequest) - { - Fire(this.channelName, this.msg, false, this.ttl, this.userMetadata, this.queryParam, savedCallback); - } - }) - { IsBackground = true }.Start(); -#endif - } - - private void Fire(string channel, object message, bool storeInHistory, int ttl, Dictionary metaData, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) - { - PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")) }; - callback.OnResponse(null, status); - return; - } - - if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) - { - PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid publish key", new ArgumentException("Invalid publish key")) }; - callback.OnResponse(null, status); - return; - } - - if (callback == null) - { - return; - } - - Dictionary urlParam = new Dictionary(); - urlParam.Add("norep", "true"); - - string requestMethodName = (this.httpPost) ? "POST" : "GET"; - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildPublishRequest(requestMethodName, "", channel, message, storeInHistory, ttl, metaData, urlParam, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new [] { channel }; - requestState.ResponseType = PNOperationType.PNFireOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - string json = ""; - - if (this.httpPost) - { - requestState.UsePostMethod = true; - Dictionary messageEnvelope = new Dictionary(); - messageEnvelope.Add("message", message); - string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - UrlProcessRequest(request, requestState, false, postData).ContinueWith(r => - { - json = r.Result.Item1; - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - else - { - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - json = r.Result.Item1; - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - if (result != null && result.Count >= 3) - { - int publishStatus; - var _ = Int32.TryParse(result[0].ToString(), out publishStatus); - if (publishStatus == 1) - { - ProcessResponseCallbacks(result, requestState); - } - else - { - PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); - PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNFireOperation, category, requestState, 400, new PNException(json)); - if (requestState.PubnubCallback != null) - { - requestState.PubnubCallback.OnResponse(default(PNPublishResult), status); - } - } - } - else - { - ProcessResponseCallbacks(result, requestState); - } - } - } - - private async Task> Fire(string channel, object message, bool storeInHistory, int ttl, Dictionary metaData, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")) }; - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid publish key", new ArgumentException("Invalid publish key")) }; - ret.Status = errStatus; - return ret; - } - - Dictionary urlParam = new Dictionary(); - urlParam.Add("norep", "true"); - - string requestMethodName = (this.httpPost) ? "POST" : "GET"; - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildPublishRequest(requestMethodName, "", channel, message, storeInHistory, ttl, metaData, urlParam, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNFireOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple; - - if (this.httpPost) - { - requestState.UsePostMethod = true; - Dictionary messageEnvelope = new Dictionary(); - messageEnvelope.Add("message", message); - string postMessage = jsonLibrary.SerializeToJsonString(messageEnvelope); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, postData).ConfigureAwait(false); - } - else - { - JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - } - - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - if (result != null && result.Count >= 3) - { - int publishStatus; - var _ = Int32.TryParse(result[0].ToString(), out publishStatus); - if (publishStatus == 1) - { - List resultList = ProcessJsonResponse(requestState, json); - if (resultList != null && resultList.Count > 0) - { - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNPublishResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - } - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class FireOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private object publishContent; + private string channelName = ""; + private bool httpPost; + private Dictionary userMetadata; + private readonly int ttl = -1; + private PNCallback savedCallback; + private bool syncRequest; + private Dictionary queryParam; + + public FireOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public FireOperation Message(object message) + { + this.publishContent = message; + return this; + } + + public FireOperation Channel(string channelName) + { + this.channelName = channelName; + return this; + } + + public FireOperation Meta(Dictionary metadata) + { + this.userMetadata = metadata; + return this; + } + + public FireOperation UsePOST(bool post) + { + this.httpPost = post; + return this; + } + + public FireOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim()) || this.publishContent == null) { + throw new ArgumentException("Missing Channel or Message"); + } + + if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) { + throw new MissingMemberException("Invalid publish key"); + } + + if (callback == null) { + throw new ArgumentException("Missing userCallback"); + } + Fire(this.channelName, this.publishContent, false, this.ttl, this.userMetadata, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + syncRequest = false; + return await Fire(this.channelName, this.publishContent, false, this.ttl, this.userMetadata, this.queryParam).ConfigureAwait(false); + } + + public PNPublishResult Sync() + { + System.Threading.ManualResetEvent syncEvent = new System.Threading.ManualResetEvent(false); + Task task = Task.Factory.StartNew(() => { + syncRequest = true; + syncEvent = new System.Threading.ManualResetEvent(false); + Fire(this.channelName, this.publishContent, false, this.ttl, this.userMetadata, this.queryParam, new PNPublishResultExt((r, s) => { SyncResult = r; syncEvent.Set(); })); + syncEvent.WaitOne(config.NonSubscribeRequestTimeout * 1000); + + return SyncResult; + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default); + return task.Result; + } + + private static PNPublishResult SyncResult { get; set; } + + internal void Retry() + { + Fire(this.channelName, this.publishContent, false, this.ttl, this.userMetadata, this.queryParam, savedCallback); + } + + private void Fire(string channel, object message, bool storeInHistory, int ttl, Dictionary metaData, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) { + PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")) }; + callback.OnResponse(null, status); + return; + } + + if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) { + PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid publish key", new ArgumentException("Invalid publish key")) }; + callback.OnResponse(null, status); + return; + } + + if (callback == null) { + return; + } + + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNFireOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNFireOperation); + + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + if (result != null && result.Count >= 3) { + int publishStatus; + var _ = Int32.TryParse(result[0].ToString(), out publishStatus); + if (publishStatus == 1) { + ProcessResponseCallbacks(result, requestState); + } else { + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNFireOperation, category, requestState, 400, new PNException(responseString)); + if (requestState.PubnubCallback != null) { + requestState.PubnubCallback.OnResponse(default(PNPublishResult), status); + } + } + } else { + ProcessResponseCallbacks(result, requestState); + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNFireOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNPublishResult), status); + } + }); + } + + private async Task> Fire(string channel, object message, bool storeInHistory, int ttl, Dictionary metaData, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")) }; + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid publish key", new ArgumentException("Invalid publish key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNFireOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + Tuple JsonAndStatusTuple; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNFireOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + + if (transportResponse.Error == null) { + string responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple("", errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List result = ProcessJsonResponse(requestState, json); + + if (result != null && result.Count >= 3) { + int publishStatus; + _ = int.TryParse(result[0].ToString(), out publishStatus); + if (publishStatus == 1) { + List resultList = ProcessJsonResponse(requestState, json); + if (resultList != null && resultList.Count > 0) { + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNPublishResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNFireOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + + private RequestParameter CreateRequestParameter() + { + List urlSegments = new List + { + "publish", + config.PublishKey?? "", + config.SubscribeKey??"", + "0", + channelName, + "0" + }; + if (!httpPost) { + urlSegments.Add(PrepareContent(this.publishContent)); + } + Dictionary requestQueryStringParams = new Dictionary(); + + if (userMetadata != null) { + string jsonMetaData = jsonLibrary.SerializeToJsonString(userMetadata); + requestQueryStringParams.Add("meta", UriUtil.EncodeUriComponent(jsonMetaData, PNOperationType.PNPublishOperation, false, false, false)); + } + requestQueryStringParams.Add("norep", "true"); + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNPublishOperation, false, false, false)); + } + } + } + var requestParam = new RequestParameter() { + RequestType = httpPost ? Constants.POST : Constants.GET, + PathSegment = urlSegments, + Query = requestQueryStringParams + }; + if (httpPost) { + string postMessage = PrepareContent(publishContent); + requestParam.BodyContentString = postMessage; + } + return requestParam; + } + private string PrepareContent(object originalMessage) + { + string message = jsonLibrary.SerializeToJsonString(originalMessage); + if (config.CryptoModule != null || config.CipherKey.Length > 0) { + config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, config.UseRandomInitializationVector, pubnubLog), null); + string encryptMessage = config.CryptoModule.Encrypt(message); + message = jsonLibrary.SerializeToJsonString(encryptMessage); + } + return message; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/GetMessageActionsOperation.cs b/src/Api/PubnubApi/EndPoint/PubSub/GetMessageActionsOperation.cs index 163c30bf1..ff502caf7 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/GetMessageActionsOperation.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/GetMessageActionsOperation.cs @@ -1,241 +1,255 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class GetMessageActionsOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string messageActionChannelName = ""; - private long startTT = -1; - private long endTT = -1; - private int limitRecords = -1; - private PNCallback savedCallback; - private Dictionary queryParam; - - public GetMessageActionsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - - public GetMessageActionsOperation Channel(string channelName) - { - messageActionChannelName = channelName; - return this; - } - - public GetMessageActionsOperation Start(long startTimetoken) - { - startTT = startTimetoken; - return this; - } - - public GetMessageActionsOperation End(long endTimetoken) - { - endTT = endTimetoken; - return this; - } - - public GetMessageActionsOperation Limit(int numberOfRecords) - { - limitRecords = numberOfRecords; - return this; - } - - public GetMessageActionsOperation QueryParam(Dictionary customQueryParam) - { - queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) - { - throw new MissingMemberException("subscribe key is required"); - } - - if (callback == null) - { - throw new ArgumentException("Missing userCallback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetMessageActions(this.messageActionChannelName, this.startTT, this.endTT, this.limitRecords, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetMessageActions(this.messageActionChannelName, this.startTT, this.endTT, this.limitRecords, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) - { - throw new MissingMemberException("subscribe key is required"); - } - - return await GetMessageActions(this.messageActionChannelName, this.startTT, this.endTT, this.limitRecords, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetMessageActions(this.messageActionChannelName, this.startTT, this.endTT, this.limitRecords, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetMessageActions(this.messageActionChannelName, this.startTT, this.endTT, this.limitRecords, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void GetMessageActions(string channel, long start, long end, int limit, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); - callback.OnResponse(null, status); - return; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); - callback.OnResponse(null, status); - return; - } - - if (callback == null) - { - return; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetMessageActionsRequest("GET", "", channel, start, end, limit, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNGetMessageActionsOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - - ProcessResponseCallbacks(result, requestState); - } - - CleanUp(); - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> GetMessageActions(string channel, long start, long end, int limit, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); - ret.Status = status; - return ret; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); - ret.Status = status; - return ret; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetMessageActionsRequest("GET", "", channel, start, end, limit, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNGetMessageActionsOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNGetMessageActionsResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private void CleanUp() - { - this.savedCallback = null; - } - } + public class GetMessageActionsOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string messageActionChannelName = ""; + private long startTimetoken = -1; + private long endTimetoken = -1; + private int limit = -1; + private PNCallback savedCallback; + private Dictionary queryParam; + + public GetMessageActionsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + + public GetMessageActionsOperation Channel(string channelName) + { + messageActionChannelName = channelName; + return this; + } + + public GetMessageActionsOperation Start(long startTimetoken) + { + this.startTimetoken = startTimetoken; + return this; + } + + public GetMessageActionsOperation End(long endTimetoken) + { + this.endTimetoken = endTimetoken; + return this; + } + + public GetMessageActionsOperation Limit(int numberOfRecords) + { + limit = numberOfRecords; + return this; + } + + public GetMessageActionsOperation QueryParam(Dictionary customQueryParam) + { + queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) { + throw new MissingMemberException("subscribe key is required"); + } + + if (callback == null) { + throw new ArgumentException("Missing userCallback"); + } + + GetMessageActions(this.messageActionChannelName, this.startTimetoken, this.endTimetoken, this.limit, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) { + throw new MissingMemberException("subscribe key is required"); + } + + return await GetMessageActions(this.messageActionChannelName, this.startTimetoken, this.endTimetoken, this.limit, this.queryParam); + } + + internal void Retry() + { + GetMessageActions(this.messageActionChannelName, this.startTimetoken, this.endTimetoken, this.limit, this.queryParam, savedCallback); + } + + private void GetMessageActions(string channel, long start, long end, int limit, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(messageActionChannelName) || string.IsNullOrEmpty(messageActionChannelName.Trim())) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); + callback.OnResponse(null, status); + return; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); + callback.OnResponse(null, status); + return; + } + + if (callback == null) { + return; + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { messageActionChannelName }; + requestState.ResponseType = PNOperationType.PNGetMessageActionsOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + string responseString = string.Empty; + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetMessageActionsOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + if (t.Result.Error == null) { + responseString = Encoding.UTF8.GetString(t.Result.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + ProcessResponseCallbacks(null, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishOperation, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNGetMessageActionsResult), status); + } + }); + CleanUp(); + } + + private async Task> GetMessageActions(string channel, long start, long end, int limit, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); + returnValue.Status = status; + return returnValue; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); + returnValue.Status = status; + return returnValue; + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNGetMessageActionsOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNGetMessageActionsOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + string responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNGetMessageActionsResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNGetMessageActionsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private void CleanUp() + { + this.savedCallback = null; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "message-actions", + config.SubscribeKey, + "channel", + messageActionChannelName + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (startTimetoken >= 0) { + requestQueryStringParams.Add("start", startTimetoken.ToString(CultureInfo.InvariantCulture)); + } + if (endTimetoken >= 0) { + requestQueryStringParams.Add("end", endTimetoken.ToString(CultureInfo.InvariantCulture)); + } + if (limit >= 0) { + requestQueryStringParams.Add("limit", limit.ToString(CultureInfo.InvariantCulture)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNGetMessageActionsOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/ListenerManager.cs b/src/Api/PubnubApi/EndPoint/PubSub/ListenerManager.cs index f31dfcf5e..34ba64eb5 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/ListenerManager.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/ListenerManager.cs @@ -16,7 +16,7 @@ public class ListenerManager : PubnubCoreBase private readonly PNConfiguration pubnubConfig; private readonly IPubnubLog pubnubLog; - public ListenerManager(PNConfiguration config, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(config, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public ListenerManager(PNConfiguration config, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(config, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { this.pubnubConfig = config; this.pubnubLog = log; diff --git a/src/Api/PubnubApi/EndPoint/PubSub/PublishOperation.cs b/src/Api/PubnubApi/EndPoint/PubSub/PublishOperation.cs index de3e175f1..11be3ed3d 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/PublishOperation.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/PublishOperation.cs @@ -1,410 +1,350 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; using System.Threading; using System.Net; using PubnubApi.Security.Crypto.Cryptors; using PubnubApi.Security.Crypto; -#if !NET35 && !NET40 +using System.Globalization; using System.Collections.Concurrent; -#endif +using System.Text; namespace PubnubApi.EndPoint { - public class PublishOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private object msg; - private string channelName = ""; - private bool storeInHistory = true; - private bool httpPost; - private Dictionary userMetadata; - private int ttl = -1; - private PNCallback savedCallback; - private bool syncRequest; - private Dictionary queryParam; - - public PublishOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - - public PublishOperation Message(object message) - { - this.msg = message; - return this; - } - - public PublishOperation Channel(string channelName) - { - this.channelName = channelName; - return this; - } - - public PublishOperation ShouldStore(bool store) - { - this.storeInHistory = store; - return this; - } - - public PublishOperation Meta(Dictionary metadata) - { - this.userMetadata = metadata; - return this; - } - - public PublishOperation UsePOST(bool post) - { - this.httpPost = post; - return this; - } - - /// - /// tttl in hours - /// - /// - /// - public PublishOperation Ttl(int ttl) - { - this.ttl = ttl; - return this; - } - - public PublishOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(channelName.Trim()) || this.msg == null) - { - throw new ArgumentException("Missing Channel or Message"); - } - - if (config == null || string.IsNullOrEmpty(config.PublishKey) || config.PublishKey.Trim().Length <= 0) - { - throw new MissingMemberException("publish key is required"); - } - - if (callback == null) - { - throw new ArgumentException("Missing userCallback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - syncRequest = false; - this.savedCallback = callback; - Publish(this.channelName, this.msg, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - syncRequest = false; - this.savedCallback = callback; - Publish(this.channelName, this.msg, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - syncRequest = false; - return await Publish(this.channelName, this.msg, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam).ConfigureAwait(false); - } - - public PNPublishResult Sync() - { - if (this.msg == null) - { - throw new ArgumentException("message cannot be null"); - } - - if (config == null || string.IsNullOrEmpty(config.PublishKey) || config.PublishKey.Trim().Length <= 0) - { - throw new MissingMemberException("publish key is required"); - } - - System.Threading.ManualResetEvent syncEvent = new System.Threading.ManualResetEvent(false); - Task task = Task.Factory.StartNew(() => - { - syncRequest = true; - syncEvent = new System.Threading.ManualResetEvent(false); - Publish(this.channelName, this.msg, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam, new PNPublishResultExt((r, s) => { SyncResult = r; syncEvent.Set(); })); - syncEvent.WaitOne(config.NonSubscribeRequestTimeout * 1000); - - return SyncResult; - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default); - return task.Result; - } - - private static PNPublishResult SyncResult { get; set; } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - if (!syncRequest) - { - Publish(this.channelName, this.msg, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam, savedCallback); - } - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - if (!syncRequest) - { - Publish(this.channelName, this.msg, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam, savedCallback); - } - }) - { IsBackground = true }.Start(); -#endif - } - - internal void Publish(string channel, object message, bool storeInHistory, int ttl, Dictionary metaData, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")); - callback.OnResponse(null, status); - return; - } - - if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Invalid publish key", new MissingMemberException("Invalid publish key")); - callback.OnResponse(null, status); - return; - } - - if (callback == null) - { - return; - } - - RequestState requestState = new RequestState(); - try - { - string requestMethodName = (this.httpPost) ? "POST" : "GET"; - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildPublishRequest(requestMethodName, "", channel, message, storeInHistory, ttl, metaData, null, externalQueryParam); - - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNPublishOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - string json = ""; - - if (this.httpPost) - { - requestState.UsePostMethod = true; - string postMessage = JsonEncodePublishMsg(message); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - UrlProcessRequest(request, requestState, false, postData).ContinueWith(r => - { - json = r.Result.Item1; - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - else - { - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - json = r.Result.Item1; - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - - if (result != null && result.Count >= 3) - { - int publishStatus; - var _ = Int32.TryParse(result[0].ToString(), out publishStatus); - if (publishStatus == 1) - { - ProcessResponseCallbacks(result, requestState); - } - else - { - PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); - PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishOperation, category, requestState, 400, new PNException(json)); - if (requestState.PubnubCallback != null) - { - requestState.PubnubCallback.OnResponse(default(PNPublishResult), status); - } - } - } - else - { - ProcessResponseCallbacks(result, requestState); - } - } - - CleanUp(); - } - catch (Exception ex) - { - int statusCode = PNStatusCodeHelper.GetHttpStatusCode(ex.ToString()); - PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, ex.ToString()); - PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishOperation, category, requestState, statusCode, new PNException(ex.ToString())); - if (requestState.PubnubCallback != null) - { - requestState.PubnubCallback.OnResponse(default(PNPublishResult), status); - } - - } - } - - internal async Task> Publish(string channel, object message, bool storeInHistory, int ttl, Dictionary metaData, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) - { - PNStatus errStatus = new PNStatus(); - errStatus.Error = true; - errStatus.ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")); - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) - { - PNStatus errStatus = new PNStatus(); - errStatus.Error = true; - errStatus.ErrorData = new PNErrorData("Invalid publish key", new MissingMemberException("Invalid publish key")); - ret.Status = errStatus; - return ret; - } - - RequestState requestState = new RequestState(); - try - { - string requestMethodName = (this.httpPost) ? "POST" : "GET"; - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildPublishRequest(requestMethodName, "", channel, message, storeInHistory, ttl, metaData, null, externalQueryParam); - - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNPublishOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple; - - if (this.httpPost) - { - requestState.UsePostMethod = true; - string postMessage = JsonEncodePublishMsg(message); - byte[] postData = Encoding.UTF8.GetBytes(postMessage); - JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false, postData).ConfigureAwait(false); - } - else - { - JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - } - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - - if (result != null && result.Count >= 3) - { - int publishStatus; - var _ = Int32.TryParse(result[0].ToString(), out publishStatus); - if (publishStatus == 1) - { - List resultList = ProcessJsonResponse(requestState, json); - if (resultList != null && resultList.Count > 0) - { - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNPublishResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - } - } - } - } - catch (Exception ex) - { - int statusCode = PNStatusCodeHelper.GetHttpStatusCode(ex.ToString()); - PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, ex.ToString()); - PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishOperation, category, requestState, statusCode, new PNException(ex.ToString())); - ret.Status = status; - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - - private string JsonEncodePublishMsg(object originalMessage) - { - string message = jsonLibrary.SerializeToJsonString(originalMessage); - if (config.CryptoModule != null || config.CipherKey.Length > 0) - { - config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, config.UseRandomInitializationVector, pubnubLog), null); - string encryptMessage = config.CryptoModule.Encrypt(message); - message = jsonLibrary.SerializeToJsonString(encryptMessage); - } - return message; - } - - private void CleanUp() - { - this.savedCallback = null; - } - } + public class PublishOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private object publishContent; + private string channelName = ""; + private bool storeInHistory = true; + private bool httpPost; + private Dictionary userMetadata; + private int ttl = -1; + private PNCallback savedCallback; + private bool syncRequest; + private Dictionary queryParam; + + public PublishOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public PublishOperation Message(object message) + { + this.publishContent = message; + return this; + } + + public PublishOperation Channel(string channelName) + { + this.channelName = channelName; + return this; + } + + public PublishOperation ShouldStore(bool store) + { + this.storeInHistory = store; + return this; + } + + public PublishOperation Meta(Dictionary metadata) + { + this.userMetadata = metadata; + return this; + } + + public PublishOperation UsePOST(bool post) + { + this.httpPost = post; + return this; + } + + /// + /// ttl in hours + /// + /// + /// + public PublishOperation Ttl(int ttl) + { + this.ttl = ttl; + return this; + } + + public PublishOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(channelName.Trim()) || this.publishContent == null) { + throw new ArgumentException("Missing Channel or Message"); + } + + if (config == null || string.IsNullOrEmpty(config.PublishKey) || config.PublishKey.Trim().Length <= 0) { + throw new MissingMemberException("publish key is required"); + } + + if (callback == null) { + throw new ArgumentException("Missing userCallback"); + } + this.savedCallback = callback; + Publish(channelName, this.publishContent, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + syncRequest = false; + return await Publish(this.channelName, this.publishContent, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam).ConfigureAwait(false); + } + + public PNPublishResult Sync() + { + if (this.publishContent == null) { + throw new ArgumentException("message cannot be null"); + } + + if (config == null || string.IsNullOrEmpty(config.PublishKey) || config.PublishKey.Trim().Length <= 0) { + throw new MissingMemberException("publish key is required"); + } + + ManualResetEvent syncEvent = new System.Threading.ManualResetEvent(false); + Task task = Task.Factory.StartNew(() => { + syncRequest = true; + syncEvent = new System.Threading.ManualResetEvent(false); + Publish(this.channelName, this.publishContent, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam, new PNPublishResultExt((r, s) => { SyncResult = r; syncEvent.Set(); })); + syncEvent.WaitOne(config.NonSubscribeRequestTimeout * 1000); + + return SyncResult; + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default); + return task.Result; + } + + private static PNPublishResult SyncResult { get; set; } + + internal void Retry() + { + Publish(this.channelName, this.publishContent, this.storeInHistory, this.ttl, this.userMetadata, this.queryParam, savedCallback); + } + + internal void Publish(string channel, object message, bool storeInHistory, int ttl, Dictionary userMetadata, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")); + callback.OnResponse(null, status); + return; + } + + if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Invalid publish key", new MissingMemberException("Invalid publish key")); + callback.OnResponse(null, status); + return; + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNPublishOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameters = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameters, operationType: PNOperationType.PNPublishOperation); + + PubnubInstance.transportMiddleware.Send(transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + if (result != null && result.Count >= 3) { + int publishStatus; + _ = int.TryParse(result[0].ToString(), out publishStatus); + if (publishStatus == 1) { + ProcessResponseCallbacks(result, requestState); + } else { + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishOperation, category, requestState, 400, new PNException(responseString)); + if (requestState.PubnubCallback != null) { + requestState.PubnubCallback.OnResponse(default, status); + } + } + } else { + ProcessResponseCallbacks(result, requestState); + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + CleanUp(); + } + + internal async Task> Publish(string channel, object message, bool storeInHistory, int ttl, Dictionary metaData, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) { + PNStatus errStatus = new PNStatus(); + errStatus.Error = true; + errStatus.ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")); + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) { + PNStatus errStatus = new PNStatus(); + errStatus.Error = true; + errStatus.ErrorData = new PNErrorData("Invalid publish key", new MissingMemberException("Invalid publish key")); + returnValue.Status = errStatus; + return returnValue; + } + RequestState requestState = new RequestState(); + Tuple JsonAndStatusTuple; + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNPublishOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNPublishOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest); + if (transportResponse.Error == null) { + string responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple("", errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + + if (!string.IsNullOrEmpty(json)) { + List result = ProcessJsonResponse(requestState, json); + + if (result != null && result.Count >= 3) { + int publishStatus; + _ = int.TryParse(result[0].ToString(), out publishStatus); + if (publishStatus == 1) { + List resultList = ProcessJsonResponse(requestState, json); + if (resultList != null && resultList.Count > 0) { + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNPublishResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + + private string PrepareContent(object originalMessage) + { + string message = jsonLibrary.SerializeToJsonString(originalMessage); + if (config.CryptoModule != null || config.CipherKey.Length > 0) { + config.CryptoModule ??= new CryptoModule(new LegacyCryptor(config.CipherKey, config.UseRandomInitializationVector, pubnubLog), null); + string encryptMessage = config.CryptoModule.Encrypt(message); + message = jsonLibrary.SerializeToJsonString(encryptMessage); + } + return message; + } + + private RequestParameter CreateRequestParameter() + { + List urlSegments = new List + { + "publish", + config.PublishKey?? "", + config.SubscribeKey??"", + "0", + channelName, + "0" + }; + if (!httpPost) { + urlSegments.Add(PrepareContent(this.publishContent)); + } + Dictionary requestQueryStringParams = new Dictionary(); + + if (userMetadata != null) { + string jsonMetaData = jsonLibrary.SerializeToJsonString(userMetadata); + requestQueryStringParams.Add("meta", UriUtil.EncodeUriComponent(jsonMetaData, PNOperationType.PNPublishOperation, false, false, false)); + } + + if (storeInHistory && ttl >= 0) { + requestQueryStringParams.Add("tt1", ttl.ToString(CultureInfo.InvariantCulture)); + } + + if (!storeInHistory) { + requestQueryStringParams.Add("store", "0"); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNPublishOperation, false, false, false)); + } + } + } + + var requestParam = new RequestParameter() { + RequestType = httpPost ? Constants.POST : Constants.GET, + PathSegment = urlSegments, + Query = requestQueryStringParams + }; + if (httpPost) { + string postMessage = PrepareContent(publishContent); + requestParam.BodyContentString = postMessage; + } + return requestParam; + } + + private void CleanUp() + { + savedCallback = null; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/RemoveMessageActionOperation.cs b/src/Api/PubnubApi/EndPoint/PubSub/RemoveMessageActionOperation.cs index e7da08f46..e9be8087c 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/RemoveMessageActionOperation.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/RemoveMessageActionOperation.cs @@ -1,251 +1,248 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Globalization; namespace PubnubApi.EndPoint { - public class RemoveMessageActionOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private string msgActionChannelName = ""; - private long messageTimetoken; - private long actionTimetoken; - private string msgActionUuid; - private PNCallback savedCallback; - private Dictionary queryParam; - - public RemoveMessageActionOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - - public RemoveMessageActionOperation Channel(string channelName) - { - msgActionChannelName = channelName; - return this; - } - - /// - /// The publish timetoken of a parent message - /// - /// - /// - public RemoveMessageActionOperation MessageTimetoken(long timetoken) - { - messageTimetoken = timetoken; - return this; - } - - /// - /// The publish timetoken of the action - /// - /// - /// - public RemoveMessageActionOperation ActionTimetoken(long timetoken) - { - actionTimetoken = timetoken; - return this; - } - - public RemoveMessageActionOperation Uuid(string messageActionUuid) - { - msgActionUuid = messageActionUuid; - return this; - } - - public RemoveMessageActionOperation QueryParam(Dictionary customQueryParam) - { - queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) - { - throw new MissingMemberException("subscribe key is required"); - } - - if (callback == null) - { - throw new ArgumentException("Missing userCallback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - RemoveMessageAction(this.msgActionChannelName, this.messageTimetoken, this.actionTimetoken, this.msgActionUuid, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - RemoveMessageAction(this.msgActionChannelName, this.messageTimetoken, this.actionTimetoken, this.msgActionUuid, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) - { - throw new MissingMemberException("subscribe key is required"); - } - - return await RemoveMessageAction(this.msgActionChannelName, this.messageTimetoken, this.actionTimetoken, this.msgActionUuid, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - RemoveMessageAction(this.msgActionChannelName, this.messageTimetoken, this.actionTimetoken, this.msgActionUuid, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - RemoveMessageAction(this.msgActionChannelName, this.messageTimetoken, this.actionTimetoken, this.msgActionUuid, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void RemoveMessageAction(string channel, long messageTimetoken, long actionTimetoken, string messageActionUuid, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); - callback.OnResponse(null, status); - return; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); - callback.OnResponse(null, status); - return; - } - - if (callback == null) - { - return; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildRemoveMessageActionRequest("DELETE", "", channel, messageTimetoken, actionTimetoken, messageActionUuid, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNRemoveMessageActionOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - - ProcessResponseCallbacks(result, requestState); - } - - CleanUp(); - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> RemoveMessageAction(string channel, long messageTimetoken, long actionTimetoken, string messageActionUuid, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); - ret.Status = status; - return ret; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus status = new PNStatus(); - status.Error = true; - status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); - ret.Status = status; - return ret; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildRemoveMessageActionRequest("DELETE", "", channel, messageTimetoken, actionTimetoken, messageActionUuid, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNRemoveMessageActionOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNRemoveMessageActionResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - private void CleanUp() - { - this.savedCallback = null; - } - } + public class RemoveMessageActionOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private string channelName = ""; + private long messageTimetoken; + private long actionTimetoken; + private string actionUuid; + private PNCallback savedCallback; + private Dictionary queryParam; + + public RemoveMessageActionOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + PubnubInstance = instance; + } + + public RemoveMessageActionOperation Channel(string channelName) + { + this.channelName = channelName; + return this; + } + + /// + /// The publish timetoken of a parent message + /// + /// + /// + public RemoveMessageActionOperation MessageTimetoken(long timetoken) + { + messageTimetoken = timetoken; + return this; + } + + /// + /// The publish timetoken of the action + /// + /// + /// + public RemoveMessageActionOperation ActionTimetoken(long timetoken) + { + actionTimetoken = timetoken; + return this; + } + + public RemoveMessageActionOperation Uuid(string messageActionUuid) + { + actionUuid = messageActionUuid; + return this; + } + + public RemoveMessageActionOperation QueryParam(Dictionary customQueryParam) + { + queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) { + throw new MissingMemberException("subscribe key is required"); + } + + if (callback == null) { + throw new ArgumentException("Missing userCallback"); + } + RemoveMessageAction(this.channelName, this.messageTimetoken, this.actionTimetoken, this.actionUuid, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + if (config == null || string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length <= 0) { + throw new MissingMemberException("subscribe key is required"); + } + + return await RemoveMessageAction(this.channelName, this.messageTimetoken, this.actionTimetoken, this.actionUuid, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + RemoveMessageAction(this.channelName, this.messageTimetoken, this.actionTimetoken, this.actionUuid, this.queryParam, savedCallback); + } + + private void RemoveMessageAction(string channel, long messageTimetoken, long actionTimetoken, string messageActionUuid, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); + callback.OnResponse(null, status); + return; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); + callback.OnResponse(null, status); + return; + } + + if (callback == null) { + return; + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNRemoveMessageActionOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveMessageActionOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + if (t.Result.Error == null) { + var responseString = Encoding.UTF8.GetString(t.Result.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveMessageActionOperation, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNRemoveMessageActionResult), status); + } + CleanUp(); + }); + } + + private async Task> RemoveMessageAction(string channel, long messageTimetoken, long actionTimetoken, string messageActionUuid, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Missing Channel or MessageAction", new ArgumentException("Missing Channel or MessageAction")); + returnValue.Status = status; + return returnValue; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus status = new PNStatus(); + status.Error = true; + status.ErrorData = new PNErrorData("Invalid subscribe key", new MissingMemberException("Invalid subscribe key")); + returnValue.Status = status; + return returnValue; + } + + RequestState requestState = new RequestState(); + Tuple JsonAndStatusTuple; + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNRemoveMessageActionOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNRemoveMessageActionOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + + if (transportResponse.Error == null) { + string responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple("", errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNRemoveMessageActionResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNRemoveMessageActionOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private void CleanUp() + { + this.savedCallback = null; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "v1", + "message-actions", + config.SubscribeKey, + "channel", + channelName, + "message", + messageTimetoken.ToString(CultureInfo.InvariantCulture), + "action", + actionTimetoken.ToString(CultureInfo.InvariantCulture) + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (actionUuid != null) { + requestQueryStringParams.Add("uuid", UriUtil.EncodeUriComponent(actionUuid, PNOperationType.PNRemoveMessageActionOperation, false, false, false)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNRemoveMessageActionOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.DELETE, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/SignalOperation.cs b/src/Api/PubnubApi/EndPoint/PubSub/SignalOperation.cs index ba2610a85..7fd2c9b42 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/SignalOperation.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/SignalOperation.cs @@ -1,283 +1,219 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; -using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class SignalOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private object msg; - private string channelName = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public SignalOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - if (instance != null) - { - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } - - public SignalOperation Message(object message) - { - msg = message; - return this; - } - - public SignalOperation Channel(string channelName) - { - this.channelName = channelName; - return this; - } - - public SignalOperation QueryParam(Dictionary customQueryParam) - { - queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(channelName.Trim()) || this.msg == null) - { - throw new ArgumentException("Missing Channel or Message"); - } - - if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) - { - throw new MissingMemberException("Invalid publish key"); - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - throw new MissingMemberException("Invalid subscribe key"); - } - - if (callback == null) - { - throw new ArgumentException("Missing userCallback"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - try - { - Signal(this.channelName, this.msg, null, this.queryParam, callback); - } - catch(Exception ex) - { - PNStatus unexpectedExceptionStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Unexpected exception", ex) }; - callback.OnResponse(null, unexpectedExceptionStatus); - } - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - try - { - Signal(this.channelName, this.msg, null, this.queryParam, callback); - } - catch(Exception ex) - { - PNStatus unexpectedExceptionStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Unexpected exception", ex) }; - callback.OnResponse(null, unexpectedExceptionStatus); - } - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await Signal(this.channelName, this.msg, null, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - Signal(this.channelName, this.msg, null, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - Signal(this.channelName, this.msg, null, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - private void Signal(string channel, object message, Dictionary metaData, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) - { - PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message"))}; - callback.OnResponse(null, status); - return; - } - - if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) - { - PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid publish key", new ArgumentException("Invalid publish key")) }; - callback.OnResponse(null, status); - return; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid subscribe key", new ArgumentException("Invalid subscribe key")) }; - callback.OnResponse(null, status); - return; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildSignalRequest("GET", "", channel, message, metaData, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNSignalOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - - if (result != null && result.Count >= 3) - { - int signalStatus; - var _ = Int32.TryParse(result[0].ToString(), out signalStatus); - if (signalStatus == 1) - { - ProcessResponseCallbacks(result, requestState); - } - else - { - PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); - PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSignalOperation, category, requestState, 400, new PNException(json)); - if (requestState.PubnubCallback != null) - { - requestState.PubnubCallback.OnResponse(default(PNPublishResult), status); - } - } - } - else - { - ProcessResponseCallbacks(result, requestState); - } - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - private async Task> Signal(string channel, object message, Dictionary metaData, Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")) }; - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid publish key", new ArgumentException("Invalid publish key")) }; - ret.Status = errStatus; - return ret; - } - - if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) - { - PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid subscribe key", new ArgumentException("Invalid subscribe key")) }; - ret.Status = errStatus; - return ret; - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildSignalRequest("GET", "", channel, message, metaData, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNSignalOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - if (result != null && result.Count >= 3) - { - int publishStatus; - var _ = Int32.TryParse(result[0].ToString(), out publishStatus); - if (publishStatus == 1) - { - List resultList = ProcessJsonResponse(requestState, json); - if (resultList != null && resultList.Count > 0) - { - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNPublishResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - else - { - PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); - PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSignalOperation, category, requestState, 400, new PNException(json)); - ret.Status = status; - ret.Result = default(PNPublishResult); - } - } - } - } - - return ret; - } - } + public class SignalOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private object signalMessage; + private string channelName = ""; + private PNCallback savedCallback; + private Dictionary queryParam; + + public SignalOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public SignalOperation Message(object message) + { + signalMessage = message; + return this; + } + + public SignalOperation Channel(string channelName) + { + this.channelName = channelName; + return this; + } + + public SignalOperation QueryParam(Dictionary customQueryParam) + { + queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(channelName.Trim()) || this.signalMessage == null) { + throw new ArgumentException("Missing Channel or Message"); + } + + if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) { + throw new MissingMemberException("Invalid publish key"); + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + throw new MissingMemberException("Invalid subscribe key"); + } + + if (callback == null) { + throw new ArgumentException("Missing userCallback"); + } + Signal(this.channelName, this.signalMessage, null, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await Signal(this.channelName, this.signalMessage, null, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + Signal(this.channelName, this.signalMessage, null, this.queryParam, savedCallback); + } + + private void Signal(string channel, object message, Dictionary metaData, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) { + PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")) }; + callback.OnResponse(null, status); + return; + } + + if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) { + PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid publish key", new ArgumentException("Invalid publish key")) }; + callback.OnResponse(null, status); + return; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus status = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid subscribe key", new ArgumentException("Invalid subscribe key")) }; + callback.OnResponse(null, status); + return; + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNSignalOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameters = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameters, operationType: PNOperationType.PNSignalOperation); + PubnubInstance.transportMiddleware.Send(transportRequest).ContinueWith(t => { + if (t.Result.Error == null) { + var responseString = Encoding.UTF8.GetString(t.Result.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + + if (result != null && result.Count >= 3) { + int signalStatus; + var _ = Int32.TryParse(result[0].ToString(), out signalStatus); + if (signalStatus == 1) { + ProcessResponseCallbacks(result, requestState); + } else { + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSignalOperation, category, requestState, 400, new PNException(responseString)); + requestState.PubnubCallback.OnResponse(default(PNPublishResult), status); + } + } else { + ProcessResponseCallbacks(result, requestState); + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(t.Result.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, t.Result.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSignalOperation, category, requestState, statusCode, new PNException(t.Result.Error.Message, t.Result.Error)); + requestState.PubnubCallback.OnResponse(default(PNPublishResult), status); + } + }); + } + + private async Task> Signal(string channel, object message, Dictionary metaData, Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Missing Channel or Message", new ArgumentException("Missing Channel or Message")) }; + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(config.PublishKey) || string.IsNullOrEmpty(config.PublishKey.Trim()) || config.PublishKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid publish key", new ArgumentException("Invalid publish key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + if (string.IsNullOrEmpty(config.SubscribeKey) || string.IsNullOrEmpty(config.SubscribeKey.Trim()) || config.SubscribeKey.Length <= 0) { + PNStatus errStatus = new PNStatus { Error = true, ErrorData = new PNErrorData("Invalid subscribe key", new ArgumentException("Invalid subscribe key")) }; + returnValue.Status = errStatus; + return returnValue; + } + + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNSignalOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNSignalOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + string responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + if (result != null && result.Count >= 3) { + int publishStatus; + var _ = Int32.TryParse(result[0].ToString(), out publishStatus); + if (publishStatus == 1) { + List resultList = ProcessJsonResponse(requestState, responseString); + if (resultList != null && resultList.Count > 0) { + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNPublishResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } else { + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(400, result[1].ToString()); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNSignalOperation, category, requestState, 400, new PNException(responseString)); + returnValue.Status = status; + returnValue.Result = default; + } + } + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNPublishOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List urlSegments = new List() + { + "signal", + config.PublishKey, + config.SubscribeKey, + "0", + this.channelName, + "0", + jsonLibrary.SerializeToJsonString(this.signalMessage) + }; + + var requestParemeter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = urlSegments + }; + + return requestParemeter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/SubscribeEndpoint.cs b/src/Api/PubnubApi/EndPoint/PubSub/SubscribeEndpoint.cs index 4142c946d..5e13ca538 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/SubscribeEndpoint.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/SubscribeEndpoint.cs @@ -5,7 +5,6 @@ using PubnubApi.EventEngine.Subscribe; using PubnubApi.EventEngine.Core; using PubnubApi.EventEngine.Subscribe.States; -using PubnubApi.EventEngine.Subscribe.Common; using PubnubApi.EventEngine.Common; namespace PubnubApi.EndPoint @@ -16,7 +15,6 @@ public class SubscribeEndpoint: ISubscribeOperation private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; private readonly EndPoint.TokenManager pubnubTokenMgr; private List subscribeChannelNames = new List(); @@ -30,20 +28,20 @@ public class SubscribeEndpoint: ISubscribeOperation private SubscribeEventEngineFactory subscribeEventEngineFactory; private PresenceOperation presenceOperation; private string instanceId { get; set; } + public EventEmitter EventEmitter { get; set; } public List SubscribeListenerList { get; set; } = new List(); - public SubscribeEndpoint(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager,SubscribeEventEngineFactory subscribeEventEngineFactory, PresenceOperation presenceOperation , string instanceId, Pubnub instance) + public SubscribeEndpoint(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager,SubscribeEventEngineFactory subscribeEventEngineFactory, PresenceOperation presenceOperation , string instanceId, Pubnub instance) { PubnubInstance = instance; config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; pubnubTokenMgr = tokenManager; this.subscribeEventEngineFactory = subscribeEventEngineFactory; this.presenceOperation = presenceOperation; @@ -125,16 +123,15 @@ private void Subscribe(string[] channels, string[] channelGroups, SubscriptionCu if (subscribeEventEngineFactory.HasEventEngine(instanceId)) { subscribeEventEngine = subscribeEventEngineFactory.GetEventEngine(instanceId); } else { - var subscribeManager = new SubscribeManager2(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, pubnubTokenMgr, PubnubInstance); - var eventEmitter = new EventEmitter(config, SubscribeListenerList, jsonLibrary, pubnubTokenMgr, pubnubLog, PubnubInstance); - subscribeEventEngine = subscribeEventEngineFactory.InitializeEventEngine(instanceId, PubnubInstance, config, subscribeManager, eventEmitter, jsonLibrary, StatusEmitter); + var subscribeManager = new SubscribeManager2(config, jsonLibrary, unit, pubnubLog, pubnubTokenMgr, PubnubInstance); + subscribeEventEngine = subscribeEventEngineFactory.InitializeEventEngine(instanceId, PubnubInstance, config, subscribeManager, this.EventEmitter, jsonLibrary, StatusEmitter); subscribeEventEngine.OnStateTransition += SubscribeEventEngine_OnStateTransition; subscribeEventEngine.OnEventQueued += SubscribeEventEngine_OnEventQueued; subscribeEventEngine.OnEffectDispatch += SubscribeEventEngine_OnEffectDispatch; } subscribeEventEngine.Subscribe(channels, channelGroups, cursor); if (this.presenceOperation != null) { - presenceOperation.Start(channels?.Where(c => !c.EndsWith("-pnpres")).ToArray(), channelGroups?.Where(cg => !cg.EndsWith("-pnpres")).ToArray()); + presenceOperation.Start(channels?.Where(c => !c.EndsWith(Constants.Pnpres)).ToArray(), channelGroups?.Where(cg => !cg.EndsWith(Constants.Pnpres)).ToArray()); } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager.cs b/src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager.cs index 01801cbe9..fd0068105 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager.cs @@ -5,1483 +5,1319 @@ using System.Net; using System.Threading.Tasks; using System.Globalization; -#if !NET35 && !NET40 +using System.Text; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - internal class SubscribeManager : PubnubCoreBase, IDisposable - { - private static ConcurrentDictionary config { get; } = new ConcurrentDictionary(); - private static IJsonPluggableLibrary jsonLibrary; - private static IPubnubUnitTest unit; - private static IPubnubLog pubnubLog; - private static EndPoint.TelemetryManager pubnubTelemetryMgr; - - private static Timer SubscribeHeartbeatCheckTimer; - private Timer multiplexExceptionTimer; - private Dictionary customQueryParam; - - public SubscribeManager(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config.AddOrUpdate(instance.InstanceId, pubnubConfig, (k, o) => pubnubConfig); - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - -#pragma warning disable - internal void MultiChannelUnSubscribeAll(PNOperationType type, Dictionary externalQueryParam) -#pragma warning restore - { - //Retrieve the current channels already subscribed previously and terminate them - string[] currentChannels = (MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe[PubnubInstance.InstanceId] != null) ? new List(MultiChannelSubscribe[PubnubInstance.InstanceId].Keys).ToArray() : null; - string[] currentChannelGroups = (MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe[PubnubInstance.InstanceId] != null) ? new List(MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys).ToArray() : null; - - if (currentChannels != null && currentChannels.Length >= 0) - { - string multiChannelName = (currentChannels.Length > 0) ? string.Join(",", currentChannels.OrderBy(x => x).ToArray()) : ","; - string multiChannelGroupName = (currentChannelGroups.Length > 0) ? string.Join(",", currentChannelGroups.OrderBy(x => x).ToArray()) : ""; - - Task.Factory.StartNew(() => - { - if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(multiChannelName)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Aborting previous subscribe/presence requests having channel(s)={1}; channelgroup(s)={2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - - HttpWebRequest webRequest; - ChannelRequest[PubnubInstance.InstanceId].TryGetValue(multiChannelName, out webRequest); - ChannelRequest[PubnubInstance.InstanceId].TryUpdate(multiChannelName, null, webRequest); - - HttpWebRequest removedRequest; - bool removedChannel = ChannelRequest[PubnubInstance.InstanceId].TryRemove(multiChannelName, out removedRequest); - if (removedChannel) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Success to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelUnSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelUnSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - if (webRequest != null) - { - TerminatePendingWebRequest(webRequest); - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to capture channel(s)={1}; channelgroup(s)={2} from _channelRequest to abort request.", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); - - if (type == PNOperationType.PNUnsubscribeOperation && config.ContainsKey(PubnubInstance.InstanceId) && !config[PubnubInstance.InstanceId].SuppressLeaveEvents) - { - //just fire leave() event to REST API for safeguard - string channelsJsonState = BuildJsonUserState(currentChannels, currentChannelGroups, false); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config[PubnubInstance.InstanceId], jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildMultiChannelLeaveRequest("GET", "", currentChannels, currentChannelGroups, channelsJsonState, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = currentChannels; - requestState.ChannelGroups = currentChannelGroups; - requestState.ResponseType = PNOperationType.Leave; - requestState.Reconnect = false; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - MultiChannelSubscribe[PubnubInstance.InstanceId].Clear(); - MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Clear(); - }); - } - } - - } - - internal void MultiChannelUnSubscribeInit(PNOperationType type, string channel, string channelGroup, Dictionary externalQueryParam) - { - List validChannels = new List(); - List validChannelGroups = new List(); - - try - { - this.customQueryParam = externalQueryParam; - - if (PubnubInstance == null) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, PubnubInstance is null. exiting MultiChannelUnSubscribeInit", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - return; - } - - if (!MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId)) - { - MultiChannelSubscribe.GetOrAdd(PubnubInstance.InstanceId, new ConcurrentDictionary()); - } - if (!MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId)) - { - MultiChannelGroupSubscribe.GetOrAdd(PubnubInstance.InstanceId, new ConcurrentDictionary()); - } - - string[] rawChannels = (channel != null && channel.Trim().Length > 0) ? channel.Split(',') : new string[] { }; - string[] rawChannelGroups = (channelGroup != null && channelGroup.Trim().Length > 0) ? channelGroup.Split(',') : new string[] { }; - - if (rawChannels.Length > 0) - { - for (int index = 0; index < rawChannels.Length; index++) - { - if (rawChannels[index].Trim().Length > 0) - { - string channelName = rawChannels[index].Trim(); - if (string.IsNullOrEmpty(channelName)) - { - continue; - } - - if (config.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe[PubnubInstance.InstanceId] != null && !MultiChannelSubscribe[PubnubInstance.InstanceId].ContainsKey(channelName)) - { - PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(PNOperationType.PNUnsubscribeOperation, PNStatusCategory.PNUnexpectedDisconnectCategory, null, (int)HttpStatusCode.NotFound, null); - if (!status.AffectedChannels.Contains(channelName)) - { - status.AffectedChannels.Add(channelName); - } - Announce(status); - } - else - { - validChannels.Add(channelName); - string presenceChannelName = string.Format(CultureInfo.InvariantCulture, "{0}-pnpres", channelName); - if (MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe[PubnubInstance.InstanceId] != null && MultiChannelSubscribe[PubnubInstance.InstanceId].ContainsKey(presenceChannelName)) - { - validChannels.Add(presenceChannelName); - } - } - } - } - } - - if (rawChannelGroups.Length > 0) - { - for (int index = 0; index < rawChannelGroups.Length; index++) - { - if (rawChannelGroups[index].Trim().Length > 0) - { - string channelGroupName = rawChannelGroups[index].Trim(); - if (string.IsNullOrEmpty(channelGroupName)) - { - continue; - } - - if (config.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe[PubnubInstance.InstanceId] != null && !MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ContainsKey(channelGroupName)) - { - PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(PNOperationType.PNUnsubscribeOperation, PNStatusCategory.PNUnexpectedDisconnectCategory, null, (int)HttpStatusCode.NotFound, null); - if (!status.AffectedChannelGroups.Contains(channelGroupName)) - { - status.AffectedChannelGroups.Add(channelGroupName); - } - Announce(status); - } - else - { - validChannelGroups.Add(channelGroupName); - string presenceChannelGroupName = string.Format(CultureInfo.InvariantCulture, "{0}-pnpres", channelGroupName); - if (MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe[PubnubInstance.InstanceId] != null && MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ContainsKey(presenceChannelGroupName)) - { - validChannelGroups.Add(presenceChannelGroupName); - } - } - } - } - } - - if (validChannels.Count > 0 || validChannelGroups.Count > 0) - { - //Retrieve the current channels already subscribed previously and terminate them - string[] currentChannels = new List(MultiChannelSubscribe[PubnubInstance.InstanceId].Keys).ToArray(); - string[] currentChannelGroups = new List(MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys).ToArray(); - - if (currentChannels != null && currentChannels.Length >= 0) - { - string multiChannelName = (currentChannels.Length > 0) ? string.Join(",", currentChannels.OrderBy(x => x).ToArray()) : ","; - string multiChannelGroupName = (currentChannelGroups.Length > 0) ? string.Join(",", currentChannelGroups.OrderBy(x => x).ToArray()) : ""; - - Task.Factory.StartNew(() => - { - if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(multiChannelName)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Aborting previous subscribe/presence requests having channel(s)={1}; channelgroup(s)={2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - - HttpWebRequest webRequest; - ChannelRequest[PubnubInstance.InstanceId].TryGetValue(multiChannelName, out webRequest); - ChannelRequest[PubnubInstance.InstanceId].TryUpdate(multiChannelName, null, webRequest); - - HttpWebRequest removedRequest; - bool removedChannel = ChannelRequest[PubnubInstance.InstanceId].TryRemove(multiChannelName, out removedRequest); - if (removedChannel) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Success to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelUnSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelUnSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - if (webRequest != null) - { - TerminatePendingWebRequest(webRequest); - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to capture channel(s)={1}; channelgroup(s)={2} from _channelRequest to abort request.", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); - - if (type == PNOperationType.PNUnsubscribeOperation && config.ContainsKey(PubnubInstance.InstanceId)) - { - //just fire leave() event to REST API for safeguard - string channelsJsonState = BuildJsonUserState(validChannels.ToArray(), validChannelGroups.ToArray(), false); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config[PubnubInstance.InstanceId], jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildMultiChannelLeaveRequest("GET", "", validChannels.ToArray(), validChannelGroups.ToArray(), channelsJsonState, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new [] { channel }; - requestState.ChannelGroups = new [] { channelGroup }; - requestState.ResponseType = PNOperationType.Leave; - requestState.Reconnect = false; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => { }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - } - - Dictionary originalMultiChannelSubscribe = null; - Dictionary originalMultiChannelGroupSubscribe = null; - if (PubnubInstance != null && MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId)) - { - originalMultiChannelSubscribe = MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0 ? MultiChannelSubscribe[PubnubInstance.InstanceId].ToDictionary(kvp => kvp.Key, kvp => kvp.Value) : null; - } - if (PubnubInstance != null && MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId)) - { - originalMultiChannelGroupSubscribe = MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0 ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ToDictionary(kvp => kvp.Key, kvp => kvp.Value) : null; - } - - PNStatus successStatus = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(PNOperationType.PNUnsubscribeOperation, PNStatusCategory.PNDisconnectedCategory, null, (int)HttpStatusCode.OK, null); - PNStatus failStatus = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(PNOperationType.PNUnsubscribeOperation, PNStatusCategory.PNDisconnectedCategory, null, (int)HttpStatusCode.NotFound, new PNException("Unsubscribe Error. Please retry unsubscribe operation")); - bool successExist = false; - bool failExist = false; - - //Remove the valid channels from subscribe list for unsubscribe - for (int index = 0; index < validChannels.Count; index++) - { - long timetokenValue; - string channelToBeRemoved = validChannels[index]; - bool unsubscribeStatus = false; - if (PubnubInstance != null && MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId)) - { - unsubscribeStatus = MultiChannelSubscribe[PubnubInstance.InstanceId].TryRemove(channelToBeRemoved, out timetokenValue); - } - if (channelToBeRemoved.Contains("-pnpres")) - { - continue; //Do not send status for -pnpres channels - } - if (unsubscribeStatus) - { - successExist = true; - if (!successStatus.AffectedChannels.Contains(channelToBeRemoved)) - { - successStatus.AffectedChannels.Add(channelToBeRemoved); - } - - base.DeleteLocalChannelUserState(channelToBeRemoved); - } - else - { - failExist = true; - if (!failStatus.AffectedChannels.Contains(channelToBeRemoved)) - { - failStatus.AffectedChannels.Add(channelToBeRemoved); - } - } - } - for (int index = 0; index < validChannelGroups.Count; index++) - { - long timetokenValue; - string channelGroupToBeRemoved = validChannelGroups[index]; - bool unsubscribeStatus = false; - if (PubnubInstance != null && MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId)) - { - unsubscribeStatus = MultiChannelGroupSubscribe[PubnubInstance.InstanceId].TryRemove(channelGroupToBeRemoved, out timetokenValue); - } - if (channelGroupToBeRemoved.Contains("-pnpres")) - { - continue; //Do not send status for -pnpres channel-groups - } - if (unsubscribeStatus) - { - successExist = true; - if (!successStatus.AffectedChannelGroups.Contains(channelGroupToBeRemoved)) - { - successStatus.AffectedChannelGroups.Add(channelGroupToBeRemoved); - } - - base.DeleteLocalChannelGroupUserState(channelGroupToBeRemoved); - } - else - { - failExist = true; - if (!failStatus.AffectedChannelGroups.Contains(channelGroupToBeRemoved)) - { - failStatus.AffectedChannelGroups.Add(channelGroupToBeRemoved); - } - } - } - - if (successExist && PubnubInstance != null) - { - Announce(successStatus); - } - - if (failExist && PubnubInstance != null) - { - Announce(failStatus); - } - - //Get all the channels - string[] channels = new string[] { }; - string[] channelGroups = new string[] { }; - - if (PubnubInstance != null && MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId)) - { - channels = MultiChannelSubscribe[PubnubInstance.InstanceId].Keys.ToArray(); - //Check any chained subscribes while unsubscribe - for (int keyIndex = 0; keyIndex < MultiChannelSubscribe[PubnubInstance.InstanceId].Count; keyIndex++) - { - KeyValuePair kvp = MultiChannelSubscribe[PubnubInstance.InstanceId].ElementAt(keyIndex); - if (originalMultiChannelSubscribe != null && !originalMultiChannelSubscribe.ContainsKey(kvp.Key)) - { - return; - } - } - } - - if (PubnubInstance != null && MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId)) - { - channelGroups = MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys.ToArray(); - for (int keyIndex = 0; keyIndex < MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count; keyIndex++) - { - KeyValuePair kvp = MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ElementAt(keyIndex); - if (originalMultiChannelGroupSubscribe != null && !originalMultiChannelGroupSubscribe.ContainsKey(kvp.Key)) - { - return; - } - } - } - - channels = (channels != null) ? channels : new string[] { }; - channelGroups = (channelGroups != null) ? channelGroups : new string[] { }; - - if (channels.Length > 0 || channelGroups.Length > 0) - { - string multiChannel = (channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; - - RequestState state = new RequestState(); - ChannelRequest[PubnubInstance.InstanceId].AddOrUpdate(multiChannel, state.Request, (key, oldValue) => state.Request); - - ResetInternetCheckSettings(channels, channelGroups); - - - //Continue with any remaining channels for subscribe/presence - MultiChannelSubscribeRequest(PNOperationType.PNSubscribeOperation, channels, channelGroups, 0, 0, false, null, this.customQueryParam); - } - else - { - if (PresenceHeartbeatTimer != null) - { - // Stop the presence heartbeat timer if there are no channels subscribed - PresenceHeartbeatTimer.Dispose(); - PresenceHeartbeatTimer = null; - } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, All channels are Unsubscribed. Further subscription was stopped", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - } - } - catch(Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} SubscribeManager=> MultiChannelUnSubscribeInit \n channel(s)={1} \n cg(s)={2} \n Exception Details={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", validChannels.OrderBy(x => x).ToArray()), string.Join(",", validChannelGroups.OrderBy(x => x).ToArray()), ex), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - } - - internal void MultiChannelSubscribeInit(PNOperationType responseType, string[] rawChannels, string[] rawChannelGroups, Dictionary initialSubscribeUrlParams, Dictionary externalQueryParam) - { - List validChannels = new List(); - List validChannelGroups = new List(); - - try - { - bool channelGroupSubscribeOnly = false; - SubscribeDisconnected[PubnubInstance.InstanceId] = false; - - if (rawChannels != null && rawChannels.Length > 0) - { - string[] rawChannelsFiltered = rawChannels; - if (rawChannels.Length != rawChannels.Distinct().Count()) - { - rawChannelsFiltered = rawChannels.Distinct().ToArray(); - } - - for (int index = 0; index < rawChannelsFiltered.Length; index++) - { - if (rawChannelsFiltered[index].Trim().Length > 0) - { - string channelName = rawChannelsFiltered[index].Trim(); - if (!string.IsNullOrEmpty(channelName)) - { - if (MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && !MultiChannelSubscribe[PubnubInstance.InstanceId].ContainsKey(channelName)) - { - validChannels.Add(channelName); - } - } - } - } - } - - if (rawChannelGroups != null && rawChannelGroups.Length > 0) - { - string[] rawChannelGroupsFiltered = rawChannelGroups; - if (rawChannelGroups.Length != rawChannelGroups.Distinct().Count()) - { - rawChannelGroupsFiltered = rawChannelGroups.Distinct().ToArray(); - } - - for (int index = 0; index < rawChannelGroupsFiltered.Length; index++) - { - if (rawChannelGroupsFiltered[index].Trim().Length > 0) - { - string channelGroupName = rawChannelGroupsFiltered[index].Trim(); - if (MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && !MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ContainsKey(channelGroupName)) - { - validChannelGroups.Add(channelGroupName); - } - } - } - } - - if (validChannels.Count > 0 || validChannelGroups.Count > 0 && config.ContainsKey(PubnubInstance.InstanceId)) - { - //Retrieve the current channels already subscribed previously and terminate them - List currentChannelsList = new List(MultiChannelSubscribe[PubnubInstance.InstanceId].Keys); - List currentChannelGroupsList = new List(MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys); - string[] currentChannels = new List(currentChannelsList).ToArray(); - string[] currentChannelGroups = new List(currentChannelGroupsList).ToArray(); - - if (currentChannels != null && currentChannels.Length >= 0) - { - string multiChannelGroupName = (currentChannelGroups.Length > 0) ? string.Join(",", currentChannelGroups.OrderBy(x => x).ToArray()) : ""; - if (ChannelRequest.ContainsKey(PubnubInstance.InstanceId)) - { - List keysList = new List(ChannelRequest[PubnubInstance.InstanceId].Keys); - for (int keyIndex = 0; keyIndex < keysList.Count; keyIndex++) - { - string multiChannelName = keysList[keyIndex]; - if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(multiChannelName)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Aborting previous subscribe/presence requests having channel(s)={1}; channelgroup(s)={2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - HttpWebRequest webRequest; - ChannelRequest[PubnubInstance.InstanceId].TryGetValue(multiChannelName, out webRequest); - ChannelRequest[PubnubInstance.InstanceId].TryUpdate(multiChannelName, null, webRequest); - - HttpWebRequest removedRequest; - bool removedChannel = ChannelRequest[PubnubInstance.InstanceId].TryRemove(multiChannelName, out removedRequest); - if (removedChannel) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Success to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - if (webRequest != null) - { - TerminatePendingWebRequest(webRequest); - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to capture channel(s)={1}; channelgroup(s)={2} from _channelRequest to abort request.", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to find instance id = {1} from _channelRequest.", DateTime.Now.ToString(CultureInfo.InvariantCulture), PubnubInstance.InstanceId), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - } - - TerminateCurrentSubscriberRequest(); - - //Add the valid channels to the channels subscribe list for tracking - for (int index = 0; index < validChannels.Count; index++) - { - string currentLoopChannel = validChannels[index]; - MultiChannelSubscribe[PubnubInstance.InstanceId].GetOrAdd(currentLoopChannel, 0); - } - - - for (int index = 0; index < validChannelGroups.Count; index++) - { - string currentLoopChannelGroup = validChannelGroups[index]; - MultiChannelGroupSubscribe[PubnubInstance.InstanceId].GetOrAdd(currentLoopChannelGroup, 0); - } - - //Get all the channels - string[] channels = new List(MultiChannelSubscribe[PubnubInstance.InstanceId].Keys).ToArray(); - string[] channelGroups = new List(MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys).ToArray(); - - if (channelGroups != null && channelGroups.Length > 0 && (channels == null || channels.Length == 0)) - { - channelGroupSubscribeOnly = true; - } - - RequestState state = new RequestState(); - if (ChannelRequest.ContainsKey(PubnubInstance.InstanceId)) - { - if (channelGroupSubscribeOnly) - { - ChannelRequest[PubnubInstance.InstanceId].AddOrUpdate(",", state.Request, (key, oldValue) => state.Request); - } - else - { - ChannelRequest[PubnubInstance.InstanceId].AddOrUpdate(string.Join(",", channels.OrderBy(x => x).ToArray()), state.Request, (key, oldValue) => state.Request); - } - } - - ResetInternetCheckSettings(channels, channelGroups); - MultiChannelSubscribeRequest(responseType, channels, channelGroups, 0, 0, false, initialSubscribeUrlParams, externalQueryParam); - - if (SubscribeHeartbeatCheckTimer != null) - { - try - { - SubscribeHeartbeatCheckTimer.Change(Timeout.Infinite, Timeout.Infinite); - } - catch { /* ignore */ } - } - SubscribeHeartbeatCheckTimer = new Timer(StartSubscribeHeartbeatCheckCallback, null, config[PubnubInstance.InstanceId].SubscribeTimeout * 500, config[PubnubInstance.InstanceId].SubscribeTimeout * 500); - } - } - catch(Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} SubscribeManager=> MultiChannelSubscribeInit \n channel(s)={1} \n cg(s)={2} \n Exception Details={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", validChannels.OrderBy(x => x).ToArray()), string.Join(",", validChannelGroups.OrderBy(x => x).ToArray()), ex), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - } - - private void MultiChannelSubscribeRequest(PNOperationType type, string[] channels, string[] channelGroups, object timetoken, int region, bool reconnect, Dictionary initialSubscribeUrlParams, Dictionary externalQueryParam) - { - if (!config.ContainsKey(PubnubInstance.InstanceId)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, InstanceId Not Available. Exiting MultiChannelSubscribeRequest", DateTime.Now.ToString(CultureInfo.InvariantCulture)), PNLogVerbosity.BODY); - return; - } - if (SubscribeDisconnected[PubnubInstance.InstanceId]) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeDisconnected. Exiting MultiChannelSubscribeRequest", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); - return; - } - - //Exit if the channel is unsubscribed - if (MultiChannelSubscribe != null && MultiChannelSubscribe[PubnubInstance.InstanceId].Count <= 0 && MultiChannelGroupSubscribe != null && MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count <= 0) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Zero channels/channelGroups. Further subscription was stopped", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - return; - } - - string multiChannel = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; - string multiChannelGroup = (channelGroups != null && channelGroups.Length > 0) ? string.Join(",", channelGroups.OrderBy(x => x).ToArray()) : ""; - - bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, type, null, channels, channelGroups); - - if (!networkConnection) - { - ConnectionErrors++; - UpdatePubnubNetworkTcpCheckIntervalInSeconds(); - ChannelInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(multiChannel, networkConnection, (key, oldValue) => networkConnection); - ChannelGroupInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(multiChannelGroup, networkConnection, (key, oldValue) => networkConnection); - } - - bool channelInternetFlag; - bool channelGroupInternetFlag; - if (((ChannelInternetStatus[PubnubInstance.InstanceId].ContainsKey(multiChannel) && ChannelInternetStatus[PubnubInstance.InstanceId].TryGetValue(multiChannel, out channelInternetFlag) && !channelInternetFlag) - || (multiChannelGroup != "" && ChannelGroupInternetStatus[PubnubInstance.InstanceId].ContainsKey(multiChannelGroup) && ChannelGroupInternetStatus[PubnubInstance.InstanceId].TryGetValue(multiChannelGroup, out channelGroupInternetFlag) && !channelGroupInternetFlag)) - && PubnetSystemActive) - { - if (ReconnectNetworkIfOverrideTcpKeepAlive(type, channels, channelGroups, timetoken, region, networkConnection)) - { - return; - } - } - - if (!ChannelRequest.ContainsKey(PubnubInstance.InstanceId) || (!multiChannel.Equals(",", StringComparison.OrdinalIgnoreCase) && !ChannelRequest[PubnubInstance.InstanceId].ContainsKey(multiChannel))) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, PubnubInstance.InstanceId NOT matching", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - return; - } - - - // Begin recursive subscribe - RequestState pubnubRequestState = null; - try - { - this.customQueryParam = externalQueryParam; - RegisterPresenceHeartbeatTimer(channels, channelGroups); - - long lastTimetoken = 0; - long minimumTimetoken1 = (MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelSubscribe[PubnubInstance.InstanceId].Min(token => token.Value) : 0; - long minimumTimetoken2 = (MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Min(token => token.Value) : 0; - long minimumTimetoken = Math.Max(minimumTimetoken1, minimumTimetoken2); - - long maximumTimetoken1 = (MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelSubscribe[PubnubInstance.InstanceId].Max(token => token.Value) : 0; - long maximumTimetoken2 = (MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Max(token => token.Value) : 0; - long maximumTimetoken = Math.Max(maximumTimetoken1, maximumTimetoken2); - - - if (minimumTimetoken == 0 || reconnect || UserIdChanged[PubnubInstance.InstanceId]) - { - lastTimetoken = 0; - UserIdChanged.AddOrUpdate(PubnubInstance.InstanceId, false, (k, o) => false); - } - else - { - if (LastSubscribeTimetoken[PubnubInstance.InstanceId] == maximumTimetoken) - { - lastTimetoken = maximumTimetoken; - } - else - { - lastTimetoken = LastSubscribeTimetoken[PubnubInstance.InstanceId]; - } - } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Building request for channel(s)={1}, channelgroup(s)={2} with timetoken={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannel, multiChannelGroup, lastTimetoken), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - // Build URL - string channelsJsonState = BuildJsonUserState(channels, channelGroups, false); - config[PubnubInstance.InstanceId].UserId = CurrentUserId[PubnubInstance.InstanceId]; // to make sure we capture if UUID is changed - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config[PubnubInstance.InstanceId], jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildMultiChannelSubscribeRequest("GET", "", channels, channelGroups, (Convert.ToInt64(timetoken.ToString(), CultureInfo.InvariantCulture) == 0) ? Convert.ToInt64(timetoken.ToString(), CultureInfo.InvariantCulture) : lastTimetoken, region, channelsJsonState, initialSubscribeUrlParams, externalQueryParam); - - pubnubRequestState = new RequestState(); - pubnubRequestState.Channels = channels; - pubnubRequestState.ChannelGroups = channelGroups; - pubnubRequestState.ResponseType = type; - pubnubRequestState.Reconnect = reconnect; - pubnubRequestState.Timetoken = Convert.ToInt64(timetoken.ToString(), CultureInfo.InvariantCulture); - pubnubRequestState.Region = region; - pubnubRequestState.TimeQueued = DateTime.Now; - - // Wait for message - string json = ""; - UrlProcessRequest(request, pubnubRequestState, false).ContinueWith(r => - { - json = r.Result.Item1; - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - if (!string.IsNullOrEmpty(json)) - { - string subscribedChannels = (MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelSubscribe[PubnubInstance.InstanceId].Keys.OrderBy(x=>x).Aggregate((x, y) => x + "," + y) : ""; - string currentChannels = (channels != null && channels.Length > 0) ? channels.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; - - string subscribedChannelGroups = (MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; - string currentChannelGroups = (channelGroups != null && channelGroups.Length > 0) ? channelGroups.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; - - if (subscribedChannels.Equals(currentChannels, StringComparison.OrdinalIgnoreCase) && subscribedChannelGroups.Equals(currentChannelGroups, StringComparison.OrdinalIgnoreCase)) - { - List result = ProcessJsonResponse(pubnubRequestState, json); - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, result count of ProcessJsonResponse = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), (result != null) ? result.Count : -1), config[PubnubInstance.InstanceId].LogVerbosity); - - ProcessResponseCallbacks(result, pubnubRequestState); - - if ((pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation || pubnubRequestState.ResponseType == PNOperationType.Presence) && (result != null) && (result.Count > 0)) - { - long jsonTimetoken = GetTimetokenFromMultiplexResult(result); - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, jsonTimetoken = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), jsonTimetoken), config[PubnubInstance.InstanceId].LogVerbosity); - - if (jsonTimetoken > 0) - { - if (pubnubRequestState.Channels != null) - { - foreach (string currentChannel in pubnubRequestState.Channels) - { - MultiChannelSubscribe[PubnubInstance.InstanceId].AddOrUpdate(currentChannel, jsonTimetoken, (key, oldValue) => jsonTimetoken); - } - } - if (pubnubRequestState.ChannelGroups != null && pubnubRequestState.ChannelGroups.Length > 0) - { - foreach (string currentChannelGroup in pubnubRequestState.ChannelGroups) - { - MultiChannelGroupSubscribe[PubnubInstance.InstanceId].AddOrUpdate(currentChannelGroup, jsonTimetoken, (key, oldValue) => jsonTimetoken); - } - } - } - } - - if (pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation) - { - MultiplexInternalCallback(pubnubRequestState.ResponseType, result); - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, condition failed for subscribedChannels == currentChannels && subscribedChannelGroups == currentChannelGroups", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, subscribedChannels = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), subscribedChannels), config[PubnubInstance.InstanceId].LogVerbosity); - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, currentChannels = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentChannels), config[PubnubInstance.InstanceId].LogVerbosity); - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, subscribedChannelGroups = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), subscribedChannelGroups), config[PubnubInstance.InstanceId].LogVerbosity); - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, currentChannelGroups = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentChannelGroups), config[PubnubInstance.InstanceId].LogVerbosity); - } - - } - else - { - if (multiplexExceptionTimer != null) - { - multiplexExceptionTimer.Change(Timeout.Infinite, Timeout.Infinite); - } - ConnectionErrors++; - UpdatePubnubNetworkTcpCheckIntervalInSeconds(); - multiplexExceptionTimer = new Timer(new TimerCallback(MultiplexExceptionHandlerTimerCallback), pubnubRequestState, - (-1 == PubnubNetworkTcpCheckIntervalInSeconds) ? Timeout.Infinite : PubnubNetworkTcpCheckIntervalInSeconds * 1000, - Timeout.Infinite); - } - } - catch (Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} method:_subscribe \n channel={1} \n timetoken={2} \n Exception Details={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", channels.OrderBy(x => x).ToArray()), timetoken, ex), config[PubnubInstance.InstanceId].LogVerbosity); - - PNStatusCategory errorCategory = PNStatusCategoryHelper.GetPNStatusCategory(ex); - PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(type, errorCategory, pubnubRequestState, (int)HttpStatusCode.NotFound, new PNException(ex)); - if (channels != null && channels.Length > 0) - { - status.AffectedChannels.AddRange(channels); - } - - if (channelGroups != null && channelGroups.Length > 0) - { - status.AffectedChannels.AddRange(channelGroups); - } - - Announce(status); - - MultiChannelSubscribeRequest(type, channels, channelGroups, LastSubscribeTimetoken[PubnubInstance.InstanceId], LastSubscribeRegion[PubnubInstance.InstanceId], false, null, externalQueryParam); - } - } - - private void MultiplexExceptionHandlerTimerCallback(object state) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} MultiplexExceptionHandlerTimerCallback", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - RequestState currentState = state as RequestState; - if (currentState != null) - { - MultiplexExceptionHandler(currentState.ResponseType, currentState.Channels, currentState.ChannelGroups, false); - } - } - - private void MultiplexExceptionHandler(PNOperationType type, string[] channels, string[] channelGroups, bool resumeOnReconnect) - { - List result = new List(); - result.Add("0"); - if (resumeOnReconnect || LastSubscribeTimetoken == null || !LastSubscribeTimetoken.ContainsKey(PubnubInstance.InstanceId)) - { - result.Add(0); //send 0 time token to enable presence event - } - else - { - long lastTT = LastSubscribeTimetoken[PubnubInstance.InstanceId]; //get last timetoken of the current instance - int lastRegionId = (LastSubscribeRegion != null && LastSubscribeRegion.ContainsKey(PubnubInstance.InstanceId)) ? LastSubscribeRegion[PubnubInstance.InstanceId] : 0; //get last region of the current instance - - Dictionary dictTimetokenAndRegion = new Dictionary(); - dictTimetokenAndRegion.Add("t", lastTT); - dictTimetokenAndRegion.Add("r", lastRegionId); - - Dictionary dictEnvelope = new Dictionary(); - dictEnvelope.Add("t", dictTimetokenAndRegion); - result.Add(dictEnvelope); - } - - if (channelGroups != null && channelGroups.Length > 0) - { - result.Add(channelGroups); - } - result.Add(channels); //send channel name - - MultiplexInternalCallback(type, result); - } - - private void MultiplexInternalCallback(PNOperationType type, object multiplexResult) - { - List message = multiplexResult as List; - string[] channels = null; - string[] channelGroups = null; - if (message != null && message.Count >= 3) - { - if (message[message.Count - 1] is string[]) - { - channels = message[message.Count - 1] as string[]; - } - else - { - channels = message[message.Count - 1].ToString().Split(','); - } - - if (channels.Length == 1 && channels[0] == "") - { - channels = new string[] { }; - } - if (message.Count >= 4) - { - if (message[message.Count - 2] is string[]) - { - channelGroups = message[message.Count - 2] as string[]; - } - else if (message[message.Count - 2].ToString() != "") - { - channelGroups = message[message.Count - 2].ToString().Split(','); - } - } - - long timetoken = GetTimetokenFromMultiplexResult(message); - int region = GetRegionFromMultiplexResult(message); - Task.Factory.StartNew(() => - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} MultiplexInternalCallback timetoken = {1}; region = {2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), timetoken, region), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - MultiChannelSubscribeRequest(type, channels, channelGroups, timetoken, region, false, null, this.customQueryParam); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Lost Channel Name for resubscribe", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - } - - private bool ReconnectNetworkIfOverrideTcpKeepAlive(PNOperationType type, string[] channels, string[] channelGroups, object timetoken, int region, bool networkAvailable) - { - if (OverrideTcpKeepAlive) - { - ReconnectState netState = new ReconnectState(); - netState.Channels = channels; - netState.ChannelGroups = channelGroups; - netState.ResponseType = type; - netState.Timetoken = timetoken; - netState.Region = region; - if (!config.ContainsKey(PubnubInstance.InstanceId)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, InstanceId Not Available. So no reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), PNLogVerbosity.BODY); - } - - if (SubscribeDisconnected[PubnubInstance.InstanceId]) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Subscribe is still Disconnected. So no reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); - } - else if (config[PubnubInstance.InstanceId].ReconnectionPolicy != PNReconnectionPolicy.NONE) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Subscribe - No internet connection for channel={1} and channelgroup={2}; networkAvailable={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", channels.OrderBy(x => x).ToArray()), channelGroups != null ? string.Join(",", channelGroups) : "", networkAvailable), config[PubnubInstance.InstanceId].LogVerbosity); - TerminateReconnectTimer(); - ReconnectNetwork(netState); - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, reconnection policy is DISABLED, please handle reconnection manually.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); - if (!networkAvailable) - { - PNStatusCategory errorCategory = PNStatusCategory.PNNetworkIssuesCategory; - PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(type, errorCategory, null, (int)HttpStatusCode.NotFound, new PNException("SDK Network related error")); - if (channels != null && channels.Length > 0) - { - status.AffectedChannels.AddRange(channels); - } - if (channelGroups != null && channelGroups.Length > 0) - { - status.AffectedChannels.AddRange(channelGroups); - } - Announce(status); - - } - } - return true; - } - else - { - return false; - } - } - - private void ReconnectNetwork(ReconnectState netState) - { - if (netState != null && ((netState.Channels != null && netState.Channels.Length > 0) || (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0))) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager ReconnectNetwork interval = {1} sec", DateTime.Now.ToString(CultureInfo.InvariantCulture), PubnubNetworkTcpCheckIntervalInSeconds), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - - System.Threading.Timer timer; - - if (netState.Channels != null && netState.Channels.Length > 0) - { - string reconnectChannelTimerKey = string.Join(",", netState.Channels.OrderBy(x => x).ToArray()); - - if (!ChannelReconnectTimer[PubnubInstance.InstanceId].ContainsKey(reconnectChannelTimerKey)) - { - timer = new Timer(new TimerCallback(ReconnectNetworkCallback), netState, 0, - (-1 == PubnubNetworkTcpCheckIntervalInSeconds) ? Timeout.Infinite : PubnubNetworkTcpCheckIntervalInSeconds * 1000); - ChannelReconnectTimer[PubnubInstance.InstanceId].AddOrUpdate(reconnectChannelTimerKey, timer, (key, oldState) => timer); - } - } - else if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) - { - string reconnectChannelGroupTimerKey = string.Join(",", netState.ChannelGroups.OrderBy(x => x).ToArray()); - - if (!ChannelGroupReconnectTimer[PubnubInstance.InstanceId].ContainsKey(reconnectChannelGroupTimerKey)) - { - timer = new Timer(new TimerCallback(ReconnectNetworkCallback), netState, 0, - (-1 == PubnubNetworkTcpCheckIntervalInSeconds) ? Timeout.Infinite : PubnubNetworkTcpCheckIntervalInSeconds * 1000); - ChannelGroupReconnectTimer[PubnubInstance.InstanceId].AddOrUpdate(reconnectChannelGroupTimerKey, timer, (key, oldState) => timer); - } - } - } - } - - internal bool Reconnect(bool resetSubscribeTimetoken) - { - if (!SubscribeDisconnected[PubnubInstance.InstanceId]) //Check if disconnect is done before - { - return false; - } - - string[] channels = GetCurrentSubscriberChannels(); - string[] chananelGroups = GetCurrentSubscriberChannelGroups(); - - if ((channels != null && channels.Length > 0) || (chananelGroups != null && chananelGroups.Length > 0)) - { - string channel = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; - string channelGroup = (chananelGroups != null && chananelGroups.Length > 0) ? string.Join(",", chananelGroups.OrderBy(x => x).ToArray()) : ""; - - bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, PNOperationType.PNSubscribeOperation, null, channels, chananelGroups); - if (!networkConnection) - { - //Recheck for false alert with 1 sec delay + internal class SubscribeManager : PubnubCoreBase, IDisposable + { + private static ConcurrentDictionary config { get; } = new ConcurrentDictionary(); + private static IJsonPluggableLibrary jsonLibrary; + private static IPubnubUnitTest unit; + private static IPubnubLog pubnubLog; + + private static Timer SubscribeHeartbeatCheckTimer; + private Timer multiplexExceptionTimer; + private Dictionary customQueryParam; + + public SubscribeManager(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config.AddOrUpdate(instance.InstanceId, pubnubConfig, (k, o) => pubnubConfig); + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + + internal void MultiChannelUnSubscribeAll(PNOperationType type, Dictionary externalQueryParam) + { + //Retrieve the current channels already subscribed previously and terminate them + string[] currentChannels = (MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe[PubnubInstance.InstanceId] != null) ? new List(MultiChannelSubscribe[PubnubInstance.InstanceId].Keys).ToArray() : null; + string[] currentChannelGroups = (MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe[PubnubInstance.InstanceId] != null) ? new List(MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys).ToArray() : null; + + if (currentChannels != null && currentChannels.Length >= 0) { + string multiChannelName = (currentChannels.Length > 0) ? string.Join(",", currentChannels.OrderBy(x => x).ToArray()) : ","; + string multiChannelGroupName = (currentChannelGroups.Length > 0) ? string.Join(",", currentChannelGroups.OrderBy(x => x).ToArray()) : ""; + + Task.Factory.StartNew(() => { + if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(multiChannelName)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Aborting previous subscribe/presence requests having channel(s)={1}; channelgroup(s)={2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + + CancellationTokenSource webRequest; + ChannelRequest[PubnubInstance.InstanceId].TryGetValue(multiChannelName, out webRequest); + ChannelRequest[PubnubInstance.InstanceId].TryUpdate(multiChannelName, null, webRequest); + + CancellationTokenSource removedRequest; + bool removedChannel = ChannelRequest[PubnubInstance.InstanceId].TryRemove(multiChannelName, out removedRequest); + if (removedChannel) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Success to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelUnSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelUnSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to capture channel(s)={1}; channelgroup(s)={2} from _channelRequest to abort request.", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); + + if (type == PNOperationType.PNUnsubscribeOperation && config.ContainsKey(PubnubInstance.InstanceId) && !config[PubnubInstance.InstanceId].SuppressLeaveEvents) { + //just fire leave() event to REST API for safeguard + var leaveRequestParameter = CreateLeaveRequestParameter(currentChannels, currentChannelGroups); + var leaveTransportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: leaveRequestParameter, operationType: PNOperationType.Leave); + PubnubInstance.transportMiddleware.Send(transportRequest: leaveTransportRequest).ContinueWith(t => { + MultiChannelSubscribe[PubnubInstance.InstanceId].Clear(); + MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Clear(); + }); + + } + } + + } + + internal void MultiChannelUnSubscribeInit(PNOperationType type, string channel, string channelGroup, Dictionary externalQueryParam) + { + List validChannels = new List(); + List validChannelGroups = new List(); + + try { + this.customQueryParam = externalQueryParam; + + if (PubnubInstance == null) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, PubnubInstance is null. exiting MultiChannelUnSubscribeInit", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + return; + } + + if (!MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId)) { + MultiChannelSubscribe.GetOrAdd(PubnubInstance.InstanceId, new ConcurrentDictionary()); + } + if (!MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId)) { + MultiChannelGroupSubscribe.GetOrAdd(PubnubInstance.InstanceId, new ConcurrentDictionary()); + } + + string[] rawChannels = (channel != null && channel.Trim().Length > 0) ? channel.Split(',') : new string[] { }; + string[] rawChannelGroups = (channelGroup != null && channelGroup.Trim().Length > 0) ? channelGroup.Split(',') : new string[] { }; + + if (rawChannels.Length > 0) { + for (int index = 0; index < rawChannels.Length; index++) { + if (rawChannels[index].Trim().Length > 0) { + string channelName = rawChannels[index].Trim(); + if (string.IsNullOrEmpty(channelName)) { + continue; + } + + if (config.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe[PubnubInstance.InstanceId] != null && !MultiChannelSubscribe[PubnubInstance.InstanceId].ContainsKey(channelName)) { + PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(PNOperationType.PNUnsubscribeOperation, PNStatusCategory.PNUnexpectedDisconnectCategory, null, (int)HttpStatusCode.NotFound, null); + if (!status.AffectedChannels.Contains(channelName)) { + status.AffectedChannels.Add(channelName); + } + Announce(status); + } else { + validChannels.Add(channelName); + string presenceChannelName = string.Format(CultureInfo.InvariantCulture, "{0}-pnpres", channelName); + if (MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe[PubnubInstance.InstanceId] != null && MultiChannelSubscribe[PubnubInstance.InstanceId].ContainsKey(presenceChannelName)) { + validChannels.Add(presenceChannelName); + } + } + } + } + } + + if (rawChannelGroups.Length > 0) { + for (int index = 0; index < rawChannelGroups.Length; index++) { + if (rawChannelGroups[index].Trim().Length > 0) { + string channelGroupName = rawChannelGroups[index].Trim(); + if (string.IsNullOrEmpty(channelGroupName)) { + continue; + } + + if (config.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe[PubnubInstance.InstanceId] != null && !MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ContainsKey(channelGroupName)) { + PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(PNOperationType.PNUnsubscribeOperation, PNStatusCategory.PNUnexpectedDisconnectCategory, null, (int)HttpStatusCode.NotFound, null); + if (!status.AffectedChannelGroups.Contains(channelGroupName)) { + status.AffectedChannelGroups.Add(channelGroupName); + } + Announce(status); + } else { + validChannelGroups.Add(channelGroupName); + string presenceChannelGroupName = string.Format(CultureInfo.InvariantCulture, "{0}-pnpres", channelGroupName); + if (MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe[PubnubInstance.InstanceId] != null && MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ContainsKey(presenceChannelGroupName)) { + validChannelGroups.Add(presenceChannelGroupName); + } + } + } + } + } + + if (validChannels.Count > 0 || validChannelGroups.Count > 0) { + //Retrieve the current channels already subscribed previously and terminate them + string[] currentChannels = new List(MultiChannelSubscribe[PubnubInstance.InstanceId].Keys).ToArray(); + string[] currentChannelGroups = new List(MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys).ToArray(); + + if (currentChannels != null && currentChannels.Length >= 0) { + string multiChannelName = (currentChannels.Length > 0) ? string.Join(",", currentChannels.OrderBy(x => x).ToArray()) : ","; + string multiChannelGroupName = (currentChannelGroups.Length > 0) ? string.Join(",", currentChannelGroups.OrderBy(x => x).ToArray()) : ""; + + Task.Factory.StartNew(() => { + if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(multiChannelName)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Aborting previous subscribe/presence requests having channel(s)={1}; channelgroup(s)={2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + + CancellationTokenSource webRequest; + ChannelRequest[PubnubInstance.InstanceId].TryGetValue(multiChannelName, out webRequest); + ChannelRequest[PubnubInstance.InstanceId].TryUpdate(multiChannelName, null, webRequest); + + CancellationTokenSource removedRequest; + bool removedChannel = ChannelRequest[PubnubInstance.InstanceId].TryRemove(multiChannelName, out removedRequest); + if (removedChannel) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Success to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelUnSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelUnSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to capture channel(s)={1}; channelgroup(s)={2} from _channelRequest to abort request.", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); + + if (type == PNOperationType.PNUnsubscribeOperation && config.ContainsKey(PubnubInstance.InstanceId)) { + //just fire leave() event to REST API for safeguard + + var leaveRequestParameter = CreateLeaveRequestParameter(validChannels.ToArray(), validChannelGroups.ToArray()); + var leaveTransportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: leaveRequestParameter, operationType: PNOperationType.Leave); + PubnubInstance.transportMiddleware.Send(transportRequest: leaveTransportRequest).ContinueWith(t => { }); + + } + } + + Dictionary originalMultiChannelSubscribe = null; + Dictionary originalMultiChannelGroupSubscribe = null; + if (PubnubInstance != null && MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId)) { + originalMultiChannelSubscribe = MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0 ? MultiChannelSubscribe[PubnubInstance.InstanceId].ToDictionary(kvp => kvp.Key, kvp => kvp.Value) : null; + } + if (PubnubInstance != null && MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId)) { + originalMultiChannelGroupSubscribe = MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0 ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ToDictionary(kvp => kvp.Key, kvp => kvp.Value) : null; + } + + PNStatus successStatus = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(PNOperationType.PNUnsubscribeOperation, PNStatusCategory.PNDisconnectedCategory, null, (int)HttpStatusCode.OK, null); + PNStatus failStatus = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(PNOperationType.PNUnsubscribeOperation, PNStatusCategory.PNDisconnectedCategory, null, (int)HttpStatusCode.NotFound, new PNException("Unsubscribe Error. Please retry unsubscribe operation")); + bool successExist = false; + bool failExist = false; + + //Remove the valid channels from subscribe list for unsubscribe + for (int index = 0; index < validChannels.Count; index++) { + long timetokenValue; + string channelToBeRemoved = validChannels[index]; + bool unsubscribeStatus = false; + if (PubnubInstance != null && MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId)) { + unsubscribeStatus = MultiChannelSubscribe[PubnubInstance.InstanceId].TryRemove(channelToBeRemoved, out timetokenValue); + } + if (channelToBeRemoved.Contains("-pnpres")) { + continue; //Do not send status for -pnpres channels + } + if (unsubscribeStatus) { + successExist = true; + if (!successStatus.AffectedChannels.Contains(channelToBeRemoved)) { + successStatus.AffectedChannels.Add(channelToBeRemoved); + } + + base.DeleteLocalChannelUserState(channelToBeRemoved); + } else { + failExist = true; + if (!failStatus.AffectedChannels.Contains(channelToBeRemoved)) { + failStatus.AffectedChannels.Add(channelToBeRemoved); + } + } + } + for (int index = 0; index < validChannelGroups.Count; index++) { + long timetokenValue; + string channelGroupToBeRemoved = validChannelGroups[index]; + bool unsubscribeStatus = false; + if (PubnubInstance != null && MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId)) { + unsubscribeStatus = MultiChannelGroupSubscribe[PubnubInstance.InstanceId].TryRemove(channelGroupToBeRemoved, out timetokenValue); + } + if (channelGroupToBeRemoved.Contains("-pnpres")) { + continue; //Do not send status for -pnpres channel-groups + } + if (unsubscribeStatus) { + successExist = true; + if (!successStatus.AffectedChannelGroups.Contains(channelGroupToBeRemoved)) { + successStatus.AffectedChannelGroups.Add(channelGroupToBeRemoved); + } + + base.DeleteLocalChannelGroupUserState(channelGroupToBeRemoved); + } else { + failExist = true; + if (!failStatus.AffectedChannelGroups.Contains(channelGroupToBeRemoved)) { + failStatus.AffectedChannelGroups.Add(channelGroupToBeRemoved); + } + } + } + + if (successExist && PubnubInstance != null) { + Announce(successStatus); + } + + if (failExist && PubnubInstance != null) { + Announce(failStatus); + } + + //Get all the channels + string[] channels = new string[] { }; + string[] channelGroups = new string[] { }; + + if (PubnubInstance != null && MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId)) { + channels = MultiChannelSubscribe[PubnubInstance.InstanceId].Keys.ToArray(); + //Check any chained subscribes while unsubscribe + for (int keyIndex = 0; keyIndex < MultiChannelSubscribe[PubnubInstance.InstanceId].Count; keyIndex++) { + KeyValuePair kvp = MultiChannelSubscribe[PubnubInstance.InstanceId].ElementAt(keyIndex); + if (originalMultiChannelSubscribe != null && !originalMultiChannelSubscribe.ContainsKey(kvp.Key)) { + return; + } + } + } + + if (PubnubInstance != null && MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId)) { + channelGroups = MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys.ToArray(); + for (int keyIndex = 0; keyIndex < MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count; keyIndex++) { + KeyValuePair kvp = MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ElementAt(keyIndex); + if (originalMultiChannelGroupSubscribe != null && !originalMultiChannelGroupSubscribe.ContainsKey(kvp.Key)) { + return; + } + } + } + + channels = (channels != null) ? channels : new string[] { }; + channelGroups = (channelGroups != null) ? channelGroups : new string[] { }; + + if (channels.Length > 0 || channelGroups.Length > 0) { + string multiChannel = (channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; + + RequestState state = new RequestState(); + ChannelRequest[PubnubInstance.InstanceId].AddOrUpdate(multiChannel, state.RequestCancellationTokenSource, (key, oldValue) => state.RequestCancellationTokenSource); + + ResetInternetCheckSettings(channels, channelGroups); + + + //Continue with any remaining channels for subscribe/presence + MultiChannelSubscribeRequest(PNOperationType.PNSubscribeOperation, channels, channelGroups, 0, 0, false, null, this.customQueryParam); + } else { + if (PresenceHeartbeatTimer != null) { + // Stop the presence heartbeat timer if there are no channels subscribed + PresenceHeartbeatTimer.Dispose(); + PresenceHeartbeatTimer = null; + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, All channels are Unsubscribed. Further subscription was stopped", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } + } catch (Exception ex) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} SubscribeManager=> MultiChannelUnSubscribeInit \n channel(s)={1} \n cg(s)={2} \n Exception Details={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", validChannels.OrderBy(x => x).ToArray()), string.Join(",", validChannelGroups.OrderBy(x => x).ToArray()), ex), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } + + internal void MultiChannelSubscribeInit(PNOperationType responseType, string[] rawChannels, string[] rawChannelGroups, Dictionary initialSubscribeUrlParams, Dictionary externalQueryParam) + { + List validChannels = new List(); + List validChannelGroups = new List(); + + try { + bool channelGroupSubscribeOnly = false; + SubscribeDisconnected[PubnubInstance.InstanceId] = false; + + if (rawChannels != null && rawChannels.Length > 0) { + string[] rawChannelsFiltered = rawChannels; + if (rawChannels.Length != rawChannels.Distinct().Count()) { + rawChannelsFiltered = rawChannels.Distinct().ToArray(); + } + + for (int index = 0; index < rawChannelsFiltered.Length; index++) { + if (rawChannelsFiltered[index].Trim().Length > 0) { + string channelName = rawChannelsFiltered[index].Trim(); + if (!string.IsNullOrEmpty(channelName)) { + if (MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && !MultiChannelSubscribe[PubnubInstance.InstanceId].ContainsKey(channelName)) { + validChannels.Add(channelName); + } + } + } + } + } + + if (rawChannelGroups != null && rawChannelGroups.Length > 0) { + string[] rawChannelGroupsFiltered = rawChannelGroups; + if (rawChannelGroups.Length != rawChannelGroups.Distinct().Count()) { + rawChannelGroupsFiltered = rawChannelGroups.Distinct().ToArray(); + } + + for (int index = 0; index < rawChannelGroupsFiltered.Length; index++) { + if (rawChannelGroupsFiltered[index].Trim().Length > 0) { + string channelGroupName = rawChannelGroupsFiltered[index].Trim(); + if (MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && !MultiChannelGroupSubscribe[PubnubInstance.InstanceId].ContainsKey(channelGroupName)) { + validChannelGroups.Add(channelGroupName); + } + } + } + } + + if (validChannels.Count > 0 || validChannelGroups.Count > 0 && config.ContainsKey(PubnubInstance.InstanceId)) { + //Retrieve the current channels already subscribed previously and terminate them + List currentChannelsList = new List(MultiChannelSubscribe[PubnubInstance.InstanceId].Keys); + List currentChannelGroupsList = new List(MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys); + string[] currentChannels = new List(currentChannelsList).ToArray(); + string[] currentChannelGroups = new List(currentChannelGroupsList).ToArray(); + + if (currentChannels != null && currentChannels.Length >= 0) { + string multiChannelGroupName = (currentChannelGroups.Length > 0) ? string.Join(",", currentChannelGroups.OrderBy(x => x).ToArray()) : ""; + if (ChannelRequest.ContainsKey(PubnubInstance.InstanceId)) { + List keysList = new List(ChannelRequest[PubnubInstance.InstanceId].Keys); + for (int keyIndex = 0; keyIndex < keysList.Count; keyIndex++) { + string multiChannelName = keysList[keyIndex]; + if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(multiChannelName)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Aborting previous subscribe/presence requests having channel(s)={1}; channelgroup(s)={2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + CancellationTokenSource webRequest; + ChannelRequest[PubnubInstance.InstanceId].TryGetValue(multiChannelName, out webRequest); + ChannelRequest[PubnubInstance.InstanceId].TryUpdate(multiChannelName, null, webRequest); + + CancellationTokenSource removedRequest; + bool removedChannel = ChannelRequest[PubnubInstance.InstanceId].TryRemove(multiChannelName, out removedRequest); + if (removedChannel) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Success to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to remove channel(s)={1}; channelgroup(s)={2} from _channelRequest (MultiChannelSubscribeInit).", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to capture channel(s)={1}; channelgroup(s)={2} from _channelRequest to abort request.", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannelName, multiChannelGroupName), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unable to find instance id = {1} from _channelRequest.", DateTime.Now.ToString(CultureInfo.InvariantCulture), PubnubInstance.InstanceId), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } + + TerminateCurrentSubscriberRequest(); + + //Add the valid channels to the channels subscribe list for tracking + for (int index = 0; index < validChannels.Count; index++) { + string currentLoopChannel = validChannels[index]; + MultiChannelSubscribe[PubnubInstance.InstanceId].GetOrAdd(currentLoopChannel, 0); + } + + + for (int index = 0; index < validChannelGroups.Count; index++) { + string currentLoopChannelGroup = validChannelGroups[index]; + MultiChannelGroupSubscribe[PubnubInstance.InstanceId].GetOrAdd(currentLoopChannelGroup, 0); + } + + //Get all the channels + string[] channels = new List(MultiChannelSubscribe[PubnubInstance.InstanceId].Keys).ToArray(); + string[] channelGroups = new List(MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys).ToArray(); + + if (channelGroups != null && channelGroups.Length > 0 && (channels == null || channels.Length == 0)) { + channelGroupSubscribeOnly = true; + } + + RequestState state = new RequestState(); + if (ChannelRequest.ContainsKey(PubnubInstance.InstanceId)) { + if (channelGroupSubscribeOnly) { + ChannelRequest[PubnubInstance.InstanceId].AddOrUpdate(",", state.RequestCancellationTokenSource, (key, oldValue) => state.RequestCancellationTokenSource); + } else { + ChannelRequest[PubnubInstance.InstanceId].AddOrUpdate(string.Join(",", channels.OrderBy(x => x).ToArray()), state.RequestCancellationTokenSource, (key, oldValue) => state.RequestCancellationTokenSource); + } + } + + ResetInternetCheckSettings(channels, channelGroups); + MultiChannelSubscribeRequest(responseType, channels, channelGroups, 0, 0, false, initialSubscribeUrlParams, externalQueryParam); + + if (SubscribeHeartbeatCheckTimer != null) { + try { + SubscribeHeartbeatCheckTimer.Change(Timeout.Infinite, Timeout.Infinite); + } catch { /* ignore */ } + } + SubscribeHeartbeatCheckTimer = new Timer(StartSubscribeHeartbeatCheckCallback, null, config[PubnubInstance.InstanceId].SubscribeTimeout * 500, config[PubnubInstance.InstanceId].SubscribeTimeout * 500); + } + } catch (Exception ex) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} SubscribeManager=> MultiChannelSubscribeInit \n channel(s)={1} \n cg(s)={2} \n Exception Details={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", validChannels.OrderBy(x => x).ToArray()), string.Join(",", validChannelGroups.OrderBy(x => x).ToArray()), ex), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } + + private void MultiChannelSubscribeRequest(PNOperationType type, string[] channels, string[] channelGroups, object timetoken, int region, bool reconnect, Dictionary initialSubscribeUrlParams, Dictionary externalQueryParam) + { + if (!config.ContainsKey(PubnubInstance.InstanceId)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, InstanceId Not Available. Exiting MultiChannelSubscribeRequest", DateTime.Now.ToString(CultureInfo.InvariantCulture)), PNLogVerbosity.BODY); + return; + } + if (SubscribeDisconnected[PubnubInstance.InstanceId]) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeDisconnected. Exiting MultiChannelSubscribeRequest", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); + return; + } + + //Exit if the channel is unsubscribed + if (MultiChannelSubscribe != null && MultiChannelSubscribe[PubnubInstance.InstanceId].Count <= 0 && MultiChannelGroupSubscribe != null && MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count <= 0) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Zero channels/channelGroups. Further subscription was stopped", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + return; + } + + string multiChannel = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; + string multiChannelGroup = (channelGroups != null && channelGroups.Length > 0) ? string.Join(",", channelGroups.OrderBy(x => x).ToArray()) : ""; + + bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, type, null, channels, channelGroups); + + if (!networkConnection) { + ConnectionErrors++; + UpdatePubnubNetworkTcpCheckIntervalInSeconds(); + ChannelInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(multiChannel, networkConnection, (key, oldValue) => networkConnection); + ChannelGroupInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(multiChannelGroup, networkConnection, (key, oldValue) => networkConnection); + } + + bool channelInternetFlag; + bool channelGroupInternetFlag; + if (((ChannelInternetStatus[PubnubInstance.InstanceId].ContainsKey(multiChannel) && ChannelInternetStatus[PubnubInstance.InstanceId].TryGetValue(multiChannel, out channelInternetFlag) && !channelInternetFlag) + || (multiChannelGroup != "" && ChannelGroupInternetStatus[PubnubInstance.InstanceId].ContainsKey(multiChannelGroup) && ChannelGroupInternetStatus[PubnubInstance.InstanceId].TryGetValue(multiChannelGroup, out channelGroupInternetFlag) && !channelGroupInternetFlag)) + && PubnetSystemActive) { + if (ReconnectNetworkIfOverrideTcpKeepAlive(type, channels, channelGroups, timetoken, region, networkConnection)) { + return; + } + } + + if (!ChannelRequest.ContainsKey(PubnubInstance.InstanceId) || (!multiChannel.Equals(",", StringComparison.OrdinalIgnoreCase) && !ChannelRequest[PubnubInstance.InstanceId].ContainsKey(multiChannel))) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, PubnubInstance.InstanceId NOT matching", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + return; + } + + + // Begin recursive subscribe + RequestState pubnubRequestState = null; + try { + this.customQueryParam = externalQueryParam; + RegisterPresenceHeartbeatTimer(channels, channelGroups); + + long lastTimetoken = 0; + long minimumTimetoken1 = (MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelSubscribe[PubnubInstance.InstanceId].Min(token => token.Value) : 0; + long minimumTimetoken2 = (MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Min(token => token.Value) : 0; + long minimumTimetoken = Math.Max(minimumTimetoken1, minimumTimetoken2); + + long maximumTimetoken1 = (MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelSubscribe[PubnubInstance.InstanceId].Max(token => token.Value) : 0; + long maximumTimetoken2 = (MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Max(token => token.Value) : 0; + long maximumTimetoken = Math.Max(maximumTimetoken1, maximumTimetoken2); + + + if (minimumTimetoken == 0 || reconnect || UserIdChanged[PubnubInstance.InstanceId]) { + lastTimetoken = 0; + UserIdChanged.AddOrUpdate(PubnubInstance.InstanceId, false, (k, o) => false); + } else { + if (LastSubscribeTimetoken[PubnubInstance.InstanceId] == maximumTimetoken) { + lastTimetoken = maximumTimetoken; + } else { + lastTimetoken = LastSubscribeTimetoken[PubnubInstance.InstanceId]; + } + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Building request for channel(s)={1}, channelgroup(s)={2} with timetoken={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), multiChannel, multiChannelGroup, lastTimetoken), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + // Build URL + string channelsJsonState = BuildJsonUserState(channels, channelGroups, false); + config[PubnubInstance.InstanceId].UserId = CurrentUserId[PubnubInstance.InstanceId]; // to make sure we capture if UUID is changed + IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config[PubnubInstance.InstanceId], jsonLibrary, unit, pubnubLog, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); + + Uri request = urlBuilder.BuildMultiChannelSubscribeRequest(Constants.GET, "", channels, channelGroups, + (Convert.ToInt64(timetoken.ToString(), CultureInfo.InvariantCulture) == 0) ? Convert.ToInt64(timetoken.ToString(), CultureInfo.InvariantCulture) : lastTimetoken, region, channelsJsonState, initialSubscribeUrlParams, externalQueryParam); + + pubnubRequestState = new RequestState(); + pubnubRequestState.Channels = channels; + pubnubRequestState.ChannelGroups = channelGroups; + pubnubRequestState.ResponseType = type; + pubnubRequestState.Reconnect = reconnect; + pubnubRequestState.Timetoken = Convert.ToInt64(timetoken.ToString(), CultureInfo.InvariantCulture); + pubnubRequestState.Region = region; + pubnubRequestState.TimeQueued = DateTime.Now; + + // Wait for message + //string json = ""; + //UrlProcessRequest(request, pubnubRequestState, false).ContinueWith(r => { + // json = r.Result.Item1; + //}, TaskContinuationOptions.ExecuteSynchronously).Wait(); + + CancellationTokenSource cts = new CancellationTokenSource(); + var subscribeRequestParameter = CreateSubscribeRequestParameter(channels: channels, channelGroups: channelGroups,timetoken: (Convert.ToInt64(timetoken.ToString(), CultureInfo.InvariantCulture) == 0) ? Convert.ToInt64(timetoken.ToString(), CultureInfo.InvariantCulture) : lastTimetoken,region: region,stateJsonValue: channelsJsonState, initialSubscribeUrlParams: initialSubscribeUrlParams, externalQueryParam: externalQueryParam); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: subscribeRequestParameter, operationType: PNOperationType.PNSubscribeOperation); + transportRequest.CancellationToken = cts.Token; + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith( t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var json = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(json)) { + string subscribedChannels = (MultiChannelSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelSubscribe[PubnubInstance.InstanceId].Keys.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; + string currentChannels = (channels != null && channels.Length > 0) ? channels.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; + + string subscribedChannelGroups = (MultiChannelGroupSubscribe.ContainsKey(PubnubInstance.InstanceId) && MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; + string currentChannelGroups = (channelGroups != null && channelGroups.Length > 0) ? channelGroups.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; + + if (subscribedChannels.Equals(currentChannels, StringComparison.OrdinalIgnoreCase) && subscribedChannelGroups.Equals(currentChannelGroups, StringComparison.OrdinalIgnoreCase)) { + List result = ProcessJsonResponse(pubnubRequestState, json); + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, result count of ProcessJsonResponse = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), (result != null) ? result.Count : -1), config[PubnubInstance.InstanceId].LogVerbosity); + + ProcessResponseCallbacks(result, pubnubRequestState); + + if ((pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation || pubnubRequestState.ResponseType == PNOperationType.Presence) && (result != null) && (result.Count > 0)) { + long jsonTimetoken = GetTimetokenFromMultiplexResult(result); + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, jsonTimetoken = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), jsonTimetoken), config[PubnubInstance.InstanceId].LogVerbosity); + + if (jsonTimetoken > 0) { + if (pubnubRequestState.Channels != null) { + foreach (string currentChannel in pubnubRequestState.Channels) { + MultiChannelSubscribe[PubnubInstance.InstanceId].AddOrUpdate(currentChannel, jsonTimetoken, (key, oldValue) => jsonTimetoken); + } + } + if (pubnubRequestState.ChannelGroups != null && pubnubRequestState.ChannelGroups.Length > 0) { + foreach (string currentChannelGroup in pubnubRequestState.ChannelGroups) { + MultiChannelGroupSubscribe[PubnubInstance.InstanceId].AddOrUpdate(currentChannelGroup, jsonTimetoken, (key, oldValue) => jsonTimetoken); + } + } + } + } + + if (pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation) { + MultiplexInternalCallback(pubnubRequestState.ResponseType, result); + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, condition failed for subscribedChannels == currentChannels && subscribedChannelGroups == currentChannelGroups", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, subscribedChannels = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), subscribedChannels), config[PubnubInstance.InstanceId].LogVerbosity); + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, currentChannels = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentChannels), config[PubnubInstance.InstanceId].LogVerbosity); + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, subscribedChannelGroups = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), subscribedChannelGroups), config[PubnubInstance.InstanceId].LogVerbosity); + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, currentChannelGroups = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentChannelGroups), config[PubnubInstance.InstanceId].LogVerbosity); + } + + } else { + if (multiplexExceptionTimer != null) { + multiplexExceptionTimer.Change(Timeout.Infinite, Timeout.Infinite); + } + ConnectionErrors++; + UpdatePubnubNetworkTcpCheckIntervalInSeconds(); + multiplexExceptionTimer = new Timer(new TimerCallback(MultiplexExceptionHandlerTimerCallback), pubnubRequestState, + (-1 == PubnubNetworkTcpCheckIntervalInSeconds) ? Timeout.Infinite : PubnubNetworkTcpCheckIntervalInSeconds * 1000, + Timeout.Infinite); + } + } else { + throw transportResponse.Error; + } + }, TaskContinuationOptions.ExecuteSynchronously).Wait(); + + + } catch (Exception ex) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} method:_subscribe \n channel={1} \n timetoken={2} \n Exception Details={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", channels.OrderBy(x => x).ToArray()), timetoken, ex), config[PubnubInstance.InstanceId].LogVerbosity); + + PNStatusCategory errorCategory = PNStatusCategoryHelper.GetPNStatusCategory(ex); + PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(type, errorCategory, pubnubRequestState, (int)HttpStatusCode.NotFound, new PNException(ex)); + if (channels != null && channels.Length > 0) { + status.AffectedChannels.AddRange(channels); + } + + if (channelGroups != null && channelGroups.Length > 0) { + status.AffectedChannels.AddRange(channelGroups); + } + + Announce(status); + + MultiChannelSubscribeRequest(type, channels, channelGroups, LastSubscribeTimetoken[PubnubInstance.InstanceId], LastSubscribeRegion[PubnubInstance.InstanceId], false, null, externalQueryParam); + } + } + + private void MultiplexExceptionHandlerTimerCallback(object state) + { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} MultiplexExceptionHandlerTimerCallback", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + RequestState currentState = state as RequestState; + if (currentState != null) { + MultiplexExceptionHandler(currentState.ResponseType, currentState.Channels, currentState.ChannelGroups, false); + } + } + + private void MultiplexExceptionHandler(PNOperationType type, string[] channels, string[] channelGroups, bool resumeOnReconnect) + { + List result = new List(); + result.Add("0"); + if (resumeOnReconnect || LastSubscribeTimetoken == null || !LastSubscribeTimetoken.ContainsKey(PubnubInstance.InstanceId)) { + result.Add(0); //send 0 time token to enable presence event + } else { + long lastTT = LastSubscribeTimetoken[PubnubInstance.InstanceId]; //get last timetoken of the current instance + int lastRegionId = (LastSubscribeRegion != null && LastSubscribeRegion.ContainsKey(PubnubInstance.InstanceId)) ? LastSubscribeRegion[PubnubInstance.InstanceId] : 0; //get last region of the current instance + + Dictionary dictTimetokenAndRegion = new Dictionary(); + dictTimetokenAndRegion.Add("t", lastTT); + dictTimetokenAndRegion.Add("r", lastRegionId); + + Dictionary dictEnvelope = new Dictionary(); + dictEnvelope.Add("t", dictTimetokenAndRegion); + result.Add(dictEnvelope); + } + + if (channelGroups != null && channelGroups.Length > 0) { + result.Add(channelGroups); + } + result.Add(channels); //send channel name + + MultiplexInternalCallback(type, result); + } + + private void MultiplexInternalCallback(PNOperationType type, object multiplexResult) + { + List message = multiplexResult as List; + string[] channels = null; + string[] channelGroups = null; + if (message != null && message.Count >= 3) { + if (message[message.Count - 1] is string[]) { + channels = message[message.Count - 1] as string[]; + } else { + channels = message[message.Count - 1].ToString().Split(','); + } + + if (channels.Length == 1 && channels[0] == "") { + channels = new string[] { }; + } + if (message.Count >= 4) { + if (message[message.Count - 2] is string[]) { + channelGroups = message[message.Count - 2] as string[]; + } else if (message[message.Count - 2].ToString() != "") { + channelGroups = message[message.Count - 2].ToString().Split(','); + } + } + + long timetoken = GetTimetokenFromMultiplexResult(message); + int region = GetRegionFromMultiplexResult(message); + Task.Factory.StartNew(() => { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} MultiplexInternalCallback timetoken = {1}; region = {2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), timetoken, region), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + MultiChannelSubscribeRequest(type, channels, channelGroups, timetoken, region, false, null, this.customQueryParam); + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Lost Channel Name for resubscribe", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } + + private bool ReconnectNetworkIfOverrideTcpKeepAlive(PNOperationType type, string[] channels, string[] channelGroups, object timetoken, int region, bool networkAvailable) + { + if (OverrideTcpKeepAlive) { + ReconnectState netState = new ReconnectState(); + netState.Channels = channels; + netState.ChannelGroups = channelGroups; + netState.ResponseType = type; + netState.Timetoken = timetoken; + netState.Region = region; + if (!config.ContainsKey(PubnubInstance.InstanceId)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, InstanceId Not Available. So no reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), PNLogVerbosity.BODY); + } + + if (SubscribeDisconnected[PubnubInstance.InstanceId]) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Subscribe is still Disconnected. So no reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); + } else if (config[PubnubInstance.InstanceId].ReconnectionPolicy != PNReconnectionPolicy.NONE) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Subscribe - No internet connection for channel={1} and channelgroup={2}; networkAvailable={3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), string.Join(",", channels.OrderBy(x => x).ToArray()), channelGroups != null ? string.Join(",", channelGroups) : "", networkAvailable), config[PubnubInstance.InstanceId].LogVerbosity); + TerminateReconnectTimer(); + ReconnectNetwork(netState); + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, reconnection policy is DISABLED, please handle reconnection manually.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); + if (!networkAvailable) { + PNStatusCategory errorCategory = PNStatusCategory.PNNetworkIssuesCategory; + PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(type, errorCategory, null, (int)HttpStatusCode.NotFound, new PNException("SDK Network related error")); + if (channels != null && channels.Length > 0) { + status.AffectedChannels.AddRange(channels); + } + if (channelGroups != null && channelGroups.Length > 0) { + status.AffectedChannels.AddRange(channelGroups); + } + Announce(status); + + } + } + return true; + } else { + return false; + } + } + + private void ReconnectNetwork(ReconnectState netState) + { + if (netState != null && ((netState.Channels != null && netState.Channels.Length > 0) || (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0))) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager ReconnectNetwork interval = {1} sec", DateTime.Now.ToString(CultureInfo.InvariantCulture), PubnubNetworkTcpCheckIntervalInSeconds), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + + System.Threading.Timer timer; + + if (netState.Channels != null && netState.Channels.Length > 0) { + string reconnectChannelTimerKey = string.Join(",", netState.Channels.OrderBy(x => x).ToArray()); + + if (!ChannelReconnectTimer[PubnubInstance.InstanceId].ContainsKey(reconnectChannelTimerKey)) { + timer = new Timer(new TimerCallback(ReconnectNetworkCallback), netState, 0, + (-1 == PubnubNetworkTcpCheckIntervalInSeconds) ? Timeout.Infinite : PubnubNetworkTcpCheckIntervalInSeconds * 1000); + ChannelReconnectTimer[PubnubInstance.InstanceId].AddOrUpdate(reconnectChannelTimerKey, timer, (key, oldState) => timer); + } + } else if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) { + string reconnectChannelGroupTimerKey = string.Join(",", netState.ChannelGroups.OrderBy(x => x).ToArray()); + + if (!ChannelGroupReconnectTimer[PubnubInstance.InstanceId].ContainsKey(reconnectChannelGroupTimerKey)) { + timer = new Timer(new TimerCallback(ReconnectNetworkCallback), netState, 0, + (-1 == PubnubNetworkTcpCheckIntervalInSeconds) ? Timeout.Infinite : PubnubNetworkTcpCheckIntervalInSeconds * 1000); + ChannelGroupReconnectTimer[PubnubInstance.InstanceId].AddOrUpdate(reconnectChannelGroupTimerKey, timer, (key, oldState) => timer); + } + } + } + } + + internal bool Reconnect(bool resetSubscribeTimetoken) + { + if (!SubscribeDisconnected[PubnubInstance.InstanceId]) //Check if disconnect is done before + { + return false; + } + + string[] channels = GetCurrentSubscriberChannels(); + string[] chananelGroups = GetCurrentSubscriberChannelGroups(); + + if ((channels != null && channels.Length > 0) || (chananelGroups != null && chananelGroups.Length > 0)) { + string channel = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; + string channelGroup = (chananelGroups != null && chananelGroups.Length > 0) ? string.Join(",", chananelGroups.OrderBy(x => x).ToArray()) : ""; + + bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, PNOperationType.PNSubscribeOperation, null, channels, chananelGroups); + if (!networkConnection) { + //Recheck for false alert with 1 sec delay #if !NET35 && !NET40 - Task.Delay(1000).Wait(); + Task.Delay(1000).Wait(); #else Thread.Sleep(1000); #endif - networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, PNOperationType.PNSubscribeOperation, null, channels, chananelGroups); - } - if (networkConnection) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Network available for SubscribeManager Manual Reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - if (!string.IsNullOrEmpty(channel) && ChannelInternetStatus[PubnubInstance.InstanceId].ContainsKey(channel)) - { - ChannelInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channel, networkConnection, (key, oldValue) => networkConnection); - } - if (!string.IsNullOrEmpty(channelGroup) && ChannelGroupInternetStatus[PubnubInstance.InstanceId].ContainsKey(channelGroup)) - { - ChannelGroupInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channelGroup, networkConnection, (key, oldValue) => networkConnection); - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No network for SubscribeManager Manual Reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - - PNStatusCategory errorCategory = PNStatusCategory.PNNetworkIssuesCategory; - PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(PNOperationType.PNSubscribeOperation, errorCategory, null, (int)HttpStatusCode.NotFound, new PNException("SDK Network related error")); - if (channels != null && channels.Length > 0) - { - status.AffectedChannels.AddRange(channels); - } - if (chananelGroups != null && chananelGroups.Length > 0) - { - status.AffectedChannels.AddRange(chananelGroups); - } - Announce(status); - - return false; - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No channels/channelgroups for SubscribeManager Manual Reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - return false; - } - - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager Manual Reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - SubscribeDisconnected[PubnubInstance.InstanceId] = false; - - Task.Factory.StartNew(() => - { - if (resetSubscribeTimetoken) - { - LastSubscribeTimetoken[PubnubInstance.InstanceId] = 0; - LastSubscribeRegion[PubnubInstance.InstanceId] = 0; - } - MultiChannelSubscribeRequest(PNOperationType.PNSubscribeOperation, GetCurrentSubscriberChannels(), GetCurrentSubscriberChannelGroups(), LastSubscribeTimetoken[PubnubInstance.InstanceId], LastSubscribeRegion[PubnubInstance.InstanceId], false, null, this.customQueryParam); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); - - return true; - } - - internal bool Disconnect() - { - if (SubscribeDisconnected[PubnubInstance.InstanceId]) - { - return false; - } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager Manual Disconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - SubscribeDisconnected[PubnubInstance.InstanceId] = true; - TerminateCurrentSubscriberRequest(); - PubnubCoreBase.TerminatePresenceHeartbeatTimer(); - TerminateReconnectTimer(); - - return true; - } - - internal void StartSubscribeHeartbeatCheckCallback(object state) - { - try - { - if (SubscribeDisconnected[PubnubInstance.InstanceId]) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - SubscribeDisconnected. No heartbeat check.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - return; - } - if (!config.ContainsKey(PubnubInstance.InstanceId)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, InstanceId Not Available. So No heartbeat check.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - return; - } - - string[] channels = GetCurrentSubscriberChannels(); - string[] chananelGroups = GetCurrentSubscriberChannelGroups(); - - if ((channels != null && channels.Length > 0) || (chananelGroups != null && chananelGroups.Length > 0)) - { - bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, PNOperationType.PNSubscribeOperation, null, channels, chananelGroups); - if (networkConnection && PubnubInstance != null && SubscribeRequestTracker.ContainsKey(PubnubInstance.InstanceId)) - { - DateTime lastSubscribeRequestTime = SubscribeRequestTracker[PubnubInstance.InstanceId]; - if ((DateTime.Now - lastSubscribeRequestTime).TotalSeconds < config[PubnubInstance.InstanceId].SubscribeTimeout) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - ok. expected subscribe within threshold limit of SubscribeTimeout. No action needed", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); - } - else if ((DateTime.Now - lastSubscribeRequestTime).TotalSeconds > 2 * (config[PubnubInstance.InstanceId].SubscribeTimeout - config[PubnubInstance.InstanceId].SubscribeTimeout/2)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - **No auto subscribe within threshold limit of SubscribeTimeout**. Calling MultiChannelSubscribeRequest", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); - Task.Factory.StartNew(() => - { - TerminateCurrentSubscriberRequest(); - MultiChannelSubscribeRequest(PNOperationType.PNSubscribeOperation, channels, chananelGroups, LastSubscribeTimetoken[PubnubInstance.InstanceId], LastSubscribeRegion[PubnubInstance.InstanceId], false, null, this.customQueryParam); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - **No auto subscribe within threshold limit of SubscribeTimeout**. Calling TerminateCurrentSubscriberRequest", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); - Task.Factory.StartNew(() => - { - TerminateCurrentSubscriberRequest(); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - StartSubscribeHeartbeatCheckCallback - No network or no pubnub instance mapping", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); - if (PubnubInstance != null && !networkConnection) - { - PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(PNOperationType.PNSubscribeOperation, PNStatusCategory.PNNetworkIssuesCategory, null, (int)System.Net.HttpStatusCode.NotFound, new PNException("Internet connection problem during subscribe heartbeat.")); - if (channels != null && channels.Length > 0) - { - status.AffectedChannels.AddRange(channels.ToList()); - } - if (chananelGroups != null && chananelGroups.Length > 0) - { - status.AffectedChannelGroups.AddRange(chananelGroups.ToList()); - } - Announce(status); - - Task.Factory.StartNew(() => - { - TerminateCurrentSubscriberRequest(); - MultiChannelSubscribeRequest(PNOperationType.PNSubscribeOperation, GetCurrentSubscriberChannels(), GetCurrentSubscriberChannelGroups(), LastSubscribeTimetoken[PubnubInstance.InstanceId], LastSubscribeRegion[PubnubInstance.InstanceId], false, null, this.customQueryParam); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); - } - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - StartSubscribeHeartbeatCheckCallback - No channels/cgs avaialable", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); - try - { - SubscribeHeartbeatCheckTimer.Change(Timeout.Infinite, Timeout.Infinite); - TerminateCurrentSubscriberRequest(); - } - catch { /* ignore */ } - } - } - catch (Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - StartSubscribeHeartbeatCheckCallback - EXCEPTION: {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture),ex), config[PubnubInstance.InstanceId].LogVerbosity); - } - } - - - protected void ReconnectNetworkCallback(System.Object reconnectState) - { - string channel = ""; - string channelGroup = ""; - - ReconnectState netState = reconnectState as ReconnectState; - try - { - string subscribedChannels = (MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelSubscribe[PubnubInstance.InstanceId].Keys.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; - string subscribedChannelGroups = (MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; - List channelRequestKeyList = new List(ChannelRequest[PubnubInstance.InstanceId].Keys); - for(int keyIndex= 0; keyIndex < channelRequestKeyList.Count; keyIndex++) - { - string keyChannel = channelRequestKeyList[keyIndex]; - if (keyChannel != subscribedChannels) - { - if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(keyChannel)) - { - HttpWebRequest keyChannelRequest; - ChannelRequest[PubnubInstance.InstanceId].TryGetValue(keyChannel, out keyChannelRequest); - if (keyChannelRequest != null) - { - try - { - keyChannelRequest.Abort(); - } - catch { /* ignore */ } - ChannelRequest[PubnubInstance.InstanceId].TryUpdate(keyChannel, null, keyChannelRequest); - } - HttpWebRequest tempValue; - ChannelRequest[PubnubInstance.InstanceId].TryRemove(keyChannel, out tempValue); - } - } - } - - - if (netState != null && ((netState.Channels != null && netState.Channels.Length > 0) || (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0))) - { - if (netState.Channels == null) - { - netState.Channels = new string[] { }; - } - - if (netState.ChannelGroups == null) - { - netState.ChannelGroups = new string[] { }; - } - - bool channelInternetFlag; - bool channelGroupInternetFlag; - if (netState.Channels != null && netState.Channels.Length > 0) - { - channel = (netState.Channels.Length > 0) ? string.Join(",", netState.Channels.OrderBy(x=>x).ToArray()) : ","; - channelGroup = (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) ? string.Join(",", netState.ChannelGroups.OrderBy(x => x).ToArray()) : ""; - - if (channel == subscribedChannels && ChannelInternetStatus[PubnubInstance.InstanceId].ContainsKey(channel) - && (netState.ResponseType == PNOperationType.PNSubscribeOperation || netState.ResponseType == PNOperationType.Presence)) - { - bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, netState.ResponseType, netState.PubnubCallback, netState.Channels, netState.ChannelGroups); - if (networkConnection) { - //Re-try to avoid false alert - networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, netState.ResponseType, netState.PubnubCallback, netState.Channels, netState.ChannelGroups); - } - - if (ChannelInternetStatus[PubnubInstance.InstanceId].TryGetValue(channel, out channelInternetFlag) && channelInternetFlag) - { - //do nothing - } - else - { - ChannelInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channel, networkConnection, (key, oldValue) => networkConnection); - if (!string.IsNullOrEmpty(channelGroup) && channelGroup.Length > 0) - { - ChannelGroupInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channelGroup, networkConnection, (key, oldValue) => networkConnection); - } - - ConnectionErrors++; - UpdatePubnubNetworkTcpCheckIntervalInSeconds(); - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, channel={1} {2} reconnectNetworkCallback. Retry", DateTime.Now.ToString(CultureInfo.InvariantCulture), channel, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - - if (netState.Channels != null && netState.Channels.Length > 0) - { - PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, PNStatusCategory.PNNetworkIssuesCategory, null, (int)System.Net.HttpStatusCode.NotFound, new PNException("Internet connection problem. Retrying connection")); - if (netState.Channels != null && netState.Channels.Length > 0) - { - status.AffectedChannels.AddRange(netState.Channels.ToList()); - } - if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) - { - status.AffectedChannelGroups.AddRange(netState.ChannelGroups.ToList()); - } - Announce(status); - } - - } - } - - if (ChannelInternetStatus[PubnubInstance.InstanceId].ContainsKey(channel) && ChannelInternetStatus[PubnubInstance.InstanceId].TryGetValue(channel, out channelInternetFlag) && channelInternetFlag) - { - if (ChannelReconnectTimer[PubnubInstance.InstanceId].ContainsKey(channel)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, {1} {2} terminating ch reconnectimer", DateTime.Now.ToString(CultureInfo.InvariantCulture), channel, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - TerminateReconnectTimer(); - } - - PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, PNStatusCategory.PNReconnectedCategory, null, (int)System.Net.HttpStatusCode.OK, null); - if (netState.Channels != null && netState.Channels.Length > 0) - { - status.AffectedChannels.AddRange(netState.Channels.ToList()); - } - if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) - { - status.AffectedChannelGroups.AddRange(netState.ChannelGroups.ToList()); - } - Announce(status); - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, channel={1} {2} reconnectNetworkCallback. Internet Available : {3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), channel, netState.ResponseType, channelInternetFlag.ToString()), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - switch (netState.ResponseType) - { - case PNOperationType.PNSubscribeOperation: - case PNOperationType.Presence: - MultiChannelSubscribeRequest(netState.ResponseType, netState.Channels, netState.ChannelGroups, netState.Timetoken, netState.Region, true, null, this.customQueryParam); - break; - default: - break; - } - } - } - else if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) - { - channelGroup = string.Join(",", netState.ChannelGroups.OrderBy(x => x).ToArray()); - channel = (netState.Channels != null && netState.Channels.Length > 0) ? string.Join(",", netState.Channels.OrderBy(x => x).ToArray()) : ","; - - if (subscribedChannelGroups == channelGroup && channelGroup != "" && ChannelGroupInternetStatus[PubnubInstance.InstanceId].ContainsKey(channelGroup) - && (netState.ResponseType == PNOperationType.PNSubscribeOperation || netState.ResponseType == PNOperationType.Presence)) - { - bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, netState.ResponseType, netState.PubnubCallback, netState.Channels, netState.ChannelGroups); - if (networkConnection) - { - //Re-try to avoid false alert - networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, netState.ResponseType, netState.PubnubCallback, netState.Channels, netState.ChannelGroups); - } - - if (ChannelGroupInternetStatus[PubnubInstance.InstanceId].TryGetValue(channelGroup, out channelGroupInternetFlag) && channelGroupInternetFlag) - { - //do nothing - } - else - { - ChannelGroupInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channelGroup, networkConnection, (key, oldValue) => networkConnection); - if (!string.IsNullOrEmpty(channel) && channel.Length > 0) - { - ChannelInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channel, networkConnection, (key, oldValue) => networkConnection); - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, channelgroup={1} {2} reconnectNetworkCallback. Retrying", DateTime.Now.ToString(CultureInfo.InvariantCulture), channelGroup, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - - if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) - { - PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, PNStatusCategory.PNReconnectedCategory, null, (int)System.Net.HttpStatusCode.NotFound, new PNException("Internet connection problem. Retrying connection")); - if (netState.Channels != null && netState.Channels.Length > 0) - { - status.AffectedChannels.AddRange(netState.Channels.ToList()); - } - if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) - { - status.AffectedChannelGroups.AddRange(netState.ChannelGroups.ToList()); - } - Announce(status); - } - } - } - - if (ChannelGroupInternetStatus[PubnubInstance.InstanceId].TryGetValue(channelGroup, out channelGroupInternetFlag) && channelGroupInternetFlag) - { - if (ChannelGroupReconnectTimer[PubnubInstance.InstanceId].ContainsKey(channelGroup)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, {1} {2} terminating cg reconnectimer", DateTime.Now.ToString(CultureInfo.InvariantCulture), channelGroup, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - TerminateReconnectTimer(); - } - - //Send one ReConnectedCategory message. If Channels NOT available then use this - if (netState.Channels.Length == 0 && netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) - { - PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, PNStatusCategory.PNReconnectedCategory, null, (int)System.Net.HttpStatusCode.OK, null); - if (netState.Channels != null && netState.Channels.Length > 0) - { - status.AffectedChannels.AddRange(netState.Channels.ToList()); - } - if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) - { - status.AffectedChannelGroups.AddRange(netState.ChannelGroups.ToList()); - } - Announce(status); - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, channelgroup={1} {2} reconnectNetworkCallback. Internet Available", DateTime.Now.ToString(CultureInfo.InvariantCulture), channelGroup, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - switch (netState.ResponseType) - { - case PNOperationType.PNSubscribeOperation: - case PNOperationType.Presence: - MultiChannelSubscribeRequest(netState.ResponseType, netState.Channels, netState.ChannelGroups, netState.Timetoken, netState.Region, true, null, this.customQueryParam); - break; - default: - break; - } - } - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unknown request state in reconnectNetworkCallback", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - } - catch (Exception ex) - { - if (netState != null) - { - PNStatusCategory errorCategory = PNStatusCategoryHelper.GetPNStatusCategory(ex); - PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, errorCategory, null, (int)HttpStatusCode.NotFound, new PNException(ex)); - if (netState.Channels != null && netState.Channels.Length > 0) - { - status.AffectedChannels.AddRange(netState.Channels.ToList()); - } - if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) - { - status.AffectedChannels.AddRange(netState.ChannelGroups.ToList()); - } - Announce(status); - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} method:reconnectNetworkCallback \n Exception Details={1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); - } - } - - private void RegisterPresenceHeartbeatTimer(string[] channels, string[] channelGroups) - { - if (PresenceHeartbeatTimer != null) - { - try - { - PresenceHeartbeatTimer.Change(Timeout.Infinite, Timeout.Infinite); - PresenceHeartbeatTimer.Dispose(); - PresenceHeartbeatTimer = null; - } - catch { /* ignore */ } - } - if ((channels != null && channels.Length > 0 && channels.Where(s => s != null && s.Contains("-pnpres") == false).Any()) - || (channelGroups != null && channelGroups.Length > 0 && channelGroups.Where(s => s != null && s.Contains("-pnpres") == false).Any())) - { - RequestState presenceHeartbeatState = new RequestState(); - presenceHeartbeatState.Channels = channels; - presenceHeartbeatState.ChannelGroups = channelGroups; - presenceHeartbeatState.ResponseType = PNOperationType.PNHeartbeatOperation; - presenceHeartbeatState.Request = null; - presenceHeartbeatState.Response = null; - - if (config.ContainsKey(PubnubInstance.InstanceId) && config[PubnubInstance.InstanceId].PresenceInterval > 0) - { - PresenceHeartbeatTimer = new Timer(OnPresenceHeartbeatIntervalTimeout, presenceHeartbeatState, config[PubnubInstance.InstanceId].PresenceInterval * 1000, config[PubnubInstance.InstanceId].PresenceInterval * 1000); - } - } - } + networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, PNOperationType.PNSubscribeOperation, null, channels, chananelGroups); + } + if (networkConnection) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Network available for SubscribeManager Manual Reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + if (!string.IsNullOrEmpty(channel) && ChannelInternetStatus[PubnubInstance.InstanceId].ContainsKey(channel)) { + ChannelInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channel, networkConnection, (key, oldValue) => networkConnection); + } + if (!string.IsNullOrEmpty(channelGroup) && ChannelGroupInternetStatus[PubnubInstance.InstanceId].ContainsKey(channelGroup)) { + ChannelGroupInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channelGroup, networkConnection, (key, oldValue) => networkConnection); + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No network for SubscribeManager Manual Reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + + PNStatusCategory errorCategory = PNStatusCategory.PNNetworkIssuesCategory; + PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(PNOperationType.PNSubscribeOperation, errorCategory, null, (int)HttpStatusCode.NotFound, new PNException("SDK Network related error")); + if (channels != null && channels.Length > 0) { + status.AffectedChannels.AddRange(channels); + } + if (chananelGroups != null && chananelGroups.Length > 0) { + status.AffectedChannels.AddRange(chananelGroups); + } + Announce(status); + + return false; + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No channels/channelgroups for SubscribeManager Manual Reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + return false; + } + + + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager Manual Reconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + SubscribeDisconnected[PubnubInstance.InstanceId] = false; + + Task.Factory.StartNew(() => { + if (resetSubscribeTimetoken) { + LastSubscribeTimetoken[PubnubInstance.InstanceId] = 0; + LastSubscribeRegion[PubnubInstance.InstanceId] = 0; + } + MultiChannelSubscribeRequest(PNOperationType.PNSubscribeOperation, GetCurrentSubscriberChannels(), GetCurrentSubscriberChannelGroups(), LastSubscribeTimetoken[PubnubInstance.InstanceId], LastSubscribeRegion[PubnubInstance.InstanceId], false, null, this.customQueryParam); + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); + + return true; + } + + internal bool Disconnect() + { + if (SubscribeDisconnected[PubnubInstance.InstanceId]) { + return false; + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager Manual Disconnect", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + SubscribeDisconnected[PubnubInstance.InstanceId] = true; + TerminateCurrentSubscriberRequest(); + PubnubCoreBase.TerminatePresenceHeartbeatTimer(); + TerminateReconnectTimer(); + + return true; + } + + internal void StartSubscribeHeartbeatCheckCallback(object state) + { + try { + if (SubscribeDisconnected[PubnubInstance.InstanceId]) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - SubscribeDisconnected. No heartbeat check.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + return; + } + if (!config.ContainsKey(PubnubInstance.InstanceId)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, InstanceId Not Available. So No heartbeat check.", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + return; + } + + string[] channels = GetCurrentSubscriberChannels(); + string[] chananelGroups = GetCurrentSubscriberChannelGroups(); + + if ((channels != null && channels.Length > 0) || (chananelGroups != null && chananelGroups.Length > 0)) { + bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, PNOperationType.PNSubscribeOperation, null, channels, chananelGroups); + if (networkConnection && PubnubInstance != null && SubscribeRequestTracker.ContainsKey(PubnubInstance.InstanceId)) { + DateTime lastSubscribeRequestTime = SubscribeRequestTracker[PubnubInstance.InstanceId]; + if ((DateTime.Now - lastSubscribeRequestTime).TotalSeconds < config[PubnubInstance.InstanceId].SubscribeTimeout) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - ok. expected subscribe within threshold limit of SubscribeTimeout. No action needed", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); + } else if ((DateTime.Now - lastSubscribeRequestTime).TotalSeconds > 2 * (config[PubnubInstance.InstanceId].SubscribeTimeout - config[PubnubInstance.InstanceId].SubscribeTimeout / 2)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - **No auto subscribe within threshold limit of SubscribeTimeout**. Calling MultiChannelSubscribeRequest", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); + Task.Factory.StartNew(() => { + TerminateCurrentSubscriberRequest(); + MultiChannelSubscribeRequest(PNOperationType.PNSubscribeOperation, channels, chananelGroups, LastSubscribeTimetoken[PubnubInstance.InstanceId], LastSubscribeRegion[PubnubInstance.InstanceId], false, null, this.customQueryParam); + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - **No auto subscribe within threshold limit of SubscribeTimeout**. Calling TerminateCurrentSubscriberRequest", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); + Task.Factory.StartNew(() => { + TerminateCurrentSubscriberRequest(); + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - StartSubscribeHeartbeatCheckCallback - No network or no pubnub instance mapping", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); + if (PubnubInstance != null && !networkConnection) { + PNStatus status = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(PNOperationType.PNSubscribeOperation, PNStatusCategory.PNNetworkIssuesCategory, null, (int)System.Net.HttpStatusCode.NotFound, new PNException("Internet connection problem during subscribe heartbeat.")); + if (channels != null && channels.Length > 0) { + status.AffectedChannels.AddRange(channels.ToList()); + } + if (chananelGroups != null && chananelGroups.Length > 0) { + status.AffectedChannelGroups.AddRange(chananelGroups.ToList()); + } + Announce(status); + + Task.Factory.StartNew(() => { + TerminateCurrentSubscriberRequest(); + MultiChannelSubscribeRequest(PNOperationType.PNSubscribeOperation, GetCurrentSubscriberChannels(), GetCurrentSubscriberChannelGroups(), LastSubscribeTimetoken[PubnubInstance.InstanceId], LastSubscribeRegion[PubnubInstance.InstanceId], false, null, this.customQueryParam); + }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); + } + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - StartSubscribeHeartbeatCheckCallback - No channels/cgs avaialable", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config[PubnubInstance.InstanceId].LogVerbosity); + try { + SubscribeHeartbeatCheckTimer.Change(Timeout.Infinite, Timeout.Infinite); + TerminateCurrentSubscriberRequest(); + } catch { /* ignore */ } + } + } catch (Exception ex) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SubscribeManager - StartSubscribeHeartbeatCheckCallback - EXCEPTION: {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex), config[PubnubInstance.InstanceId].LogVerbosity); + } + } + + + protected void ReconnectNetworkCallback(System.Object reconnectState) + { + string channel = ""; + string channelGroup = ""; + + ReconnectState netState = reconnectState as ReconnectState; + try { + string subscribedChannels = (MultiChannelSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelSubscribe[PubnubInstance.InstanceId].Keys.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; + string subscribedChannelGroups = (MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Count > 0) ? MultiChannelGroupSubscribe[PubnubInstance.InstanceId].Keys.OrderBy(x => x).Aggregate((x, y) => x + "," + y) : ""; + List channelRequestKeyList = new List(ChannelRequest[PubnubInstance.InstanceId].Keys); + for (int keyIndex = 0; keyIndex < channelRequestKeyList.Count; keyIndex++) { + string keyChannel = channelRequestKeyList[keyIndex]; + if (keyChannel != subscribedChannels) { + if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(keyChannel)) { + CancellationTokenSource keyChannelRequest; + ChannelRequest[PubnubInstance.InstanceId].TryGetValue(keyChannel, out keyChannelRequest); + if (keyChannelRequest != null) { + try { + keyChannelRequest.Cancel(); + } catch { /* ignore */ } + ChannelRequest[PubnubInstance.InstanceId].TryUpdate(keyChannel, null, keyChannelRequest); + } + CancellationTokenSource tempValue; + ChannelRequest[PubnubInstance.InstanceId].TryRemove(keyChannel, out tempValue); + } + } + } + + + if (netState != null && ((netState.Channels != null && netState.Channels.Length > 0) || (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0))) { + if (netState.Channels == null) { + netState.Channels = new string[] { }; + } + + if (netState.ChannelGroups == null) { + netState.ChannelGroups = new string[] { }; + } + + bool channelInternetFlag; + bool channelGroupInternetFlag; + if (netState.Channels != null && netState.Channels.Length > 0) { + channel = (netState.Channels.Length > 0) ? string.Join(",", netState.Channels.OrderBy(x => x).ToArray()) : ","; + channelGroup = (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) ? string.Join(",", netState.ChannelGroups.OrderBy(x => x).ToArray()) : ""; + + if (channel == subscribedChannels && ChannelInternetStatus[PubnubInstance.InstanceId].ContainsKey(channel) + && (netState.ResponseType == PNOperationType.PNSubscribeOperation || netState.ResponseType == PNOperationType.Presence)) { + bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, netState.ResponseType, netState.PubnubCallback, netState.Channels, netState.ChannelGroups); + if (networkConnection) { + //Re-try to avoid false alert + networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, netState.ResponseType, netState.PubnubCallback, netState.Channels, netState.ChannelGroups); + } + + if (ChannelInternetStatus[PubnubInstance.InstanceId].TryGetValue(channel, out channelInternetFlag) && channelInternetFlag) { + //do nothing + } else { + ChannelInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channel, networkConnection, (key, oldValue) => networkConnection); + if (!string.IsNullOrEmpty(channelGroup) && channelGroup.Length > 0) { + ChannelGroupInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channelGroup, networkConnection, (key, oldValue) => networkConnection); + } + + ConnectionErrors++; + UpdatePubnubNetworkTcpCheckIntervalInSeconds(); + + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, channel={1} {2} reconnectNetworkCallback. Retry", DateTime.Now.ToString(CultureInfo.InvariantCulture), channel, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + + if (netState.Channels != null && netState.Channels.Length > 0) { + PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, PNStatusCategory.PNNetworkIssuesCategory, null, (int)System.Net.HttpStatusCode.NotFound, new PNException("Internet connection problem. Retrying connection")); + if (netState.Channels != null && netState.Channels.Length > 0) { + status.AffectedChannels.AddRange(netState.Channels.ToList()); + } + if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) { + status.AffectedChannelGroups.AddRange(netState.ChannelGroups.ToList()); + } + Announce(status); + } + + } + } + + if (ChannelInternetStatus[PubnubInstance.InstanceId].ContainsKey(channel) && ChannelInternetStatus[PubnubInstance.InstanceId].TryGetValue(channel, out channelInternetFlag) && channelInternetFlag) { + if (ChannelReconnectTimer[PubnubInstance.InstanceId].ContainsKey(channel)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, {1} {2} terminating ch reconnectimer", DateTime.Now.ToString(CultureInfo.InvariantCulture), channel, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + TerminateReconnectTimer(); + } + + PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, PNStatusCategory.PNReconnectedCategory, null, (int)System.Net.HttpStatusCode.OK, null); + if (netState.Channels != null && netState.Channels.Length > 0) { + status.AffectedChannels.AddRange(netState.Channels.ToList()); + } + if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) { + status.AffectedChannelGroups.AddRange(netState.ChannelGroups.ToList()); + } + Announce(status); + + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, channel={1} {2} reconnectNetworkCallback. Internet Available : {3}", DateTime.Now.ToString(CultureInfo.InvariantCulture), channel, netState.ResponseType, channelInternetFlag.ToString()), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + switch (netState.ResponseType) { + case PNOperationType.PNSubscribeOperation: + case PNOperationType.Presence: + MultiChannelSubscribeRequest(netState.ResponseType, netState.Channels, netState.ChannelGroups, netState.Timetoken, netState.Region, true, null, this.customQueryParam); + break; + default: + break; + } + } + } else if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) { + channelGroup = string.Join(",", netState.ChannelGroups.OrderBy(x => x).ToArray()); + channel = (netState.Channels != null && netState.Channels.Length > 0) ? string.Join(",", netState.Channels.OrderBy(x => x).ToArray()) : ","; + + if (subscribedChannelGroups == channelGroup && channelGroup != "" && ChannelGroupInternetStatus[PubnubInstance.InstanceId].ContainsKey(channelGroup) + && (netState.ResponseType == PNOperationType.PNSubscribeOperation || netState.ResponseType == PNOperationType.Presence)) { + bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, netState.ResponseType, netState.PubnubCallback, netState.Channels, netState.ChannelGroups); + if (networkConnection) { + //Re-try to avoid false alert + networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, netState.ResponseType, netState.PubnubCallback, netState.Channels, netState.ChannelGroups); + } + + if (ChannelGroupInternetStatus[PubnubInstance.InstanceId].TryGetValue(channelGroup, out channelGroupInternetFlag) && channelGroupInternetFlag) { + //do nothing + } else { + ChannelGroupInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channelGroup, networkConnection, (key, oldValue) => networkConnection); + if (!string.IsNullOrEmpty(channel) && channel.Length > 0) { + ChannelInternetStatus[PubnubInstance.InstanceId].AddOrUpdate(channel, networkConnection, (key, oldValue) => networkConnection); + } + + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, channelgroup={1} {2} reconnectNetworkCallback. Retrying", DateTime.Now.ToString(CultureInfo.InvariantCulture), channelGroup, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + + if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) { + PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, PNStatusCategory.PNReconnectedCategory, null, (int)System.Net.HttpStatusCode.NotFound, new PNException("Internet connection problem. Retrying connection")); + if (netState.Channels != null && netState.Channels.Length > 0) { + status.AffectedChannels.AddRange(netState.Channels.ToList()); + } + if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) { + status.AffectedChannelGroups.AddRange(netState.ChannelGroups.ToList()); + } + Announce(status); + } + } + } + + if (ChannelGroupInternetStatus[PubnubInstance.InstanceId].TryGetValue(channelGroup, out channelGroupInternetFlag) && channelGroupInternetFlag) { + if (ChannelGroupReconnectTimer[PubnubInstance.InstanceId].ContainsKey(channelGroup)) { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, {1} {2} terminating cg reconnectimer", DateTime.Now.ToString(CultureInfo.InvariantCulture), channelGroup, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + TerminateReconnectTimer(); + } + + //Send one ReConnectedCategory message. If Channels NOT available then use this + if (netState.Channels.Length == 0 && netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) { + PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, PNStatusCategory.PNReconnectedCategory, null, (int)System.Net.HttpStatusCode.OK, null); + if (netState.Channels != null && netState.Channels.Length > 0) { + status.AffectedChannels.AddRange(netState.Channels.ToList()); + } + if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) { + status.AffectedChannelGroups.AddRange(netState.ChannelGroups.ToList()); + } + Announce(status); + } + + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, channelgroup={1} {2} reconnectNetworkCallback. Internet Available", DateTime.Now.ToString(CultureInfo.InvariantCulture), channelGroup, netState.ResponseType), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + switch (netState.ResponseType) { + case PNOperationType.PNSubscribeOperation: + case PNOperationType.Presence: + MultiChannelSubscribeRequest(netState.ResponseType, netState.Channels, netState.ChannelGroups, netState.Timetoken, netState.Region, true, null, this.customQueryParam); + break; + default: + break; + } + } + } + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Unknown request state in reconnectNetworkCallback", DateTime.Now.ToString(CultureInfo.InvariantCulture)), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } catch (Exception ex) { + if (netState != null) { + PNStatusCategory errorCategory = PNStatusCategoryHelper.GetPNStatusCategory(ex); + PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(netState.ResponseType, errorCategory, null, (int)HttpStatusCode.NotFound, new PNException(ex)); + if (netState.Channels != null && netState.Channels.Length > 0) { + status.AffectedChannels.AddRange(netState.Channels.ToList()); + } + if (netState.ChannelGroups != null && netState.ChannelGroups.Length > 0) { + status.AffectedChannels.AddRange(netState.ChannelGroups.ToList()); + } + Announce(status); + } + + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} method:reconnectNetworkCallback \n Exception Details={1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex), config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].LogVerbosity : PNLogVerbosity.NONE); + } + } + + private void RegisterPresenceHeartbeatTimer(string[] channels, string[] channelGroups) + { + if (PresenceHeartbeatTimer != null) { + try { + PresenceHeartbeatTimer.Change(Timeout.Infinite, Timeout.Infinite); + PresenceHeartbeatTimer.Dispose(); + PresenceHeartbeatTimer = null; + } catch { /* ignore */ } + } + if ((channels != null && channels.Length > 0 && channels.Where(s => s != null && s.Contains("-pnpres") == false).Any()) + || (channelGroups != null && channelGroups.Length > 0 && channelGroups.Where(s => s != null && s.Contains("-pnpres") == false).Any())) { + RequestState presenceHeartbeatState = new RequestState(); + presenceHeartbeatState.Channels = channels; + presenceHeartbeatState.ChannelGroups = channelGroups; + presenceHeartbeatState.ResponseType = PNOperationType.PNHeartbeatOperation; + presenceHeartbeatState.RequestCancellationTokenSource = null; + presenceHeartbeatState.Response = null; + + if (config.ContainsKey(PubnubInstance.InstanceId) && config[PubnubInstance.InstanceId].PresenceInterval > 0) { + PresenceHeartbeatTimer = new Timer(OnPresenceHeartbeatIntervalTimeout, presenceHeartbeatState, config[PubnubInstance.InstanceId].PresenceInterval * 1000, config[PubnubInstance.InstanceId].PresenceInterval * 1000); + } + } + } #pragma warning disable - void OnPresenceHeartbeatIntervalTimeout(System.Object presenceHeartbeatState) + void OnPresenceHeartbeatIntervalTimeout(System.Object presenceHeartbeatState) #pragma warning restore - { - //Make presence heartbeat call - RequestState currentState = presenceHeartbeatState as RequestState; - if (currentState != null) - { - string[] subscriberChannels = (currentState.Channels != null) ? currentState.Channels.Where(s => s.Contains("-pnpres") == false).ToArray() : null; - string[] subscriberChannelGroups = (currentState.ChannelGroups != null) ? currentState.ChannelGroups.Where(s => s.Contains("-pnpres") == false).ToArray() : null; - - bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, currentState.ResponseType, currentState.PubnubCallback, currentState.Channels, currentState.ChannelGroups); - if (networkConnection) - { - if ((subscriberChannels != null && subscriberChannels.Length > 0) || (subscriberChannelGroups != null && subscriberChannelGroups.Length > 0)) - { - string channelsJsonState = BuildJsonUserState(subscriberChannels, subscriberChannelGroups, false); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildPresenceHeartbeatRequest("GET", "", subscriberChannels, subscriberChannelGroups, channelsJsonState); - - RequestState requestState = new RequestState(); - requestState.Channels = currentState.Channels; - requestState.ChannelGroups = currentState.ChannelGroups; - requestState.ResponseType = PNOperationType.PNHeartbeatOperation; - requestState.PubnubCallback = null; - requestState.Reconnect = false; - requestState.Response = null; - requestState.TimeQueued = DateTime.Now; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - } - else - { - if (PubnubInstance != null && !networkConnection) - { - PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(PNOperationType.PNSubscribeOperation, PNStatusCategory.PNNetworkIssuesCategory, null, (int)System.Net.HttpStatusCode.NotFound, new PNException("Internet connection problem during presence heartbeat.")); - if (subscriberChannels != null && subscriberChannels.Length > 0) - { - status.AffectedChannels.AddRange(subscriberChannels.ToList()); - } - if (subscriberChannelGroups != null && subscriberChannelGroups.Length > 0) - { - status.AffectedChannelGroups.AddRange(subscriberChannelGroups.ToList()); - } - Announce(status); - } - - } - } - - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - } - - #region IDisposable Support - private bool disposedValue; - - protected virtual void DisposeInternal(bool disposing) - { - if (!disposedValue) - { - if (SubscribeHeartbeatCheckTimer != null) - { - SubscribeHeartbeatCheckTimer.Dispose(); - } - - disposedValue = true; - } - } - - void IDisposable.Dispose() - { - DisposeInternal(true); - } - #endregion - - } + { + //Make presence heartbeat call + RequestState currentState = presenceHeartbeatState as RequestState; + if (currentState != null) { + string[] subscriberChannels = (currentState.Channels != null) ? currentState.Channels.Where(s => s.Contains("-pnpres") == false).ToArray() : null; + string[] subscriberChannelGroups = (currentState.ChannelGroups != null) ? currentState.ChannelGroups.Where(s => s.Contains("-pnpres") == false).ToArray() : null; + + bool networkConnection = CheckInternetConnectionStatus(PubnetSystemActive, currentState.ResponseType, currentState.PubnubCallback, currentState.Channels, currentState.ChannelGroups); + if (networkConnection) { + if ((subscriberChannels != null && subscriberChannels.Length > 0) || (subscriberChannelGroups != null && subscriberChannelGroups.Length > 0)) { + RequestState requestState = new RequestState(); + requestState.Channels = currentState.Channels; + requestState.ChannelGroups = currentState.ChannelGroups; + requestState.ResponseType = PNOperationType.PNHeartbeatOperation; + requestState.PubnubCallback = null; + requestState.Reconnect = false; + requestState.Response = null; + requestState.TimeQueued = DateTime.Now; + var heartbeatRequestParameter = CreateHeartbeatRequestParameter(subscriberChannels, subscriberChannelGroups); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: heartbeatRequestParameter, operationType: PNOperationType.PNHeartbeatOperation); + PNStatus responseStatus; + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + List result = ProcessJsonResponse(requestState, responseString); + responseStatus = new StatusBuilder(config[PubnubInstance.InstanceId], jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, 200, null); + ProcessResponseCallbacks(result, requestState); + } else { + responseStatus = errorStatus; + ProcessResponseCallbacks(default, requestState); + } + } + }, TaskContinuationOptions.ExecuteSynchronously).Wait(); + } + } else { + if (PubnubInstance != null && !networkConnection) { + PNStatus status = new StatusBuilder(config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId] : null, jsonLibrary).CreateStatusResponse(PNOperationType.PNSubscribeOperation, PNStatusCategory.PNNetworkIssuesCategory, null, (int)System.Net.HttpStatusCode.NotFound, new PNException("Internet connection problem during presence heartbeat.")); + if (subscriberChannels != null && subscriberChannels.Length > 0) { + status.AffectedChannels.AddRange(subscriberChannels.ToList()); + } + if (subscriberChannelGroups != null && subscriberChannelGroups.Length > 0) { + status.AffectedChannelGroups.AddRange(subscriberChannelGroups.ToList()); + } + Announce(status); + } + } + } + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + } + + private RequestParameter CreateLeaveRequestParameter(string[] channels, string[] channelGroups) + { + string channleString = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; + List pathSegments = new List + { + "v2", + "presence", + "sub_key", + config[PubnubInstance.InstanceId].SubscribeKey, + "channel", + channleString, + "leave" + }; + + var requestQueryStringParams = new Dictionary(); + + if (channelGroups != null && channelGroups.Length > 0) { + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(string.Join(",", channelGroups.OrderBy(x => x).ToArray()), PNOperationType.Leave, false, false, false)); + } + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + + private RequestParameter CreateHeartbeatRequestParameter(string[] channels, string[] channelGroups) + { + string channelString = (channels != null && channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; + List pathSegments = new List + { + "v2", + "presence", + "sub_key", + config[PubnubInstance.InstanceId].SubscribeKey, + "channel", + channelString, + "heartbeat" + }; + string presenceState = string.Empty; + + presenceState = BuildJsonUserState(channels, channelGroups, false); + Dictionary requestQueryStringParams = new Dictionary(); + + string channelsJsonState = presenceState; + if (channelsJsonState != "{}" && channelsJsonState != string.Empty) { + requestQueryStringParams.Add("state", UriUtil.EncodeUriComponent(channelsJsonState, PNOperationType.PNHeartbeatOperation, false, false, false)); + } + + if (channelGroups != null && channelGroups.Length > 0) { + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(string.Join(",", channelGroups.OrderBy(x => x).ToArray()), PNOperationType.PNHeartbeatOperation, false, false, false)); + } + + if (config[PubnubInstance.InstanceId].PresenceTimeout != 0) { + requestQueryStringParams.Add("heartbeat", config[PubnubInstance.InstanceId].PresenceTimeout.ToString(CultureInfo.InvariantCulture)); + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + + private RequestParameter CreateSubscribeRequestParameter(string[] channels, string[] channelGroups, long timetoken, int region, string stateJsonValue, Dictionary initialSubscribeUrlParams, Dictionary externalQueryParam) + { + string channelsSegment = (channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; + List pathSegments = new List + { + "v2", + "subscribe", + config.ContainsKey(PubnubInstance.InstanceId) ? config[PubnubInstance.InstanceId].SubscribeKey : "", + channelsSegment, + "0" + }; + + Dictionary internalInitialSubscribeUrlParams = new Dictionary(); + if (initialSubscribeUrlParams != null) { + internalInitialSubscribeUrlParams = initialSubscribeUrlParams; + } + + Dictionary requestQueryStringParams = new Dictionary(internalInitialSubscribeUrlParams); + + if (!requestQueryStringParams.ContainsKey("filter-expr") && config.ContainsKey(PubnubInstance.InstanceId) && !string.IsNullOrEmpty(config[PubnubInstance.InstanceId].FilterExpression)) { + requestQueryStringParams.Add("filter-expr", UriUtil.EncodeUriComponent(config[PubnubInstance.InstanceId].FilterExpression, PNOperationType.PNSubscribeOperation, false, false, false)); + } + + if (!requestQueryStringParams.ContainsKey("ee") && config.ContainsKey(PubnubInstance.InstanceId) && config[PubnubInstance.InstanceId].EnableEventEngine) { + requestQueryStringParams.Add("ee", ""); + } + + if (!requestQueryStringParams.ContainsKey("tt")) { + requestQueryStringParams.Add("tt", timetoken.ToString(CultureInfo.InvariantCulture)); + } + + if (!requestQueryStringParams.ContainsKey("tr") && region > 0) { + requestQueryStringParams.Add("tr", region.ToString(CultureInfo.InvariantCulture)); + } + + if (config.ContainsKey(PubnubInstance.InstanceId) && config[PubnubInstance.InstanceId].PresenceTimeout != 0) { + requestQueryStringParams.Add("heartbeat", config[PubnubInstance.InstanceId].PresenceTimeout.ToString(CultureInfo.InvariantCulture)); + } + + if (channelGroups != null && channelGroups.Length > 0 && channelGroups[0] != "") { + requestQueryStringParams.Add("channel-group", UriUtil.EncodeUriComponent(string.Join(",", channelGroups.OrderBy(x => x).ToArray()), PNOperationType.PNSubscribeOperation, false, false, false)); + } + + if (stateJsonValue != "{}" && stateJsonValue != "") { + requestQueryStringParams.Add("state", UriUtil.EncodeUriComponent(stateJsonValue, PNOperationType.PNSubscribeOperation, false, false, false)); + } + + if (externalQueryParam != null && externalQueryParam.Count > 0) { + foreach (KeyValuePair kvp in externalQueryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNSubscribeOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams, + }; + return requestParameter; + } + + #region IDisposable Support + private bool disposedValue; + + protected virtual void DisposeInternal(bool disposing) + { + if (!disposedValue) { + if (SubscribeHeartbeatCheckTimer != null) { + SubscribeHeartbeatCheckTimer.Dispose(); + } + + disposedValue = true; + } + } + + void IDisposable.Dispose() + { + DisposeInternal(true); + } + #endregion + + } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager2.cs b/src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager2.cs index d6c809293..5bd543684 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager2.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager2.cs @@ -22,7 +22,6 @@ internal class SubscribeManager2 : IDisposable private IJsonPluggableLibrary jsonLibrary; private IPubnubUnitTest unit; private IPubnubLog pubnubLog; - private EndPoint.TelemetryManager pubnubTelemetryMgr; private IPubnubHttp pubnubHttp; private Timer SubscribeHeartbeatCheckTimer; @@ -34,13 +33,12 @@ internal class SubscribeManager2 : IDisposable #else private HttpWebRequest httpSubscribe { get; set; } #endif - public SubscribeManager2(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) + public SubscribeManager2(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; //PubnubInstance = instance; #if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 @@ -86,9 +84,9 @@ public SubscribeManager2(PNConfiguration pubnubConfig, IJsonPluggableLibrary jso httpNonsubscribe.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); httpNonsubscribe.Timeout = TimeSpan.FromSeconds(config.NonSubscribeRequestTimeout); } - pubnubHttp = new PubnubHttp(config, jsonLibrary, log, pubnubTelemetryMgr, httpSubscribe, httpNonsubscribe); + //pubnubHttp = new PubnubHttp(config, jsonLibrary, log, httpSubscribe, httpNonsubscribe); #else - pubnubHttp = new PubnubHttp(config, jsonLibrary, log, pubnubTelemetryMgr); + pubnubHttp = new PubnubHttp(config, jsonLibrary, log); #endif } @@ -99,8 +97,8 @@ public async Task> HandshakeRequest(PNOperati string presenceState = string.Empty; if (config.MaintainPresenceState) presenceState = BuildJsonUserState(channels, channelGroups, true); - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, ""); - Uri request = urlBuilder.BuildMultiChannelSubscribeRequest("GET", "", channels, channelGroups, timetoken.GetValueOrDefault(), region.GetValueOrDefault(), presenceState, initialSubscribeUrlParams, externalQueryParam); + IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, null, ""); + Uri request = urlBuilder.BuildMultiChannelSubscribeRequest(Constants.GET, "", channels, channelGroups, timetoken.GetValueOrDefault(), region.GetValueOrDefault(), presenceState, initialSubscribeUrlParams, externalQueryParam); RequestState pubnubRequestState = new RequestState(); pubnubRequestState.Channels = channels; @@ -153,8 +151,8 @@ internal async Task, PNStatus>> ReceiveRequest> pubnubRequestState = new RequestState>(); pubnubRequestState.Channels = channels; diff --git a/src/Api/PubnubApi/EndPoint/PubSub/SubscribeOperation.cs b/src/Api/PubnubApi/EndPoint/PubSub/SubscribeOperation.cs index a5c129c0a..e5ededea9 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/SubscribeOperation.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/SubscribeOperation.cs @@ -1,24 +1,19 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading; -using System.Threading.Tasks; -using System.Net; using System.Globalization; -#if !NET35 && !NET40 using System.Collections.Concurrent; -#endif + namespace PubnubApi.EndPoint { - public class SubscribeOperation : PubnubCoreBase, ISubscribeOperation + public class SubscribeOperation : PubnubCoreBase, ISubscribeOperation { private readonly PNConfiguration config; private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; private readonly EndPoint.TokenManager pubnubTokenMgr; private List subscribeChannelNames = new List(); @@ -28,13 +23,12 @@ public class SubscribeOperation : PubnubCoreBase, ISubscribeOperation private SubscribeManager manager; private Dictionary queryParam; - public SubscribeOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public SubscribeOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; pubnubTokenMgr = tokenManager; PubnubInstance = instance; @@ -48,7 +42,7 @@ public SubscribeOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary js } if (!ChannelRequest.ContainsKey(instance.InstanceId)) { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); } if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { @@ -210,14 +204,14 @@ private void Subscribe(string[] channels, string[] channelGroups, Dictionary { - manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, pubnubTokenMgr, PubnubInstance); + manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTokenMgr, PubnubInstance); manager.CurrentPubnubInstance(PubnubInstance); manager.MultiChannelSubscribeInit(PNOperationType.PNSubscribeOperation, channels, channelGroups, initialSubscribeUrlParams, externalQueryParam); }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); #else new Thread(() => { - manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, pubnubTokenMgr, PubnubInstance); + manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTokenMgr, PubnubInstance); manager.CurrentPubnubInstance(PubnubInstance); manager.MultiChannelSubscribeInit(PNOperationType.PNSubscribeOperation, channels, channelGroups, initialSubscribeUrlParams, externalQueryParam); }) diff --git a/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeAllEndpoint.cs b/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeAllEndpoint.cs index c483698e4..4e46bb0eb 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeAllEndpoint.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeAllEndpoint.cs @@ -9,19 +9,17 @@ public class UnsubscribeAllEndpoint: UnsubscribeAllOperation private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryManager; private readonly EndPoint.TokenManager pubnubTokenManager; private readonly SubscribeEventEngineFactory subscribeEventEngineFactory; private readonly PresenceEventEngineFactory presenceEventEngineFactory; private readonly string instanceId; - public UnsubscribeAllEndpoint(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, SubscribeEventEngineFactory subscribeEventEngineFactory, PresenceEventEngineFactory presenceEventEngineFactory ,Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public UnsubscribeAllEndpoint(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, SubscribeEventEngineFactory subscribeEventEngineFactory, PresenceEventEngineFactory presenceEventEngineFactory ,Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryManager = telemetryManager; pubnubTokenManager = tokenManager; this.subscribeEventEngineFactory = subscribeEventEngineFactory; this.presenceEventEngineFactory = presenceEventEngineFactory; diff --git a/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeAllOperation.cs b/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeAllOperation.cs index 6d507649d..8810bf903 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeAllOperation.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeAllOperation.cs @@ -1,31 +1,24 @@ -using System; -using System.Collections.Generic; -using System.Net; +using System.Collections.Generic; using System.Threading; -using System.Threading.Tasks; -#if !NET35 && !NET40 using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class UnsubscribeAllOperation : PubnubCoreBase + public class UnsubscribeAllOperation : PubnubCoreBase { private readonly PNConfiguration config; private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; private readonly EndPoint.TokenManager pubnubTokenMgr; private Dictionary queryParam; - public UnsubscribeAllOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public UnsubscribeAllOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; pubnubTokenMgr = tokenManager; CurrentPubnubInstance(instance); @@ -43,14 +36,14 @@ private void UnsubscribeAll() #if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 Task.Factory.StartNew(() => { - SubscribeManager manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, pubnubTokenMgr, PubnubInstance); + SubscribeManager manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTokenMgr, PubnubInstance); manager.CurrentPubnubInstance(PubnubInstance); manager.MultiChannelUnSubscribeAll(PNOperationType.PNUnsubscribeOperation, this.queryParam); }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); #else new Thread(() => { - SubscribeManager manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, pubnubTokenMgr, PubnubInstance); + SubscribeManager manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTokenMgr, PubnubInstance); manager.CurrentPubnubInstance(PubnubInstance); manager.MultiChannelUnSubscribeAll(PNOperationType.PNUnsubscribeOperation, this.queryParam); }) @@ -64,7 +57,7 @@ internal void CurrentPubnubInstance(Pubnub instance) if (!ChannelRequest.ContainsKey(instance.InstanceId)) { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); } if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { diff --git a/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeEndpoint.cs b/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeEndpoint.cs index 4417ed2a3..0352926b2 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeEndpoint.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeEndpoint.cs @@ -5,8 +5,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; -using System.Threading; namespace PubnubApi.EndPoint { @@ -16,7 +14,6 @@ public class UnsubscribeEndpoint : PubnubCoreBase, IUnsubscribeOperation private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; private readonly EndPoint.TokenManager pubnubTokenMgr; private string[] subscribeChannelNames; @@ -28,14 +25,13 @@ public class UnsubscribeEndpoint : PubnubCoreBase, IUnsubscribeOperation private PresenceEventEngineFactory presenceEventEngineFactory; private string instanceId { get; set; } - public UnsubscribeEndpoint(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, SubscribeEventEngineFactory subscribeEventEngineFactory, PresenceEventEngineFactory presenceEventEngineFactory, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public UnsubscribeEndpoint(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, SubscribeEventEngineFactory subscribeEventEngineFactory, PresenceEventEngineFactory presenceEventEngineFactory, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { pubnubInstance = instance; config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; pubnubTokenMgr = tokenManager; this.subscribeEventEngineFactory = subscribeEventEngineFactory; this.presenceEventEngineFactory = presenceEventEngineFactory; @@ -78,28 +74,62 @@ private void Unsubscribe(string[] channels, string[] channelGroups) if (this.subscribeEventEngineFactory.HasEventEngine(instanceId)) { subscribeEventEngine = subscribeEventEngineFactory.GetEventEngine(instanceId); - subscribeEventEngine.Unsubscribe(channels, channelGroups); - } else { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, $"DateTime {DateTime.Now.ToString(CultureInfo.InvariantCulture)}, Attempted Unsubscribe without EventEngine subscribe."), config.LogVerbosity); - } - if (config.PresenceInterval > 0 && presenceEventEngineFactory.HasEventEngine(instanceId)) { - PresenceEventEngine presenceEventEngine = presenceEventEngineFactory.GetEventEngine(instanceId); - presenceEventEngine.EventQueue.Enqueue(new EventEngine.Presence.Events.LeftEvent() { Input = new EventEngine.Presence.Common.PresenceInput() { Channels = channels, ChannelGroups = channelGroups } }); - } - if (config.MaintainPresenceState) { - if (ChannelLocalUserState.TryGetValue(PubnubInstance.InstanceId, out - var userState)) { - foreach (var channelName in channels ?? new string[0]) { - userState.TryRemove(channelName, out _); - } + channels = channels ?? new string[] { }; + channelGroups = channelGroups ?? new string[] { }; + var channelsWithPresence = channels.Concat(channels.Select((c) => $"{c}{Constants.Pnpres}")).ToList(); + var filteredChannelNames = new List(subscribeEventEngine.Channels); + foreach (var c in channelsWithPresence) { + filteredChannelNames.Remove(c); } - if (ChannelGroupLocalUserState.TryGetValue(PubnubInstance.InstanceId, out - var channelGroupUserState)) { - foreach (var channelGroupName in channelGroups ?? new string[0]) { - channelGroupUserState.TryRemove(channelGroupName, out _); + var channelGroupsWithPresence = channelGroups.Concat(channelGroups.Select((cg) => $"{cg}{Constants.Pnpres}")).ToList(); + var filteredChannelGroupNames = new List(subscribeEventEngine.ChannelGroups); + foreach (var g in channelGroupsWithPresence) { + filteredChannelGroupNames.Remove(g); + } + if (subscribeEventEngine.Channels.Distinct().Count() != filteredChannelNames.Distinct().Count() || + subscribeEventEngine.ChannelGroups.Distinct().Count() != filteredChannelGroupNames.Distinct().Count()) { + + var channelsToRemove = FindUniqueCommonElements(subscribeEventEngine.Channels, channels.ToList()); + var channelGroupsToRemove = FindUniqueCommonElements(subscribeEventEngine.ChannelGroups, channelGroups.ToList()); + + subscribeEventEngine.Unsubscribe(channelsToRemove.ToArray(), channelGroupsToRemove.ToArray()); + + if (config.PresenceInterval > 0 && presenceEventEngineFactory.HasEventEngine(instanceId)) { + PresenceEventEngine presenceEventEngine = presenceEventEngineFactory.GetEventEngine(instanceId); + presenceEventEngine.EventQueue.Enqueue(new EventEngine.Presence.Events.LeftEvent() { Input = new EventEngine.Presence.Common.PresenceInput() { Channels = channelsToRemove.ToArray(), ChannelGroups = channelGroupsToRemove.ToArray() } }); } + if (config.MaintainPresenceState) { + if (ChannelLocalUserState.TryGetValue(PubnubInstance.InstanceId, out + var userState)) { + foreach (var channelName in channels ?? new string[0]) { + userState.TryRemove(channelName, out _); + } + } + if (ChannelGroupLocalUserState.TryGetValue(PubnubInstance.InstanceId, out + var channelGroupUserState)) { + foreach (var channelGroupName in channelGroups ?? new string[0]) { + channelGroupUserState.TryRemove(channelGroupName, out _); + } + } + } + } else { + subscribeEventEngine.Channels = filteredChannelNames; + subscribeEventEngine.ChannelGroups = filteredChannelGroupNames; } + + } else { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, $"DateTime {DateTime.Now.ToString(CultureInfo.InvariantCulture)}, Attempted Unsubscribe without EventEngine subscribe."), config.LogVerbosity); } + + } + + private IEnumerable FindUniqueCommonElements(List a, List b) + { + return a + .Where(value => + b.Contains(value) && + a.IndexOf(value) == a.LastIndexOf(value) && + b.IndexOf(value) == b.LastIndexOf(value)); } } } diff --git a/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeOperation.cs b/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeOperation.cs index 1bbc9990a..3ca26bc3f 100644 --- a/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeOperation.cs +++ b/src/Api/PubnubApi/EndPoint/PubSub/UnsubscribeOperation.cs @@ -2,36 +2,30 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Net; using System.Threading; using System.Threading.Tasks; using PubnubApi.Interface; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class UnsubscribeOperation : PubnubCoreBase, IUnsubscribeOperation + public class UnsubscribeOperation : PubnubCoreBase, IUnsubscribeOperation { private readonly PNConfiguration config; private readonly IJsonPluggableLibrary jsonLibrary; private readonly IPubnubUnitTest unit; private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - private readonly EndPoint.TokenManager pubnubTokenMgr; + private readonly TokenManager pubnubTokenMgr; private string[] subscribeChannelNames; private string[] subscribeChannelGroupNames; private Dictionary queryParam; - public UnsubscribeOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) + public UnsubscribeOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) { config = pubnubConfig; jsonLibrary = jsonPluggableLibrary; unit = pubnubUnit; pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; pubnubTokenMgr = tokenManager; } @@ -73,14 +67,14 @@ private void Unsubscribe(string[] channels, string[] channelGroups) #if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 Task.Factory.StartNew(() => { - SubscribeManager manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, pubnubTokenMgr, PubnubInstance); + SubscribeManager manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTokenMgr, PubnubInstance); manager.CurrentPubnubInstance(PubnubInstance); manager.MultiChannelUnSubscribeInit(PNOperationType.PNUnsubscribeOperation, channel, channelGroup, this.queryParam); }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); #else new Thread(() => { - SubscribeManager manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, pubnubTokenMgr, PubnubInstance); + SubscribeManager manager = new SubscribeManager(config, jsonLibrary, unit, pubnubLog, pubnubTokenMgr, PubnubInstance); manager.CurrentPubnubInstance(PubnubInstance); manager.MultiChannelUnSubscribeInit(PNOperationType.PNUnsubscribeOperation, channel, channelGroup, this.queryParam); }) @@ -91,27 +85,6 @@ private void Unsubscribe(string[] channels, string[] channelGroups) internal void CurrentPubnubInstance(Pubnub instance) { PubnubInstance = instance; - - if (!MultiChannelSubscribe.ContainsKey(instance.InstanceId)) - { - MultiChannelSubscribe.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!MultiChannelGroupSubscribe.ContainsKey(instance.InstanceId)) - { - MultiChannelGroupSubscribe.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } } } } diff --git a/src/Api/PubnubApi/EndPoint/Push/AddPushChannelOperation.cs b/src/Api/PubnubApi/EndPoint/Push/AddPushChannelOperation.cs index 3c3f2a2c8..81f0e738d 100644 --- a/src/Api/PubnubApi/EndPoint/Push/AddPushChannelOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Push/AddPushChannelOperation.cs @@ -3,230 +3,239 @@ using System.Linq; using System.Net; using System.Threading.Tasks; -using System.Threading; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Text; namespace PubnubApi.EndPoint { - public class AddPushChannelOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNPushType pubnubPushType; - private string[] channelNames; - private string deviceTokenId = ""; - private PushEnvironment pushEnvironment = PushEnvironment.Development; - private string deviceTopic = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public AddPushChannelOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - - public AddPushChannelOperation PushType(PNPushType pushType) - { - this.pubnubPushType = pushType; - return this; - } - - public AddPushChannelOperation DeviceId(string deviceId) - { - this.deviceTokenId = deviceId; - return this; - } - - public AddPushChannelOperation Channels(string[] channels) - { - this.channelNames = channels; - return this; - } - - /// - /// Applies to APNS2 Only. Default = Development - /// - /// - /// - public AddPushChannelOperation Environment(PushEnvironment environment) - { - this.pushEnvironment = environment; - return this; - } - - /// - /// Applies to APNS2 Only - /// - /// - /// - public AddPushChannelOperation Topic(string deviceTopic) - { - this.deviceTopic = deviceTopic; - return this; - } - - public AddPushChannelOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - RegisterDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - RegisterDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await RegisterDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - RegisterDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - RegisterDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void RegisterDevice(string[] channels, PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam, PNCallback callback) - { - if (channels == null || channels.Length == 0 || channels[0] == null || channels[0].Trim().Length == 0) - { - throw new ArgumentException("Missing Channel"); - } - - if (pushToken == null) - { - throw new ArgumentException("Missing deviceId"); - } - - if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) - { - throw new ArgumentException("Missing Topic"); - } - - string channel = string.Join(",", channels.OrderBy(x => x).ToArray()); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildRegisterDevicePushRequest("GET", "", channel, pushType, pushToken, environment, deviceTopic, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new [] { channel }; - requestState.ResponseType = PNOperationType.PushRegister; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> RegisterDevice(string[] channels, PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam) - { - if (channels == null || channels.Length == 0 || channels[0] == null || channels[0].Trim().Length == 0) - { - throw new ArgumentException("Missing Channel"); - } - - if (pushToken == null) - { - throw new ArgumentException("Missing deviceId"); - } - - if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) - { - throw new ArgumentException("Missing Topic"); - } - PNResult ret = new PNResult(); - - string channel = string.Join(",", channels.OrderBy(x => x).ToArray()); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildRegisterDevicePushRequest("GET", "", channel, pushType, pushToken, environment, deviceTopic, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PushRegister; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNPushAddChannelResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - } + public class AddPushChannelOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNPushType pubnubPushType; + private string[] channelNames; + private string deviceTokenId = ""; + private PushEnvironment pushEnvironment = PushEnvironment.Development; + private string deviceTopic = ""; + private PNCallback savedCallback; + private Dictionary queryParam; + + public AddPushChannelOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + PubnubInstance = instance; + } + + public AddPushChannelOperation PushType(PNPushType pushType) + { + this.pubnubPushType = pushType; + return this; + } + + public AddPushChannelOperation DeviceId(string deviceId) + { + this.deviceTokenId = deviceId; + return this; + } + + public AddPushChannelOperation Channels(string[] channels) + { + this.channelNames = channels; + return this; + } + + /// + /// Applies to APNS2 Only. Default = Development + /// + /// + /// + public AddPushChannelOperation Environment(PushEnvironment environment) + { + this.pushEnvironment = environment; + return this; + } + + /// + /// Applies to APNS2 Only + /// + /// + /// + public AddPushChannelOperation Topic(string deviceTopic) + { + this.deviceTopic = deviceTopic; + return this; + } + + public AddPushChannelOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + RegisterDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await RegisterDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam); + } + + internal void Retry() + { + RegisterDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); + } + + internal void RegisterDevice(string[] channels, PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam, PNCallback callback) + { + if (channels == null || channels.Length == 0 || channels[0] == null || channels[0].Trim().Length == 0) { + throw new ArgumentException("Missing Channel"); + } + + if (pushToken == null) { + throw new ArgumentException("Missing deviceId"); + } + + if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) { + throw new ArgumentException("Missing Topic"); + } + string channel = string.Join(",", channels.OrderBy(x => x).ToArray()); + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PushRegister; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PushRegister); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PushRegister, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNPushAddChannelResult), status); + } + }); + } + + internal async Task> RegisterDevice(string[] channels, PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam) + { + if (channels == null || channels.Length == 0 || channels[0] == null || channels[0].Trim().Length == 0) { + throw new ArgumentException("Missing Channel"); + } + + if (pushToken == null) { + throw new ArgumentException("Missing deviceId"); + } + + if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) { + throw new ArgumentException("Missing Topic"); + } + string channel = string.Join(",", channels.OrderBy(x => x).ToArray()); + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PushRegister; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PushRegister); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNPushAddChannelResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PushRegister, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = pubnubPushType == PNPushType.APNS2 ? new List() { + "v2", + "push", + "sub-key", + config.SubscribeKey, + "devices-apns2", + deviceTokenId + } : new List() { + "v1", + "push", + "sub-key", + config.SubscribeKey, + "devices", + deviceTokenId + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (pubnubPushType == PNPushType.APNS2) { + requestQueryStringParams.Add("environment", pushEnvironment.ToString().ToLowerInvariant()); + requestQueryStringParams.Add("topic", UriUtil.EncodeUriComponent(deviceTopic, PNOperationType.PushRegister, false, false, false)); + } else { + requestQueryStringParams.Add("type", pubnubPushType.ToString().ToLowerInvariant()); + } + requestQueryStringParams.Add("add", UriUtil.EncodeUriComponent(string.Join(",", channelNames.OrderBy(x => x).ToArray()), PNOperationType.PushRegister, false, false, false)); + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PushRegister, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Push/AuditPushChannelOperation.cs b/src/Api/PubnubApi/EndPoint/Push/AuditPushChannelOperation.cs index 4b23a95cf..6b68c046c 100644 --- a/src/Api/PubnubApi/EndPoint/Push/AuditPushChannelOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Push/AuditPushChannelOperation.cs @@ -1,211 +1,226 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Text; namespace PubnubApi.EndPoint { - public class AuditPushChannelOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNPushType pubnubPushType; - private string deviceTokenId = ""; - private PushEnvironment pushEnvironment = PushEnvironment.Development; - private string deviceTopic = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public AuditPushChannelOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public AuditPushChannelOperation PushType(PNPushType pushType) - { - this.pubnubPushType = pushType; - return this; - } - - public AuditPushChannelOperation DeviceId(string deviceId) - { - this.deviceTokenId = deviceId; - return this; - } - - /// - /// Applies to APNS2 Only. Default = Development - /// - /// - /// - public AuditPushChannelOperation Environment(PushEnvironment environment) - { - this.pushEnvironment = environment; - return this; - } - - /// - /// Applies to APNS2 Only - /// - /// - /// - public AuditPushChannelOperation Topic(string deviceTopic) - { - this.deviceTopic = deviceTopic; - return this; - } - - public AuditPushChannelOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - GetChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - GetChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await GetChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - GetChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - GetChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void GetChannelsForDevice(PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam, PNCallback callback) - { - if (pushToken == null) - { - throw new ArgumentException("Missing Uri"); - } - - if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) - { - throw new ArgumentException("Missing Topic"); - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetChannelsPushRequest("GET", "", pushType, pushToken, environment, deviceTopic, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PushGet; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> GetChannelsForDevice(PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam) - { - if (pushToken == null) - { - throw new ArgumentException("Missing Uri"); - } - - if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) - { - throw new ArgumentException("Missing Topic"); - } - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildGetChannelsPushRequest("GET", "", pushType, pushToken, environment, deviceTopic, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PushGet; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNPushListProvisionsResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class AuditPushChannelOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNPushType pubnubPushType; + private string deviceTokenId = string.Empty; + private PushEnvironment pushEnvironment = PushEnvironment.Development; + private string deviceTopic = string.Empty; + private PNCallback savedCallback; + private Dictionary queryParam; + + public AuditPushChannelOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public AuditPushChannelOperation PushType(PNPushType pushType) + { + this.pubnubPushType = pushType; + return this; + } + + public AuditPushChannelOperation DeviceId(string deviceId) + { + this.deviceTokenId = deviceId; + return this; + } + + /// + /// Applies to APNS2 Only. Default = Development + /// + /// + /// + public AuditPushChannelOperation Environment(PushEnvironment environment) + { + this.pushEnvironment = environment; + return this; + } + + /// + /// Applies to APNS2 Only + /// + /// + /// + public AuditPushChannelOperation Topic(string deviceTopic) + { + this.deviceTopic = deviceTopic; + return this; + } + + public AuditPushChannelOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + GetChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await GetChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam); + } + + internal void Retry() + { + GetChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); + } + + internal void GetChannelsForDevice(PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam, PNCallback callback) + { + if (pushToken == null) { + throw new ArgumentException("Missing Uri"); + } + + if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) { + throw new ArgumentException("Missing Topic"); + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PushGet; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PushGet); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PushGet, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNPushListProvisionsResult), status); + } + }); + } + + internal async Task> GetChannelsForDevice(PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam) + { + if (pushToken == null) { + throw new ArgumentException("Missing Uri"); + } + + if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) { + throw new ArgumentException("Missing Topic"); + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PushGet; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + PNResult returnValue = new PNResult(); + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PushGet); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNPushListProvisionsResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PushGet, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = pubnubPushType == PNPushType.APNS2 ? new List + { + "v2", + "push", + "sub-key", + config.SubscribeKey, + "devices-apns2", + deviceTokenId + } : new List + { + "v1", + "push", + "sub-key", + config.SubscribeKey, + "devices", + deviceTokenId + }; + + + + Dictionary requestQueryStringParams = new Dictionary(); + + if (pubnubPushType == PNPushType.APNS2) { + requestQueryStringParams.Add("environment", pushEnvironment.ToString().ToLowerInvariant()); + requestQueryStringParams.Add("topic", UriUtil.EncodeUriComponent(deviceTopic, PNOperationType.PushGet, false, false, false)); + } else { + requestQueryStringParams.Add("type", pubnubPushType.ToString().ToLowerInvariant()); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PushGet, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Push/RemoveAllPushChannelsOperation.cs b/src/Api/PubnubApi/EndPoint/Push/RemoveAllPushChannelsOperation.cs index dd90ab6ee..ba069badd 100644 --- a/src/Api/PubnubApi/EndPoint/Push/RemoveAllPushChannelsOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Push/RemoveAllPushChannelsOperation.cs @@ -1,211 +1,224 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using System.Threading; -using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +using System.Text; namespace PubnubApi.EndPoint { - public class RemoveAllPushChannelsOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNPushType pubnubPushType; - private string deviceTokenId = ""; - private PushEnvironment pushEnvironment = PushEnvironment.Development; - private string deviceTopic = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public RemoveAllPushChannelsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public RemoveAllPushChannelsOperation PushType(PNPushType pushType) - { - this.pubnubPushType = pushType; - return this; - } - - public RemoveAllPushChannelsOperation DeviceId(string deviceId) - { - this.deviceTokenId = deviceId; - return this; - } - - /// - /// Applies to APNS2 Only. Default = Development - /// - /// - /// - public RemoveAllPushChannelsOperation Environment(PushEnvironment environment) - { - this.pushEnvironment = environment; - return this; - } - - /// - /// Applies to APNS2 Only - /// - /// - /// - public RemoveAllPushChannelsOperation Topic(string deviceTopic) - { - this.deviceTopic = deviceTopic; - return this; - } - - public RemoveAllPushChannelsOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - RemoveAllChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - RemoveAllChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await RemoveAllChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - RemoveAllChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - RemoveAllChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void RemoveAllChannelsForDevice(PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam, PNCallback callback) - { - if (pushToken == null) - { - throw new ArgumentException("Missing deviceId"); - } - - if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) - { - throw new ArgumentException("Missing Topic"); - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildUnregisterDevicePushRequest("GET", "", pushType, pushToken, environment, deviceTopic, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PushUnregister; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> RemoveAllChannelsForDevice(PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam) - { - if (pushToken == null) - { - throw new ArgumentException("Missing deviceId"); - } - - if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) - { - throw new ArgumentException("Missing Topic"); - } - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildUnregisterDevicePushRequest("GET", "", pushType, pushToken, environment, deviceTopic, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.ResponseType = PNOperationType.PushUnregister; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNPushRemoveAllChannelsResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class RemoveAllPushChannelsOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNPushType pubnubPushType; + private string deviceTokenId = string.Empty; + private PushEnvironment pushEnvironment = PushEnvironment.Development; + private string deviceTopic = string.Empty; + private PNCallback savedCallback; + private Dictionary queryParam; + + public RemoveAllPushChannelsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public RemoveAllPushChannelsOperation PushType(PNPushType pushType) + { + this.pubnubPushType = pushType; + return this; + } + + public RemoveAllPushChannelsOperation DeviceId(string deviceId) + { + this.deviceTokenId = deviceId; + return this; + } + + /// + /// Applies to APNS2 Only. Default = Development + /// + /// + /// + public RemoveAllPushChannelsOperation Environment(PushEnvironment environment) + { + this.pushEnvironment = environment; + return this; + } + + /// + /// Applies to APNS2 Only + /// + /// + /// + public RemoveAllPushChannelsOperation Topic(string deviceTopic) + { + this.deviceTopic = deviceTopic; + return this; + } + + public RemoveAllPushChannelsOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + RemoveAllChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await RemoveAllChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + RemoveAllChannelsForDevice(this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); + } + + internal void RemoveAllChannelsForDevice(PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam, PNCallback callback) + { + if (pushToken == null) { + throw new ArgumentException("Missing deviceId"); + } + + if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) { + throw new ArgumentException("Missing Topic"); + } + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PushUnregister; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PushUnregister); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PushUnregister, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + internal async Task> RemoveAllChannelsForDevice(PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam) + { + if (pushToken == null) { + throw new ArgumentException("Missing deviceId"); + } + + if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) { + throw new ArgumentException("Missing Topic"); + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PushUnregister; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + Tuple JsonAndStatusTuple; + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PushUnregister); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNPushRemoveAllChannelsResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PushUnregister, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = pubnubPushType == PNPushType.APNS2 ? new List + { + "v2", + "push", + "sub-key", + config.SubscribeKey, + "devices-apns2", + deviceTokenId, + "remove" + } : new List + { + "v1", + "push", + "sub-key", + config.SubscribeKey, + "devices", + deviceTokenId, + "remove" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (pubnubPushType == PNPushType.APNS2) { + requestQueryStringParams.Add("environment", pushEnvironment.ToString().ToLowerInvariant()); + requestQueryStringParams.Add("topic", UriUtil.EncodeUriComponent(deviceTopic, PNOperationType.PushUnregister, false, false, false)); + } else { + requestQueryStringParams.Add("type", pubnubPushType.ToString().ToLowerInvariant()); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PushUnregister, false, false, false)); + } + } + } + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/Push/RemovePushChannelOperation.cs b/src/Api/PubnubApi/EndPoint/Push/RemovePushChannelOperation.cs index a95e65653..524d8baf9 100644 --- a/src/Api/PubnubApi/EndPoint/Push/RemovePushChannelOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Push/RemovePushChannelOperation.cs @@ -2,231 +2,252 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Text; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class RemovePushChannelOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private PNPushType pubnubPushType; - private string[] channelNames; - private string deviceTokenId = ""; - private PushEnvironment pushEnvironment = PushEnvironment.Development; - private string deviceTopic = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public RemovePushChannelOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - - public RemovePushChannelOperation PushType(PNPushType pushType) - { - this.pubnubPushType = pushType; - return this; - } - - public RemovePushChannelOperation DeviceId(string deviceId) - { - this.deviceTokenId = deviceId; - return this; - } - - public RemovePushChannelOperation Channels(string[] channels) - { - this.channelNames = channels; - return this; - } - - /// - /// Applies to APNS2 Only. Default = Development - /// - /// - /// - public RemovePushChannelOperation Environment(PushEnvironment environment) - { - this.pushEnvironment = environment; - return this; - } - - /// - /// Applies to APNS2 Only - /// - /// - /// - public RemovePushChannelOperation Topic(string deviceTopic) - { - this.deviceTopic = deviceTopic; - return this; - } - - public RemovePushChannelOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - RemoveChannelForDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - RemoveChannelForDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await RemoveChannelForDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - RemoveChannelForDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - RemoveChannelForDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void RemoveChannelForDevice(string[] channels, PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam, PNCallback callback) - { - if (channels == null || channels.Length == 0 || channels[0] == null || channels[0].Trim().Length == 0) - { - throw new ArgumentException("Missing Channel"); - } - - if (pushToken == null) - { - throw new ArgumentException("Missing deviceId"); - } - - if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) - { - throw new ArgumentException("Missing Topic"); - } - - string channel = string.Join(",", channels.OrderBy(x => x).ToArray()); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildRemoveChannelPushRequest("GET", "", channel, pushType, pushToken, environment, deviceTopic, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new [] { channel }; - requestState.ResponseType = PNOperationType.PushRemove; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> RemoveChannelForDevice(string[] channels, PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam) - { - if (channels == null || channels.Length == 0 || channels[0] == null || channels[0].Trim().Length == 0) - { - throw new ArgumentException("Missing Channel"); - } - - if (pushToken == null) - { - throw new ArgumentException("Missing deviceId"); - } - - if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) - { - throw new ArgumentException("Missing Topic"); - } - PNResult ret = new PNResult(); - - string channel = string.Join(",", channels.OrderBy(x => x).ToArray()); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildRemoveChannelPushRequest("GET", "", channel, pushType, pushToken, environment, deviceTopic, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PushRemove; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNPushRemoveChannelResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - } + public class RemovePushChannelOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private PNPushType pubnubPushType; + private string[] channelNames; + private string deviceTokenId = ""; + private PushEnvironment pushEnvironment = PushEnvironment.Development; + private string deviceTopic = ""; + private PNCallback savedCallback; + private Dictionary queryParam; + + public RemovePushChannelOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + + public RemovePushChannelOperation PushType(PNPushType pushType) + { + this.pubnubPushType = pushType; + return this; + } + + public RemovePushChannelOperation DeviceId(string deviceId) + { + this.deviceTokenId = deviceId; + return this; + } + + public RemovePushChannelOperation Channels(string[] channels) + { + this.channelNames = channels; + return this; + } + + /// + /// Applies to APNS2 Only. Default = Development + /// + /// + /// + public RemovePushChannelOperation Environment(PushEnvironment environment) + { + this.pushEnvironment = environment; + return this; + } + + /// + /// Applies to APNS2 Only + /// + /// + /// + public RemovePushChannelOperation Topic(string deviceTopic) + { + this.deviceTopic = deviceTopic; + return this; + } + + public RemovePushChannelOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + RemoveChannelForDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await RemoveChannelForDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam); + } + + internal void Retry() + { + RemoveChannelForDevice(this.channelNames, this.pubnubPushType, this.deviceTokenId, this.pushEnvironment, this.deviceTopic, this.queryParam, savedCallback); + } + + internal void RemoveChannelForDevice(string[] channels, PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam, PNCallback callback) + { + if (channels == null || channels.Length == 0 || channels[0] == null || channels[0].Trim().Length == 0) { + throw new ArgumentException("Missing Channel"); + } + + if (pushToken == null) { + throw new ArgumentException("Missing deviceId"); + } + + if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) { + throw new ArgumentException("Missing Topic"); + } + RequestState requestState = new RequestState(); + requestState.Channels = channels.Select(c => c).ToArray(); + requestState.ResponseType = PNOperationType.PushRemove; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PushRemove); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PushRemove, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNPushRemoveChannelResult), status); + } + }); + } + + internal async Task> RemoveChannelForDevice(string[] channels, PNPushType pushType, string pushToken, PushEnvironment environment, string deviceTopic, Dictionary externalQueryParam) + { + if (channels == null || channels.Length == 0 || channels[0] == null || channels[0].Trim().Length == 0) { + throw new ArgumentException("Missing Channel"); + } + + if (pushToken == null) { + throw new ArgumentException("Missing deviceId"); + } + + if (pushType == PNPushType.APNS2 && string.IsNullOrEmpty(deviceTopic)) { + throw new ArgumentException("Missing Topic"); + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.Channels = channels.Select(c => c).ToArray(); + requestState.ResponseType = PNOperationType.PushRemove; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PushRemove); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNPushRemoveChannelResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PushRemove, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = pubnubPushType == PNPushType.APNS2 ? new List + { + "v2", + "push", + "sub-key", + config.SubscribeKey, + "devices-apns2", + deviceTokenId + } : new List + { + "v1", + "push", + "sub-key", + config.SubscribeKey, + "devices", + deviceTokenId + }; + + + Dictionary requestQueryStringParams = new Dictionary(); + if (pubnubPushType == PNPushType.APNS2) { + requestQueryStringParams.Add("environment", pushEnvironment.ToString().ToLowerInvariant()); + requestQueryStringParams.Add("topic", UriUtil.EncodeUriComponent(deviceTopic, PNOperationType.PushRemove, false, false, false)); + } else { + requestQueryStringParams.Add("type", pubnubPushType.ToString().ToLowerInvariant()); + } + + requestQueryStringParams.Add("remove", UriUtil.EncodeUriComponent(string.Join(",", channelNames.OrderBy(x => x).ToArray()), PNOperationType.PushRemove, false, false, false)); + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PushRemove, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/StoragePlayback/DeleteMessageOperation.cs b/src/Api/PubnubApi/EndPoint/StoragePlayback/DeleteMessageOperation.cs index 411892f2f..26316cdba 100644 --- a/src/Api/PubnubApi/EndPoint/StoragePlayback/DeleteMessageOperation.cs +++ b/src/Api/PubnubApi/EndPoint/StoragePlayback/DeleteMessageOperation.cs @@ -1,197 +1,211 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class DeleteMessageOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private long startTimetoken = -1; - private long endTimetoken = -1; - - private string channelName = ""; - private PNCallback savedCallback; - private Dictionary queryParam; - - public DeleteMessageOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - - } - - public DeleteMessageOperation Channel(string channel) - { - this.channelName = channel; - return this; - } - - public DeleteMessageOperation Start(long start) - { - this.startTimetoken = start; - return this; - } - - public DeleteMessageOperation End(long end) - { - this.endTimetoken = end; - return this; - } - - public DeleteMessageOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) - { - throw new MissingMemberException("Invalid Subscribe Key"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - DeleteMessage(this.channelName, this.startTimetoken, this.endTimetoken, this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - DeleteMessage(this.channelName, this.startTimetoken, this.endTimetoken, this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) - { - throw new MissingMemberException("Invalid Subscribe Key"); - } - - return await DeleteMessage(this.channelName, this.startTimetoken, this.endTimetoken, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - DeleteMessage(this.channelName, this.startTimetoken, this.endTimetoken, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - DeleteMessage(this.channelName, this.startTimetoken, this.endTimetoken, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void DeleteMessage(string channel, long start, long end, Dictionary externalQueryParam, PNCallback callback) - { - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) - { - throw new ArgumentException("Missing Channel"); - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildDeleteMessageRequest("DELETE", "", channel, start, end, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new [] { channel }; - requestState.ResponseType = PNOperationType.PNDeleteMessageOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> DeleteMessage(string channel, long start, long end, Dictionary externalQueryParam) - { - if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) - { - throw new ArgumentException("Missing Channel"); - } - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildDeleteMessageRequest("DELETE", "", channel, start, end, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNDeleteMessageOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNDeleteMessageResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - } + public class DeleteMessageOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private long startTimetoken = -1; + private long endTimetoken = -1; + + private string channelName = ""; + private PNCallback savedCallback; + private Dictionary queryParam; + + public DeleteMessageOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + + } + + public DeleteMessageOperation Channel(string channel) + { + this.channelName = channel; + return this; + } + + public DeleteMessageOperation Start(long start) + { + this.startTimetoken = start; + return this; + } + + public DeleteMessageOperation End(long end) + { + this.endTimetoken = end; + return this; + } + + public DeleteMessageOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) { + throw new MissingMemberException("Invalid Subscribe Key"); + } + this.savedCallback = callback; + DeleteMessage(this.channelName, this.startTimetoken, this.endTimetoken, this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) { + throw new MissingMemberException("Invalid Subscribe Key"); + } + + return await DeleteMessage(this.channelName, this.startTimetoken, this.endTimetoken, this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + DeleteMessage(this.channelName, this.startTimetoken, this.endTimetoken, this.queryParam, savedCallback); + } + + internal void DeleteMessage(string channel, long start, long end, Dictionary externalQueryParam, PNCallback callback) + { + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) { + throw new ArgumentException("Missing Channel"); + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNDeleteMessageOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNDeleteMessageOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNDeleteMessageOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNDeleteMessageResult), status); + } + }); + } + + internal async Task> DeleteMessage(string channel, long start, long end, Dictionary externalQueryParam) + { + if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim())) { + throw new ArgumentException("Missing Channel"); + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNDeleteMessageOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNDeleteMessageOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNDeleteMessageResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNDeleteMessageOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List() { + "v3", + "history", + "sub-key", + config.SubscribeKey, + "channel", + channelName + }; + + Dictionary requestQueryStringParams = new Dictionary(); + + if (startTimetoken != -1) { + requestQueryStringParams.Add("start", startTimetoken.ToString(CultureInfo.InvariantCulture)); + } + if (endTimetoken != -1) { + requestQueryStringParams.Add("end", endTimetoken.ToString(CultureInfo.InvariantCulture)); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNDeleteMessageOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.DELETE, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/StoragePlayback/FetchHistoryOperation.cs b/src/Api/PubnubApi/EndPoint/StoragePlayback/FetchHistoryOperation.cs index 6a7f9c072..303029571 100644 --- a/src/Api/PubnubApi/EndPoint/StoragePlayback/FetchHistoryOperation.cs +++ b/src/Api/PubnubApi/EndPoint/StoragePlayback/FetchHistoryOperation.cs @@ -3,254 +3,285 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class FetchHistoryOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private bool reverseOption; - private bool withMetaOption; - private bool withMessageActionsOption; - private bool includeMessageType = true; //default to true - private bool withUuidOption = true; //default to true - private long startTimetoken = -1; - private long endTimetoken = -1; - private int perChannelCount = -1; - private Dictionary queryParam; - - private string[] channelNames; - private PNCallback savedCallback; - - public FetchHistoryOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - - } - - public FetchHistoryOperation Channels(string[] channelNames) - { - this.channelNames = channelNames; - return this; - } - - public FetchHistoryOperation Reverse(bool reverse) - { - this.reverseOption = reverse; - return this; - } - - public FetchHistoryOperation IncludeMeta(bool withMeta) - { - this.withMetaOption = withMeta; - return this; - } - - public FetchHistoryOperation IncludeMessageType(bool withMessageType) - { - includeMessageType = withMessageType; - return this; - } - - public FetchHistoryOperation IncludeUuid(bool withUuid) - { - withUuidOption = withUuid; - return this; - } - - public FetchHistoryOperation IncludeMessageActions(bool withMessageActions) - { - this.withMessageActionsOption = withMessageActions; - return this; - } - - public FetchHistoryOperation Start(long start) - { - this.startTimetoken = start; - return this; - } - - public FetchHistoryOperation End(long end) - { - this.endTimetoken = end; - return this; - } - - public FetchHistoryOperation MaximumPerChannel(int count) - { - this.perChannelCount = count; - return this; - } - - public FetchHistoryOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) - { - throw new MissingMemberException("Invalid Subscribe Key"); - } - - if (this.channelNames == null || this.channelNames.Length == 0 || string.IsNullOrEmpty(this.channelNames[0])) - { - throw new MissingMemberException("Missing channel name(s)"); - } - - if (this.withMessageActionsOption && this.channelNames != null && this.channelNames.Length > 1) - { - throw new NotSupportedException("Only one channel can be used along with MessageActions"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - History(callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - History(callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) - { - throw new MissingMemberException("Invalid Subscribe Key"); - } - - if (this.channelNames == null || this.channelNames.Length == 0 || string.IsNullOrEmpty(this.channelNames[0])) - { - throw new MissingMemberException("Missing channel name(s)"); - } - - if (this.withMessageActionsOption && this.channelNames != null && this.channelNames.Length > 1) - { - throw new NotSupportedException("Only one channel can be used along with MessageActions"); - } - - return await History().ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - History(savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - History(savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void History(PNCallback callback) - { - if (this.channelNames == null || this.channelNames.Length == 0 || string.IsNullOrEmpty(this.channelNames[0]) || string.IsNullOrEmpty(this.channelNames[0].Trim())) - { - throw new ArgumentException("Missing Channel(s)"); - } - string channel = string.Join(",", this.channelNames); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildFetchRequest("GET", "", this.channelNames, this.startTimetoken, this.endTimetoken, this.perChannelCount, this.reverseOption, this.withMetaOption, this.withMessageActionsOption, this.withUuidOption, this.includeMessageType, this.queryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNFetchHistoryOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> History() - { - if (this.channelNames == null || this.channelNames.Length == 0 || string.IsNullOrEmpty(this.channelNames[0]) || string.IsNullOrEmpty(this.channelNames[0].Trim())) - { - throw new ArgumentException("Missing Channel(s)"); - } - PNResult ret = new PNResult(); - string channel = string.Join(",", this.channelNames); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildFetchRequest("GET", "", this.channelNames, this.startTimetoken, this.endTimetoken, this.perChannelCount, this.reverseOption, this.withMetaOption, this.withMessageActionsOption, this.withUuidOption, this.includeMessageType, this.queryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { channel }; - requestState.ResponseType = PNOperationType.PNFetchHistoryOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNFetchHistoryResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - } - + public class FetchHistoryOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private bool reverseOption; + private bool withMetaOption; + private bool withMessageActionsOption; + private bool includeMessageType = true; //default to true + private bool withUuidOption = true; //default to true + private long startTimetoken = -1; + private long endTimetoken = -1; + private int perChannelCount = -1; + private Dictionary queryParam; + + private string[] channelNames; + private PNCallback savedCallback; + + public FetchHistoryOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + + } + + public FetchHistoryOperation Channels(string[] channelNames) + { + this.channelNames = channelNames; + return this; + } + + public FetchHistoryOperation Reverse(bool reverse) + { + this.reverseOption = reverse; + return this; + } + + public FetchHistoryOperation IncludeMeta(bool withMeta) + { + this.withMetaOption = withMeta; + return this; + } + + public FetchHistoryOperation IncludeMessageType(bool withMessageType) + { + includeMessageType = withMessageType; + return this; + } + + public FetchHistoryOperation IncludeUuid(bool withUuid) + { + withUuidOption = withUuid; + return this; + } + + public FetchHistoryOperation IncludeMessageActions(bool withMessageActions) + { + this.withMessageActionsOption = withMessageActions; + return this; + } + + public FetchHistoryOperation Start(long start) + { + this.startTimetoken = start; + return this; + } + + public FetchHistoryOperation End(long end) + { + this.endTimetoken = end; + return this; + } + + public FetchHistoryOperation MaximumPerChannel(int count) + { + this.perChannelCount = count; + return this; + } + + public FetchHistoryOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) { + throw new MissingMemberException("Invalid Subscribe Key"); + } + + if (this.channelNames == null || this.channelNames.Length == 0 || string.IsNullOrEmpty(this.channelNames[0])) { + throw new MissingMemberException("Missing channel name(s)"); + } + + if (this.withMessageActionsOption && this.channelNames != null && this.channelNames.Length > 1) { + throw new NotSupportedException("Only one channel can be used along with MessageActions"); + } + this.savedCallback = callback; + History(callback); + } + + public async Task> ExecuteAsync() + { + if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) { + throw new MissingMemberException("Invalid Subscribe Key"); + } + + if (this.channelNames == null || this.channelNames.Length == 0 || string.IsNullOrEmpty(this.channelNames[0])) { + throw new MissingMemberException("Missing channel name(s)"); + } + + if (this.withMessageActionsOption && this.channelNames != null && this.channelNames.Length > 1) { + throw new NotSupportedException("Only one channel can be used along with MessageActions"); + } + + return await History(); + } + + internal void Retry() + { + History(savedCallback); + } + + internal void History(PNCallback callback) + { + if (this.channelNames == null || this.channelNames.Length == 0 || string.IsNullOrEmpty(this.channelNames[0]) || string.IsNullOrEmpty(this.channelNames[0].Trim())) { + throw new ArgumentException("Missing Channel(s)"); + } + string channel = string.Join(",", this.channelNames); + + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNFetchHistoryOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNFetchHistoryOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNFetchHistoryOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNFetchHistoryResult), status); + } + }); + } + + internal async Task> History() + { + if (this.channelNames == null || this.channelNames.Length == 0 || string.IsNullOrEmpty(this.channelNames[0]) || string.IsNullOrEmpty(this.channelNames[0].Trim())) { + throw new ArgumentException("Missing Channel(s)"); + } + PNResult returnValue = new PNResult(); + string channel = string.Join(",", this.channelNames); + RequestState requestState = new RequestState(); + requestState.Channels = new[] { channel }; + requestState.ResponseType = PNOperationType.PNFetchHistoryOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + var requestParameter = CreateRequestParameter(); + + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNFetchHistoryOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNFetchHistoryResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNFetchHistoryOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + private RequestParameter CreateRequestParameter() + { + string channelsString = (channelNames != null && channelNames.Length > 0) ? string.Join(",", channelNames.OrderBy(x => x).ToArray()) : ""; + + List pathSegments = new List() { + "v3", + withMessageActionsOption ? "history-with-actions" : "history", + "sub-key", + config.SubscribeKey, + "channel", + channelsString + }; + + Dictionary requestQueryStringParams = new Dictionary + { + { "max", (this.perChannelCount <= -1) ? (withMessageActionsOption || (channelNames != null && channelNames.Length > 1) ? "25" : "100") : perChannelCount.ToString(CultureInfo.InvariantCulture) } + }; + if (reverseOption) { + requestQueryStringParams.Add("reverse", "true"); + } + if (startTimetoken != -1) { + requestQueryStringParams.Add("start", startTimetoken.ToString(CultureInfo.InvariantCulture)); + } + if (endTimetoken != -1) { + requestQueryStringParams.Add("end", endTimetoken.ToString(CultureInfo.InvariantCulture)); + } + + if (withMetaOption) { + requestQueryStringParams.Add("include_meta", "true"); + } + + if (withUuidOption) { + requestQueryStringParams.Add("include_uuid", "true"); + } + + if (includeMessageType) { + requestQueryStringParams.Add("include_message_type", "true"); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNFetchHistoryOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/StoragePlayback/HistoryOperation.cs b/src/Api/PubnubApi/EndPoint/StoragePlayback/HistoryOperation.cs index 871d56f71..c4511ad45 100644 --- a/src/Api/PubnubApi/EndPoint/StoragePlayback/HistoryOperation.cs +++ b/src/Api/PubnubApi/EndPoint/StoragePlayback/HistoryOperation.cs @@ -1,226 +1,254 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; using System.Net; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class HistoryOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private bool reverseOption; - private bool includeTimetokenOption; - private bool withMetaOption; - private long startTimetoken = -1; - private long endTimetoken = -1; - private int historyCount = -1; - private Dictionary queryParam; - - private string channelName = ""; - private PNCallback savedCallback; - - public HistoryOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - - } - - public HistoryOperation Channel(string channel) - { - channelName = channel; - return this; - } - - public HistoryOperation Reverse(bool reverse) - { - reverseOption = reverse; - return this; - } - - public HistoryOperation IncludeTimetoken(bool includeTimetoken) - { - includeTimetokenOption = includeTimetoken; - return this; - } - - public HistoryOperation IncludeMeta(bool withMeta) - { - withMetaOption = withMeta; - return this; - } - - public HistoryOperation Start(long start) - { - startTimetoken = start; - return this; - } - - public HistoryOperation End(long end) - { - endTimetoken = end; - return this; - } - - public HistoryOperation Count(int count) - { - historyCount = count; - return this; - } - - public HistoryOperation QueryParam(Dictionary customQueryParam) - { - queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) - { - throw new MissingMemberException("Invalid Subscribe Key"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - History(callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - History(callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) - { - throw new MissingMemberException("Invalid Subscribe Key"); - } - - return await History().ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - History(savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - History(savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void History(PNCallback callback) - { - if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim())) - { - throw new ArgumentException("Missing Channel"); - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildHistoryRequest("GET", "", this.channelName, this.startTimetoken, this.endTimetoken, this.historyCount, this.reverseOption, this.includeTimetokenOption, this.withMetaOption, this.queryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new [] { this.channelName }; - requestState.ResponseType = PNOperationType.PNHistoryOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> History() - { - if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim())) - { - throw new ArgumentException("Missing Channel"); - } - - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildHistoryRequest("GET", "", this.channelName, this.startTimetoken, this.endTimetoken, this.historyCount, this.reverseOption, this.includeTimetokenOption, this.withMetaOption, this.queryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = new[] { this.channelName }; - requestState.ResponseType = PNOperationType.PNHistoryOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNHistoryResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - } + public class HistoryOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private bool reverseOption; + private bool includeTimetokenOption; + private bool withMetaOption; + private long startTimetoken = -1; + private long endTimetoken = -1; + private int historyCount = -1; + private Dictionary queryParam; + + private string channelName = ""; + private PNCallback savedCallback; + + public HistoryOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + + } + + public HistoryOperation Channel(string channel) + { + channelName = channel; + return this; + } + + public HistoryOperation Reverse(bool reverse) + { + reverseOption = reverse; + return this; + } + + public HistoryOperation IncludeTimetoken(bool includeTimetoken) + { + includeTimetokenOption = includeTimetoken; + return this; + } + + public HistoryOperation IncludeMeta(bool withMeta) + { + withMetaOption = withMeta; + return this; + } + + public HistoryOperation Start(long start) + { + startTimetoken = start; + return this; + } + + public HistoryOperation End(long end) + { + endTimetoken = end; + return this; + } + + public HistoryOperation Count(int count) + { + historyCount = count; + return this; + } + + public HistoryOperation QueryParam(Dictionary customQueryParam) + { + queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) { + throw new MissingMemberException("Invalid Subscribe Key"); + } + this.savedCallback = callback; + History(callback); + } + + public async Task> ExecuteAsync() + { + if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) { + throw new MissingMemberException("Invalid Subscribe Key"); + } + + return await History(); + } + + internal void Retry() + { + History(savedCallback); + } + + internal void History(PNCallback callback) + { + if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim())) { + throw new ArgumentException("Missing Channel"); + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { this.channelName }; + requestState.ResponseType = PNOperationType.PNHistoryOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParemeter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNHistoryOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNHistoryOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNHistoryResult), status); + } + }); + } + + internal async Task> History() + { + if (string.IsNullOrEmpty(this.channelName) || string.IsNullOrEmpty(this.channelName.Trim())) { + throw new ArgumentException("Missing Channel"); + } + RequestState requestState = new RequestState(); + requestState.Channels = new[] { this.channelName }; + requestState.ResponseType = PNOperationType.PNHistoryOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + PNResult returnValue = new PNResult(); + Tuple JsonAndStatusTuple; + var requestParameter = CreateRequestParemeter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNHistoryOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNHistoryResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNHistoryOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + private RequestParameter CreateRequestParemeter() + { + List pathSegments = new List() + { + "v2", + "history", + "sub-key", + config.SubscribeKey, + "channel", + channelName + }; + + Dictionary requestQueryStringParams = new Dictionary + { + { "count", (historyCount <= -1) ? "100" : historyCount.ToString(CultureInfo.InvariantCulture) } + }; + + if (reverseOption) { + requestQueryStringParams.Add("reverse", "true"); + } + if (startTimetoken != -1) { + requestQueryStringParams.Add("start", startTimetoken.ToString(CultureInfo.InvariantCulture)); + } + if (endTimetoken != -1) { + requestQueryStringParams.Add("end", endTimetoken.ToString(CultureInfo.InvariantCulture)); + } + + if (includeTimetokenOption) { + requestQueryStringParams.Add("include_token", "true"); + } + + if (withMetaOption) { + requestQueryStringParams.Add("include_meta", "true"); + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNHistoryOperation, false, false, false)); + } + } + } + + var requestParemeter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParemeter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/StoragePlayback/MessageCountsOperation.cs b/src/Api/PubnubApi/EndPoint/StoragePlayback/MessageCountsOperation.cs index a765608a3..d700d9b03 100644 --- a/src/Api/PubnubApi/EndPoint/StoragePlayback/MessageCountsOperation.cs +++ b/src/Api/PubnubApi/EndPoint/StoragePlayback/MessageCountsOperation.cs @@ -3,190 +3,214 @@ using System.Linq; using System.Net; using System.Text; -using System.Threading; using System.Threading.Tasks; -#if !NET35 && !NET40 +using System.Globalization; +using System.Threading; using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class MessageCountsOperation : PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private Dictionary queryParam; - - private string[] channelNames; - private long[] msgCountArrayTimetoken; - private PNCallback savedCallback; - - public MessageCountsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, tokenManager, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public MessageCountsOperation Channels(string[] channels) - { - this.channelNames = channels; - return this; - } - - public MessageCountsOperation ChannelsTimetoken(long[] timetokens) - { - this.msgCountArrayTimetoken = timetokens; - return this; - } - - public MessageCountsOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { - if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) - { - throw new MissingMemberException("Invalid Subscribe Key"); - } - -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - MessageCounts(this.channelNames, this.msgCountArrayTimetoken, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - MessageCounts(this.channelNames, this.msgCountArrayTimetoken, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) - { - throw new MissingMemberException("Invalid Subscribe Key"); - } - - return await MessageCounts(this.channelNames, this.msgCountArrayTimetoken, this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - MessageCounts(this.channelNames, this.msgCountArrayTimetoken, this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - MessageCounts(this.channelNames, this.msgCountArrayTimetoken, this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void MessageCounts(string[] channels, long[] timetokens, Dictionary externalQueryParam, PNCallback callback) - { - if (channels == null || channels.Length == 0) - { - throw new ArgumentException("Missing Channel"); - } - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildMessageCountsRequest("GET", "", channels, timetokens, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = channels; - requestState.ResponseType = PNOperationType.PNMessageCountsOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> MessageCounts(string[] channels, long[] timetokens, Dictionary externalQueryParam) - { - if (channels == null || channels.Length == 0) - { - throw new ArgumentException("Missing Channel"); - } - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildMessageCountsRequest("GET", "", channels, timetokens, externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = channels; - requestState.ResponseType = PNOperationType.PNMessageCountsOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNMessageCountResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class MessageCountsOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private Dictionary queryParam; + + private string[] channelNames; + private long[] timetokens; + private PNCallback savedCallback; + + public MessageCountsOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, tokenManager, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public MessageCountsOperation Channels(string[] channels) + { + this.channelNames = channels; + return this; + } + + public MessageCountsOperation ChannelsTimetoken(long[] timetokens) + { + this.timetokens = timetokens; + return this; + } + + public MessageCountsOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) { + throw new MissingMemberException("Invalid Subscribe Key"); + } + this.savedCallback = callback; + MessageCounts(this.channelNames, this.timetokens, this.queryParam, savedCallback); + } + + public async Task> ExecuteAsync() + { + if (string.IsNullOrEmpty(config.SubscribeKey) || config.SubscribeKey.Trim().Length == 0) { + throw new MissingMemberException("Invalid Subscribe Key"); + } + + return await MessageCounts(this.channelNames, this.timetokens, this.queryParam); + } + + internal void Retry() + { + MessageCounts(this.channelNames, this.timetokens, this.queryParam, savedCallback); + } + + internal void MessageCounts(string[] channels, long[] timetokens, Dictionary externalQueryParam, PNCallback callback) + { + if (channels == null || channels.Length == 0) { + throw new ArgumentException("Missing Channel"); + } + RequestState requestState = new RequestState(); + requestState.Channels = channels; + requestState.ResponseType = PNOperationType.PNMessageCountsOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNMessageCountsOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNMessageCountsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default(PNMessageCountResult), status); + } + }); + } + + internal async Task> MessageCounts(string[] channels, long[] timetokens, Dictionary externalQueryParam) + { + if (channels == null || channels.Length == 0) { + throw new ArgumentException("Missing Channel"); + } + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.Channels = channels; + requestState.ResponseType = PNOperationType.PNMessageCountsOperation; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNMessageCountsOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, (int)HttpStatusCode.OK, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNMessageCountResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNMessageCountsOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + + if (!ChannelRequest.ContainsKey(instance.InstanceId)) { + ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) { + ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); + } + } + + private RequestParameter CreateRequestParameter() + { + string channelString = (channelNames != null && channelNames.Length > 0) ? string.Join(",", channelNames) : ""; + + List pathSegments = new List() { + "v3", + "history", + "sub-key", + config.SubscribeKey, + "message-counts" + }; + + if (!string.IsNullOrEmpty(channelString)) { + pathSegments.Add(UriUtil.EncodeUriComponent(channelString, PNOperationType.PNMessageCountsOperation, true, false, false)); + } + + Dictionary requestQueryStringParams = new Dictionary(); + + if (timetokens != null && timetokens.Length > 0) { + string tt = string.Join(",", timetokens.Select(x => x.ToString(CultureInfo.InvariantCulture)).ToArray()); + if (timetokens.Length == 1) { + requestQueryStringParams.Add("timetoken", tt); + } else { + requestQueryStringParams.Add("channelsTimetoken", UriUtil.EncodeUriComponent(tt, PNOperationType.PNMessageCountsOperation, false, false, false)); + } + } + + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNMessageCountsOperation, false, false, false)); + } + } + } + + var queryString = UriUtil.BuildQueryString(requestQueryStringParams); + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/EndPoint/TelemetryManager.cs b/src/Api/PubnubApi/EndPoint/TelemetryManager.cs deleted file mode 100644 index d5d510b16..000000000 --- a/src/Api/PubnubApi/EndPoint/TelemetryManager.cs +++ /dev/null @@ -1,315 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Globalization; -using System.Threading.Tasks; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif - -namespace PubnubApi.EndPoint -{ - public class TelemetryManager: IDisposable - { - private const int TELEMETRY_TIMER_IN_SEC = 60; - - private PNConfiguration pubnubConfig; - private IPubnubLog pubnubLog; - - private static ConcurrentDictionary> dicEndpointLatency - { - get; - set; - } = new ConcurrentDictionary>(); - - private System.Threading.Timer telemetryTimer { get; set; } - - public TelemetryManager(PNConfiguration config, IPubnubLog log) - { - this.pubnubConfig = config; - this.pubnubLog = log; - if (config != null && config.EnableTelemetry) - { - StartTelemetryTimer(); - } - } - - private void StartTelemetryTimer() - { - StopTelemetryTimer(); - telemetryTimer = new Timer(OnTelemetryIntervalTimeout, null, 0, TELEMETRY_TIMER_IN_SEC * 1000); - } - - private void OnTelemetryIntervalTimeout(System.Object telemetryState) - { - CleanupTelemetryData(); - } - - private void StopTelemetryTimer() - { - try - { - if (telemetryTimer != null) - { - telemetryTimer.Change(Timeout.Infinite, Timeout.Infinite); - telemetryTimer.Dispose(); - } - } - catch { /* Ignore exception caused by dispose */ } - finally { telemetryTimer = null; } - } - - private static string EndpointNameForOperation(PNOperationType type) - { - string endpoint = ""; - switch (type) - { - case PNOperationType.PNPublishOperation: - endpoint = "l_pub"; - break; - case PNOperationType.PNHistoryOperation: - case PNOperationType.PNFetchHistoryOperation: - case PNOperationType.PNFireOperation: - case PNOperationType.PNDeleteMessageOperation: - endpoint = "l_hist"; - break; - case PNOperationType.PNUnsubscribeOperation: - case PNOperationType.PNWhereNowOperation: - case PNOperationType.PNHereNowOperation: - case PNOperationType.PNHeartbeatOperation: - case PNOperationType.PNSetStateOperation: - case PNOperationType.PNGetStateOperation: - endpoint = "l_pres"; - break; - case PNOperationType.PNAddChannelsToGroupOperation: - case PNOperationType.PNRemoveChannelsFromGroupOperation: - case PNOperationType.PNChannelGroupsOperation: - case PNOperationType.PNRemoveGroupOperation: - case PNOperationType.PNChannelsForGroupOperation: - endpoint = "l_cg"; - break; - case PNOperationType.PushGet: - case PNOperationType.PushRegister: - case PNOperationType.PushRemove: - case PNOperationType.PushUnregister: - endpoint = "l_push"; - break; - case PNOperationType.PNAccessManagerGrantToken: - case PNOperationType.PNAccessManagerRevokeToken: - endpoint = "l_pamv3"; - break; - case PNOperationType.PNAccessManagerAudit: - case PNOperationType.PNAccessManagerGrant: - endpoint = "l_pam"; - break; - case PNOperationType.PNTimeOperation: - endpoint = "l_time"; - break; - case PNOperationType.PNMessageCountsOperation: - endpoint = "l_mc"; - break; - case PNOperationType.PNSignalOperation: - endpoint = "l_sig"; - break; - case PNOperationType.PNSetUuidMetadataOperation: - case PNOperationType.PNDeleteUuidMetadataOperation: - case PNOperationType.PNGetAllUuidMetadataOperation: - case PNOperationType.PNGetUuidMetadataOperation: - case PNOperationType.PNSetChannelMetadataOperation: - case PNOperationType.PNDeleteChannelMetadataOperation: - case PNOperationType.PNGetAllChannelMetadataOperation: - case PNOperationType.PNGetChannelMetadataOperation: - case PNOperationType.PNGetMembershipsOperation: - case PNOperationType.PNManageMembershipsOperation: - case PNOperationType.PNSetMembershipsOperation: - case PNOperationType.PNRemoveMembershipsOperation: - case PNOperationType.PNGetChannelMembersOperation: - case PNOperationType.PNManageChannelMembersOperation: - case PNOperationType.PNSetChannelMembersOperation: - case PNOperationType.PNRemoveChannelMembersOperation: - endpoint = "l_obj"; - break; - case PNOperationType.PNAddMessageActionOperation: - case PNOperationType.PNRemoveMessageActionOperation: - case PNOperationType.PNGetMessageActionsOperation: - endpoint = "l_msga"; - break; - case PNOperationType.PNGenerateFileUploadUrlOperation: - case PNOperationType.PNPublishFileMessageOperation: - case PNOperationType.PNDownloadFileOperation: - endpoint = "l_file"; - break; - default: - endpoint = ""; - break; - } - - return endpoint; - } - - private static readonly object operationLatencyDataLock = new object(); - public async Task StoreLatency(long latencyMillisec, PNOperationType type) - { - await Task.Factory.StartNew(() => - { - try - { - string latencyEndPoint = EndpointNameForOperation(type); - if (latencyMillisec > 0 && !string.IsNullOrEmpty(latencyEndPoint)) - { - if (dicEndpointLatency == null) - { - dicEndpointLatency = new ConcurrentDictionary>(); - } - - double epochMillisec = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; - if (dicEndpointLatency.ContainsKey(latencyEndPoint) && dicEndpointLatency[latencyEndPoint] != null && dicEndpointLatency[latencyEndPoint].Keys.Count > 0) - { - if (epochMillisec - dicEndpointLatency[latencyEndPoint].Keys.Max() > 500) - { - lock (operationLatencyDataLock) - { - dicEndpointLatency[latencyEndPoint].AddOrUpdate(epochMillisec, latencyMillisec, (key, oldValue) => latencyMillisec); - } - } - } - else - { - lock (operationLatencyDataLock) - { - ConcurrentDictionary elapsedInfo = new ConcurrentDictionary(); - elapsedInfo.AddOrUpdate(epochMillisec, latencyMillisec, (o, n) => latencyMillisec); - dicEndpointLatency.AddOrUpdate(latencyEndPoint, elapsedInfo, (o, n) => elapsedInfo); - } - } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, TelemetryManager - StoreLatency {1} latency = {2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), type, latencyMillisec), pubnubConfig.LogVerbosity); - } - } - catch (Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, TelemetryManager - StoreLatency error: {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex), pubnubConfig.LogVerbosity); - } - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); - } - - public async Task> GetOperationsLatency() - { - return await Task>.Factory.StartNew(() => - { - Dictionary dictionaryOpsLatency = new Dictionary(); - try - { - lock (operationLatencyDataLock) - { - if (dicEndpointLatency != null) - { - foreach (string key in dicEndpointLatency.Keys) - { - if (dicEndpointLatency[key] != null && dicEndpointLatency[key].Count > 0) - { - - dictionaryOpsLatency.Add(key, Math.Round(((double)dicEndpointLatency[key].Average(kvp => kvp.Value) / 1000.0), 10).ToString(CultureInfo.InvariantCulture)); //Convert millisec to sec - } - } - } - } - } - catch (Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, TelemetryManager - GetOperationsLatency error: {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex), pubnubConfig.LogVerbosity); - } - return dictionaryOpsLatency; - }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).ConfigureAwait(false); - } - - private void CleanupTelemetryData() - { - Task.Factory.StartNew(() => - { - lock (operationLatencyDataLock) - { - try - { - double currentEpochMillisec = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; - string[] latencyOpKeys = (dicEndpointLatency != null) ? dicEndpointLatency.Keys.ToArray() : new string[]{ }; - for (int keyIndex = 0; keyIndex < latencyOpKeys.Length; keyIndex++) - { - string opKey = latencyOpKeys[keyIndex]; - ConcurrentDictionary outdatedLatencyValue = null; - dicEndpointLatency.TryGetValue(opKey, out outdatedLatencyValue); - if (outdatedLatencyValue != null) - { - IEnumerable> enumerableOutdatedLatencies = outdatedLatencyValue.Where(dt => currentEpochMillisec - dt.Key >= 60000); - if (enumerableOutdatedLatencies != null) - { - Dictionary dicOutdatedLatencies = enumerableOutdatedLatencies.ToDictionary(item => item.Key, item => item.Value); - if (dicOutdatedLatencies != null && dicOutdatedLatencies.Count > 0) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, TelemetryManager - CleanupTelemetryData => {1} dicOutdatedLatencies count = {2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), opKey, dicOutdatedLatencies.Count), pubnubConfig.LogVerbosity); - double[] outLatencyKeys = dicOutdatedLatencies.Keys.ToArray(); - for (int outdateIndex = 0; outdateIndex < outLatencyKeys.Length; outdateIndex++) - { - double outKey = outLatencyKeys[outdateIndex]; - ConcurrentDictionary currentEndPointLatency = null; - dicEndpointLatency.TryGetValue(opKey, out currentEndPointLatency); - if (currentEndPointLatency != null && currentEndPointLatency.ContainsKey(outKey)) - { - long removeOutdatedLatency; - if (!currentEndPointLatency.TryRemove(outKey, out removeOutdatedLatency)) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, TelemetryManager - CleanupTelemetryData => removed failed for key = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), outKey), pubnubConfig.LogVerbosity); - } - } - } - } - } - } - } - } - catch (Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0}, TelemetryManager - CleanupTelemetryData => Exception = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex), pubnubConfig.LogVerbosity); - } - } - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); - - } - - public void Destroy() - { - StopTelemetryTimer(); - dicEndpointLatency.Clear(); - dicEndpointLatency = null; - pubnubConfig = null; - pubnubLog = null; - } - - #region IDisposable Support - private bool disposedValue; - - protected virtual void DisposeInternal(bool disposing) - { - if (!disposedValue) - { - dicEndpointLatency.Clear(); - pubnubConfig = null; - pubnubLog = null; - if (telemetryTimer != null) - { - telemetryTimer.Dispose(); - telemetryTimer = null; - } - - disposedValue = true; - } - } - - void IDisposable.Dispose() - { - DisposeInternal(true); - } - #endregion - } -} - diff --git a/src/Api/PubnubApi/EndPoint/TimeOperation.cs b/src/Api/PubnubApi/EndPoint/TimeOperation.cs index a2a9f5dea..73a9a806e 100644 --- a/src/Api/PubnubApi/EndPoint/TimeOperation.cs +++ b/src/Api/PubnubApi/EndPoint/TimeOperation.cs @@ -1,162 +1,159 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Threading; -using System.Net; -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif namespace PubnubApi.EndPoint { - public class TimeOperation: PubnubCoreBase - { - private readonly PNConfiguration config; - private readonly IJsonPluggableLibrary jsonLibrary; - private readonly IPubnubUnitTest unit; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; - - private Dictionary queryParam; - - private PNCallback savedCallback; - - public TimeOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, telemetryManager, null, instance) - { - config = pubnubConfig; - jsonLibrary = jsonPluggableLibrary; - unit = pubnubUnit; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; - } - - public TimeOperation QueryParam(Dictionary customQueryParam) - { - this.queryParam = customQueryParam; - return this; - } - - [Obsolete("Async is deprecated, please use Execute instead.")] - public void Async(PNCallback callback) - { - Execute(callback); - } - - public void Execute(PNCallback callback) - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - this.savedCallback = callback; - Time(this.queryParam, callback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - this.savedCallback = callback; - Time(this.queryParam, callback); - }) - { IsBackground = true }.Start(); -#endif - } - - public async Task> ExecuteAsync() - { - return await Time(this.queryParam).ConfigureAwait(false); - } - - internal void Retry() - { -#if NETFX_CORE || WINDOWS_UWP || UAP || NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 - Task.Factory.StartNew(() => - { - Time(this.queryParam, savedCallback); - }, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default).ConfigureAwait(false); -#else - new Thread(() => - { - Time(this.queryParam, savedCallback); - }) - { IsBackground = true }.Start(); -#endif - } - - internal void Time(Dictionary externalQueryParam, PNCallback callback) - { - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildTimeRequest("GET", "", externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = null; - requestState.ResponseType = PNOperationType.PNTimeOperation; - requestState.PubnubCallback = callback; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - UrlProcessRequest(request, requestState, false).ContinueWith(r => - { - string json = r.Result.Item1; - if (!string.IsNullOrEmpty(json)) - { - List result = ProcessJsonResponse(requestState, json); - ProcessResponseCallbacks(result, requestState); - } - }, TaskContinuationOptions.ExecuteSynchronously).Wait(); - } - - internal async Task> Time(Dictionary externalQueryParam) - { - PNResult ret = new PNResult(); - - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); - - Uri request = urlBuilder.BuildTimeRequest("GET", "", externalQueryParam); - - RequestState requestState = new RequestState(); - requestState.Channels = null; - requestState.ResponseType = PNOperationType.PNTimeOperation; - requestState.Reconnect = false; - requestState.EndPointOperation = this; - - Tuple JsonAndStatusTuple = await UrlProcessRequest(request, requestState, false).ConfigureAwait(false); - ret.Status = JsonAndStatusTuple.Item2; - string json = JsonAndStatusTuple.Item1; - if (!string.IsNullOrEmpty(json)) - { - List resultList = ProcessJsonResponse(requestState, json); - if (resultList != null && resultList.Count > 0) - { - ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); - PNTimeResult responseResult = responseBuilder.JsonToObject(resultList, true); - if (responseResult != null) - { - ret.Result = responseResult; - } - } - } - - return ret; - } - - internal void CurrentPubnubInstance(Pubnub instance) - { - PubnubInstance = instance; - - if (!ChannelRequest.ContainsKey(instance.InstanceId)) - { - ChannelRequest.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - if (!ChannelGroupInternetStatus.ContainsKey(instance.InstanceId)) - { - ChannelGroupInternetStatus.GetOrAdd(instance.InstanceId, new ConcurrentDictionary()); - } - } - } + public class TimeOperation : PubnubCoreBase + { + private readonly PNConfiguration config; + private readonly IJsonPluggableLibrary jsonLibrary; + private readonly IPubnubUnitTest unit; + private readonly IPubnubLog pubnubLog; + + private Dictionary queryParam; + + private PNCallback savedCallback; + + public TimeOperation(PNConfiguration pubnubConfig, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnit, IPubnubLog log, Pubnub instance) : base(pubnubConfig, jsonPluggableLibrary, pubnubUnit, log, null, instance) + { + config = pubnubConfig; + jsonLibrary = jsonPluggableLibrary; + unit = pubnubUnit; + pubnubLog = log; + } + + public TimeOperation QueryParam(Dictionary customQueryParam) + { + this.queryParam = customQueryParam; + return this; + } + + [Obsolete("Async is deprecated, please use Execute instead.")] + public void Async(PNCallback callback) + { + Execute(callback); + } + + public void Execute(PNCallback callback) + { + this.savedCallback = callback; + Time(this.queryParam, callback); + } + + public async Task> ExecuteAsync() + { + return await Time(this.queryParam).ConfigureAwait(false); + } + + internal void Retry() + { + Time(this.queryParam, savedCallback); + } + + internal void Time(Dictionary externalQueryParam, PNCallback callback) + { + RequestState requestState = new RequestState(); + requestState.Channels = null; + requestState.ResponseType = PNOperationType.PNTimeOperation; + requestState.PubnubCallback = callback; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNTimeOperation); + PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest).ContinueWith(t => { + var transportResponse = t.Result; + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + if (!string.IsNullOrEmpty(responseString)) { + List result = ProcessJsonResponse(requestState, responseString); + ProcessResponseCallbacks(result, requestState); + } else { + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + callback.OnResponse(default, errorStatus); + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNTimeOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + requestState.PubnubCallback.OnResponse(default, status); + } + }); + } + + internal async Task> Time(Dictionary externalQueryParam) + { + PNResult returnValue = new PNResult(); + RequestState requestState = new RequestState(); + requestState.ResponseType = PNOperationType.PNTimeOperation; + requestState.Channels = null; + requestState.Reconnect = false; + requestState.EndPointOperation = this; + Tuple JsonAndStatusTuple; + var requestParameter = CreateRequestParameter(); + var transportRequest = PubnubInstance.transportMiddleware.PreapareTransportRequest(requestParameter: requestParameter, operationType: PNOperationType.PNTimeOperation); + var transportResponse = await PubnubInstance.transportMiddleware.Send(transportRequest: transportRequest); + if (transportResponse.Error == null) { + var responseString = Encoding.UTF8.GetString(transportResponse.Content); + PNStatus errorStatus = GetStatusIfError(requestState, responseString); + if (errorStatus == null) { + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(requestState.ResponseType, PNStatusCategory.PNAcknowledgmentCategory, requestState, transportResponse.StatusCode, null); + JsonAndStatusTuple = new Tuple(responseString, status); + } else { + JsonAndStatusTuple = new Tuple(string.Empty, errorStatus); + } + returnValue.Status = JsonAndStatusTuple.Item2; + string json = JsonAndStatusTuple.Item1; + if (!string.IsNullOrEmpty(json)) { + List resultList = ProcessJsonResponse(requestState, json); + if (resultList != null && resultList.Count > 0) { + ResponseBuilder responseBuilder = new ResponseBuilder(config, jsonLibrary, pubnubLog); + PNTimeResult responseResult = responseBuilder.JsonToObject(resultList, true); + if (responseResult != null) { + returnValue.Result = responseResult; + } + } + } + } else { + int statusCode = PNStatusCodeHelper.GetHttpStatusCode(transportResponse.Error.Message); + PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, transportResponse.Error.Message); + PNStatus status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse(PNOperationType.PNTimeOperation, category, requestState, statusCode, new PNException(transportResponse.Error.Message, transportResponse.Error)); + returnValue.Status = status; + } + + return returnValue; + } + + internal void CurrentPubnubInstance(Pubnub instance) + { + PubnubInstance = instance; + } + + private RequestParameter CreateRequestParameter() + { + List pathSegments = new List + { + "time", + "0" + }; + + Dictionary requestQueryStringParams = new Dictionary(); + if (queryParam != null && queryParam.Count > 0) { + foreach (KeyValuePair kvp in queryParam) { + if (!requestQueryStringParams.ContainsKey(kvp.Key)) { + requestQueryStringParams.Add(kvp.Key, UriUtil.EncodeUriComponent(kvp.Value.ToString(), PNOperationType.PNTimeOperation, false, false, false)); + } + } + } + + var requestParameter = new RequestParameter() { + RequestType = Constants.GET, + PathSegment = pathSegments, + Query = requestQueryStringParams + }; + + return requestParameter; + } + } } diff --git a/src/Api/PubnubApi/Entity/Channel.cs b/src/Api/PubnubApi/Entity/Channel.cs new file mode 100644 index 000000000..eac4c787e --- /dev/null +++ b/src/Api/PubnubApi/Entity/Channel.cs @@ -0,0 +1,25 @@ +using System; +using System.Linq; +using PubnubApi.EventEngine.Common; + +namespace PubnubApi +{ + public class Channel + { + public string Name { get; set; } + private Pubnub Pubnub { get; set; } + private EventEmitter EventEmitter { get; set; } + + public Channel(string name, Pubnub pubnub, EventEmitter eventEmitter) + { + Name = name; + this.Pubnub = pubnub; + this.EventEmitter = eventEmitter; + } + + public Subscription Subscription(SubscriptionOptions? options = SubscriptionOptions.None) + { + return new Subscription(options == SubscriptionOptions.ReceivePresenceEvents ? new string[] { Name, $"{Name}{Constants.Pnpres}" } : new string[] { Name }, new string[] { }, options, this.Pubnub, this.EventEmitter); + } + } +} \ No newline at end of file diff --git a/src/Api/PubnubApi/Entity/ChannelGroup.cs b/src/Api/PubnubApi/Entity/ChannelGroup.cs new file mode 100644 index 000000000..17a5060a7 --- /dev/null +++ b/src/Api/PubnubApi/Entity/ChannelGroup.cs @@ -0,0 +1,24 @@ +using System; +using System.Linq; +using PubnubApi.EventEngine.Common; + +namespace PubnubApi +{ + public class ChannelGroup + { + public string Name { get; set; } + private Pubnub Pubnub { get; set; } + private EventEmitter EventEmitter { get; set; } + public ChannelGroup(string name, Pubnub pubnub, EventEmitter eventEmitter) + { + Name = name; + this.Pubnub = pubnub; + this.EventEmitter = eventEmitter; + } + + public Subscription Subscription(SubscriptionOptions? options = SubscriptionOptions.None) + { + return new Subscription(new string[] { }, options == SubscriptionOptions.ReceivePresenceEvents ? new string[] { Name, $"{Name}{Constants.Pnpres}" } : new string[] { Name }, options, this.Pubnub, this.EventEmitter); + } + } +} \ No newline at end of file diff --git a/src/Api/PubnubApi/Entity/ChannelMetadata.cs b/src/Api/PubnubApi/Entity/ChannelMetadata.cs new file mode 100644 index 000000000..1e09b9166 --- /dev/null +++ b/src/Api/PubnubApi/Entity/ChannelMetadata.cs @@ -0,0 +1,23 @@ +using PubnubApi.EventEngine.Common; + +namespace PubnubApi +{ + public class ChannelMetadata + { + public string Id { get; set; } + private Pubnub Pubnub { get; set; } + private EventEmitter EventEmitter { get; set; } + + public ChannelMetadata(string id, Pubnub pubnub, EventEmitter eventEmitter) + { + Id = id; + this.Pubnub = pubnub; + this.EventEmitter = eventEmitter; + } + + public Subscription Subscription(SubscriptionOptions options = SubscriptionOptions.None) + { + return new Subscription(options == SubscriptionOptions.ReceivePresenceEvents ? new string[] { Id, $"{Id}{Constants.Pnpres}" } : new string[] { Id }, new string[] { }, options, this.Pubnub, this.EventEmitter); + } + } +} diff --git a/src/Api/PubnubApi/Entity/SubscribeCapable.cs b/src/Api/PubnubApi/Entity/SubscribeCapable.cs new file mode 100644 index 000000000..4a8b85b96 --- /dev/null +++ b/src/Api/PubnubApi/Entity/SubscribeCapable.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using PubnubApi.EventEngine.Common; +using PubnubApi.EventEngine.Subscribe.Common; + +namespace PubnubApi +{ + public abstract class SubscribeCapable + { + public abstract List ChannelNames { get; set; } + public abstract List ChannelGroupNames { get; set; } + public abstract Pubnub Pubnub { get; set; } + public abstract EventEmitter EventEmitter { get; set; } + public abstract SubscriptionOptions? Options { get; set; } + protected abstract SubscribeCallbackExt Listener { get; set; } + + public abstract event Action> onMessage; + public abstract event Action onPresence; + public abstract event Action> onSignal; + public abstract event Action onObject; + public abstract event Action onMessageAction; + public abstract event Action onFile; + public abstract event Action onStatus; + + public void Subscribe(SubscriptionCursor cursor = null) + { + var subscription = this.Pubnub.Subscribe().Channels(this.ChannelNames.ToArray()).ChannelGroups(this.ChannelGroupNames.ToArray()); + if (cursor is not null && cursor.Timetoken != 0) { + var timetoken = cursor.Timetoken ?? 0; + subscription.WithTimetoken(timetoken).Execute(); + + } else { + subscription.Execute(); + } + } + + public void AddListener(SubscribeCallback listener) + { + this.EventEmitter.AddListener(listener, this.ChannelNames.ToArray(), this.ChannelGroupNames.ToArray()); + } + + public void RemoveListener(SubscribeCallback listener) + { + this.EventEmitter.RemoveListener(listener, this.ChannelNames.ToArray(), this.ChannelGroupNames.ToArray()); + } + + public void Unsubscribe() + { + this.Pubnub.Unsubscribe().Channels(ChannelNames.ToArray()).ChannelGroups(ChannelGroupNames.ToArray()).Execute(); + } + } +} + diff --git a/src/Api/PubnubApi/Entity/Subscription.cs b/src/Api/PubnubApi/Entity/Subscription.cs new file mode 100644 index 000000000..001d927b5 --- /dev/null +++ b/src/Api/PubnubApi/Entity/Subscription.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PubnubApi.EventEngine.Common; + +namespace PubnubApi +{ + public class Subscription : SubscribeCapable + { + public override List ChannelNames { get; set; } = new List(); + public override List ChannelGroupNames { get; set; } = new List(); + public override Pubnub Pubnub { get; set; } + public override EventEmitter EventEmitter { get; set; } + public override SubscriptionOptions? Options { get; set; } + protected override SubscribeCallbackExt Listener { get; set; } = new SubscribeCallbackExt(); + + public override event Action> onMessage; + public override event Action onPresence; + public override event Action> onSignal; + public override event Action onObject; + public override event Action onMessageAction; + public override event Action onFile; + public override event Action onStatus; + + public Subscription(string[] channels, string[] channelGroups, SubscriptionOptions? options, Pubnub pubnub, EventEmitter eventEmitter) + { + this.ChannelNames = channels.ToList(); + this.ChannelGroupNames = channelGroups.ToList(); + this.Pubnub = pubnub; + this.EventEmitter = eventEmitter; + this.Options = options; + + this.Listener = new SubscribeCallbackExt( + (pnObj, pubMsg) => { + onMessage?.Invoke(pnObj, pubMsg); + }, + (pnObj, presenceEvnt) => { + onPresence?.Invoke(pnObj, presenceEvnt); + }, + (pnObj, signalMsg) => { + onSignal?.Invoke(pnObj, signalMsg); + }, + (pnObj, objectEventObj) => { + onObject?.Invoke(pnObj, objectEventObj); + }, + (pnObj, msgActionEvent) => { + onMessageAction?.Invoke(pnObj, msgActionEvent); + }, + (pnObj, fileEvent) => { + onFile?.Invoke(pnObj, fileEvent); + }, + (pnObj, pnStatus) => { + onStatus?.Invoke(pnObj, pnStatus); + } + ); + this.EventEmitter.AddListener(Listener, channels: channels, groups: channelGroups); + } + + public SubscriptionSet Add(Subscription subscription) + { + this.ChannelNames.AddRange(subscription.ChannelNames); + this.ChannelGroupNames.AddRange(subscription.ChannelGroupNames); + return new SubscriptionSet(this.ChannelNames.ToArray(), this.ChannelGroupNames.ToArray(), this.Options, this.Pubnub, this.EventEmitter); + } + } +} \ No newline at end of file diff --git a/src/Api/PubnubApi/Entity/SubscriptionOptions.cs b/src/Api/PubnubApi/Entity/SubscriptionOptions.cs new file mode 100644 index 000000000..d0d93bc0b --- /dev/null +++ b/src/Api/PubnubApi/Entity/SubscriptionOptions.cs @@ -0,0 +1,6 @@ +using System; +namespace PubnubApi +{ + public enum SubscriptionOptions { None, ReceivePresenceEvents } +} + diff --git a/src/Api/PubnubApi/Entity/SubscriptionSet.cs b/src/Api/PubnubApi/Entity/SubscriptionSet.cs new file mode 100644 index 000000000..35aa29065 --- /dev/null +++ b/src/Api/PubnubApi/Entity/SubscriptionSet.cs @@ -0,0 +1,134 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using PubnubApi.EventEngine.Common; + +namespace PubnubApi +{ + + public class SubscriptionSet : SubscribeCapable + { + public override List ChannelNames { get; set; } = new List(); + public override List ChannelGroupNames { get; set; } = new List(); + public override Pubnub Pubnub { get; set; } + public override EventEmitter EventEmitter { get; set; } + public override SubscriptionOptions? Options { get; set; } + List SubscriptionList { get; set; } = new List(); + protected override SubscribeCallbackExt Listener { get; set; } = new SubscribeCallbackExt(); + + public override event Action> onMessage; + public override event Action onPresence; + public override event Action> onSignal; + public override event Action onObject; + public override event Action onMessageAction; + public override event Action onFile; + public override event Action onStatus; + + public SubscriptionSet(string[] channels, string[] channelGroups, SubscriptionOptions? options, Pubnub pubnub, EventEmitter eventEmitter) + { + this.Pubnub = pubnub; + this.EventEmitter = eventEmitter; + this.Options = options; + + foreach (var c in channels + .Where(c => !c.EndsWith(Constants.Pnpres))) { + var subscription = this.Pubnub.Channel(c).Subscription(this.Options); + this.ChannelNames.AddRange(subscription.ChannelNames); + this.SubscriptionList.Add(subscription); + } + + foreach (var cg in channelGroups + .Where(cg => !cg.EndsWith(Constants.Pnpres))) { + var subscription = this.Pubnub.ChannelGroup(cg).Subscription(this.Options); + this.ChannelGroupNames.AddRange(subscription.ChannelGroupNames); + this.SubscriptionList.Add(subscription); + } + + this.Listener = new SubscribeCallbackExt( + (pnObj, pubMsg) => { + onMessage?.Invoke(pnObj, pubMsg); + }, + (pnObj, presenceEvnt) => { + onPresence?.Invoke(pnObj, presenceEvnt); + }, + (pnObj, signalMsg) => { + onSignal?.Invoke(pnObj, signalMsg); + }, + (pnObj, objectEventObj) => { + onObject?.Invoke(pnObj, objectEventObj); + }, + (pnObj, msgActionEvent) => { + onMessageAction?.Invoke(pnObj, msgActionEvent); + }, + (pnObj, fileEvent) => { + onFile?.Invoke(pnObj, fileEvent); + }, + (pnObj, pnStatus) => { + + onStatus?.Invoke(pnObj, pnStatus); + } + ); + this.EventEmitter.AddListener(Listener, channels: channels, groups: channelGroups ); + } + + public SubscriptionSet Add(Subscription subscription) + { + this.SubscriptionList.ToList().Add(subscription); + if (subscription.ChannelNames.Count > 0) { + this.ChannelNames.AddRange(subscription.ChannelNames); + } + if (subscription.ChannelGroupNames.Count > 0) { + this.ChannelGroupNames.AddRange(subscription.ChannelGroupNames); + } + this.EventEmitter.AddListener(this.Listener, subscription.ChannelNames.ToArray(), subscription.ChannelGroupNames.ToArray()); + return this; + } + + public SubscriptionSet Remove(Subscription subscription) + { + this.SubscriptionList.Remove(subscription); + if (subscription.ChannelNames.Count > 0) { + foreach (var c in subscription.ChannelNames) { + this.ChannelNames.Remove(c); + } + } + if (subscription.ChannelGroupNames.Count > 0) { + foreach (var g in subscription.ChannelGroupNames) { + this.ChannelGroupNames.Remove(g); + } + } + this.EventEmitter.RemoveListener(this.Listener, subscription.ChannelNames.ToArray(), subscription.ChannelGroupNames.ToArray()); + return this; + } + + public SubscriptionSet Add(SubscriptionSet subscriptionSet) + { + this.SubscriptionList.AddRange(subscriptionSet.SubscriptionList); + if (subscriptionSet.ChannelNames.Count > 0) { + this.ChannelNames.AddRange(subscriptionSet.ChannelNames); + } + if (subscriptionSet.ChannelGroupNames.Count > 0) { + this.ChannelGroupNames.AddRange(subscriptionSet.ChannelGroupNames); + } + this.EventEmitter.AddListener(this.Listener, subscriptionSet.ChannelNames.ToArray(), subscriptionSet.ChannelGroupNames.ToArray()); + return this; + } + + public SubscriptionSet Remove(SubscriptionSet subscriptionSet) + { + SubscriptionList = this.SubscriptionList.Except(subscriptionSet.SubscriptionList).ToList(); + if (subscriptionSet.ChannelNames.Count > 0) { + foreach (var c in subscriptionSet.ChannelNames) { + this.ChannelNames.Remove(c); + } + } + if (subscriptionSet.ChannelGroupNames.Count > 0) { + foreach (var g in subscriptionSet.ChannelGroupNames) { + this.ChannelGroupNames.Remove(g); + } + } + this.EventEmitter.RemoveListener(this.Listener, subscriptionSet.ChannelNames.ToArray(), subscriptionSet.ChannelGroupNames.ToArray()); + return this; + } + } +} \ No newline at end of file diff --git a/src/Api/PubnubApi/Entity/UserMetadata.cs b/src/Api/PubnubApi/Entity/UserMetadata.cs new file mode 100644 index 000000000..f75baf756 --- /dev/null +++ b/src/Api/PubnubApi/Entity/UserMetadata.cs @@ -0,0 +1,24 @@ +using PubnubApi.EventEngine.Common; + +namespace PubnubApi +{ + public class UserMetadata + { + public string Id { get; set; } + private Pubnub Pubnub { get; set; } + private EventEmitter EventEmitter { get; set; } + + public UserMetadata(string id, Pubnub pubnub, EventEmitter eventEmitter) + { + Id = id; + this.Pubnub = pubnub; + this.EventEmitter = eventEmitter; + } + + public Subscription Subscription(SubscriptionOptions options = SubscriptionOptions.None) + { + return new Subscription(options == SubscriptionOptions.ReceivePresenceEvents ? new string[] { Id, $"{Id}{Constants.Pnpres}" } : new string[] { Id }, new string[] { }, options, this.Pubnub, this.EventEmitter); + } + } +} + diff --git a/src/Api/PubnubApi/EventEngine/Common/EventEmitter.cs b/src/Api/PubnubApi/EventEngine/Common/EventEmitter.cs index b78bc6d9a..3f142def4 100644 --- a/src/Api/PubnubApi/EventEngine/Common/EventEmitter.cs +++ b/src/Api/PubnubApi/EventEngine/Common/EventEmitter.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Globalization; using PubnubApi.EndPoint; using PubnubApi.EventEngine.Subscribe.Common; using PubnubApi.Security.Crypto; using PubnubApi.Security.Crypto.Cryptors; +using Newtonsoft.Json.Linq; namespace PubnubApi.EventEngine.Common { @@ -16,6 +18,8 @@ public class EventEmitter private IJsonPluggableLibrary jsonLibrary; private Pubnub instance; private TokenManager tokenManager; + private Dictionary> channelListenersMap; + private Dictionary> channelGroupListenersMap; public EventEmitter(PNConfiguration configuration, List listenerCallbacks, IJsonPluggableLibrary jsonPluggableLibrary, TokenManager tokenManager, IPubnubLog log, Pubnub instance) { @@ -25,6 +29,8 @@ public EventEmitter(PNConfiguration configuration, List liste this.tokenManager = tokenManager; jsonLibrary = jsonPluggableLibrary; listeners = listenerCallbacks; + channelGroupListenersMap = new Dictionary>(); + channelListenersMap = new Dictionary>(); } private TimetokenMetadata GetTimetokenMetadata(object t) @@ -47,6 +53,39 @@ private TimetokenMetadata GetTimetokenMetadata(object t) return null; } + public void AddListener(SubscribeCallback listener, string[] channels, string[] groups) + { + foreach (var c in channels.Where(c => !c.EndsWith("-pnpres"))) { + if (channelListenersMap.ContainsKey(c)) { + channelListenersMap[c].Add(listener); + } else { + channelListenersMap[c] = new List { listener }; + } + } + + foreach (var cg in groups.Where(cg => !cg.EndsWith("-pnpres"))) { + if (channelGroupListenersMap.ContainsKey(cg)) { + channelGroupListenersMap[cg].Add(listener); + } else { + channelGroupListenersMap[cg] = new List { listener }; + } + } + } + + public void RemoveListener(SubscribeCallback listener, string[] channels, string[] groups) + { + foreach (var c in channels.Where(c => !c.EndsWith("-pnpres"))) { + if (channelListenersMap.ContainsKey(c)) { + channelListenersMap[c].Remove(listener); + } + } + foreach (var cg in groups.Where(cg => !cg.EndsWith("-pnpres"))) { + if (channelGroupListenersMap.ContainsKey(cg)) { + channelGroupListenersMap[cg].Remove(listener); + } + } + } + public void EmitEvent(object e) { Message eventData = e as Message; @@ -57,14 +96,21 @@ public void EmitEvent(object e) if (currentMessageChannel.Replace("-pnpres", "") == currentMessageChannelGroup?.Replace("-pnpres", "")) { currentMessageChannelGroup = ""; } - object payload = eventData.Payload; + object payload; + string payloadAsString = eventData.Payload as string; + if (payloadAsString != null) { + var jsonObject = jsonLibrary.BuildJsonObject(payloadAsString.ToString()); + payload = jsonObject ?? payloadAsString; + } else { + payload = eventData.Payload; + } List payloadContainer = new List(); //First item always message if (currentMessageChannel.Contains("-pnpres") || currentMessageChannel.Contains(".*-pnpres")) { payloadContainer.Add(payload); } else if (eventData.MessageType == 2) //Objects Simplification events { double objectsVersion = -1; - Dictionary objectsDic = payload as Dictionary; + Dictionary objectsDic = payload as Dictionary ?? (payload as JObject).ToObject>(); if (objectsDic != null && objectsDic.ContainsKey("source") && objectsDic.ContainsKey("version") @@ -76,10 +122,10 @@ public void EmitEvent(object e) } } } else { - if ((configuration.CryptoModule != null || configuration.CipherKey.Length > 0) && eventData.MessageType != 1) //decrypt the subscriber message if cipherkey is available + if ((configuration.CryptoModule != null || configuration.CipherKey.Length > 0) && (eventData.MessageType == 0 || eventData.MessageType == 4)) //decrypt the subscriber message if cipherkey is available { string decryptMessage = ""; - configuration.CryptoModule ??= new CryptoModule(new LegacyCryptor(configuration.CipherKey, configuration.UseRandomInitializationVector, log), null); + configuration.CryptoModule ??= new CryptoModule(new AesCbcCryptor(configuration.CipherKey, log), new List() { new LegacyCryptor(configuration.CipherKey, configuration.UseRandomInitializationVector) }); try { decryptMessage = configuration.CryptoModule.Decrypt(payload.ToString()); } catch (Exception ex) { @@ -112,7 +158,7 @@ public void EmitEvent(object e) payloadContainer.Add(userMetaData); //Second one always user meta data - payloadContainer.Add(GetTimetokenMetadata(eventData.PublishMetadata)); //Third one always Timetoken + payloadContainer.Add(GetTimetokenMetadata(eventData.PublishMetadata).Timetoken); //Third one always Timetoken payloadContainer.Add(eventData.IssuingClientId); //Fourth one always Publisher @@ -140,6 +186,16 @@ public void EmitEvent(object e) foreach (var listener in listeners) { listener?.Signal(instance, signalMessage); } + if (!string.IsNullOrEmpty(signalMessage.Channel) && channelListenersMap.ContainsKey(signalMessage.Channel)) { + foreach (var l in channelListenersMap[signalMessage.Channel]) { + l?.Signal(instance, signalMessage); + } + } + if (!string.IsNullOrEmpty(signalMessage.Subscription) && channelGroupListenersMap.ContainsKey(signalMessage.Subscription)) { + foreach (var l in channelGroupListenersMap[signalMessage.Subscription]) { + l?.Signal(instance, signalMessage); + } + } } } else if (eventData.MessageType == 2) { ResponseBuilder responseBuilder = new ResponseBuilder(configuration, jsonLibrary, log); @@ -148,6 +204,16 @@ public void EmitEvent(object e) foreach (var listener in listeners) { listener?.ObjectEvent(instance, objectApiEvent); } + if (!string.IsNullOrEmpty(objectApiEvent.Channel) && channelListenersMap.ContainsKey(objectApiEvent.Channel)) { + foreach (var l in channelListenersMap[objectApiEvent.Channel]) { + l?.ObjectEvent(instance, objectApiEvent); + } + } + if (!string.IsNullOrEmpty(objectApiEvent.Subscription) && channelGroupListenersMap.ContainsKey(objectApiEvent.Subscription)) { + foreach (var l in channelGroupListenersMap[objectApiEvent.Subscription]) { + l?.ObjectEvent(instance, objectApiEvent); + } + } } } else if (eventData.MessageType == 3) { ResponseBuilder responseBuilder = new ResponseBuilder(configuration, jsonLibrary, log); @@ -156,6 +222,16 @@ public void EmitEvent(object e) foreach (var listener in listeners) { listener?.MessageAction(instance, messageActionEvent); } + if (!string.IsNullOrEmpty(messageActionEvent.Channel) && channelListenersMap.ContainsKey(messageActionEvent.Channel)) { + foreach (var l in channelListenersMap[messageActionEvent.Channel]) { + l?.MessageAction(instance, messageActionEvent); + } + } + if (!string.IsNullOrEmpty(messageActionEvent.Subscription) && channelGroupListenersMap.ContainsKey(messageActionEvent.Subscription)) { + foreach (var l in channelGroupListenersMap[messageActionEvent.Subscription]) { + l?.MessageAction(instance, messageActionEvent); + } + } } } else if (eventData.MessageType == 4) { ResponseBuilder responseBuilder = new ResponseBuilder(configuration, jsonLibrary, log); @@ -177,7 +253,7 @@ public void EmitEvent(object e) if (fileObjDic != null && fileObjDic.ContainsKey("id") && fileObjDic.ContainsKey("name")) { fileMessage.File = new PNFile { Id = fileObjDic["id"].ToString(), Name = fileObjDic["name"].ToString() }; - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(configuration, jsonLibrary, null, log, null, tokenManager, (instance != null) ? instance.InstanceId : ""); + IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(configuration, jsonLibrary, null, log, tokenManager, (instance != null) ? instance.InstanceId : ""); Uri fileUrlRequest = urlBuilder.BuildGetFileUrlOrDeleteReqest("GET", "", fileMessage.Channel, fileMessage.File.Id, fileMessage.File.Name, null, PNOperationType.PNGenerateFileUploadUrlOperation); fileMessage.File.Url = fileUrlRequest.ToString(); } @@ -190,24 +266,53 @@ public void EmitEvent(object e) foreach (var listener in listeners) { listener?.File(instance, fileMessage); } + if (!string.IsNullOrEmpty(fileMessage.Channel) && channelListenersMap.ContainsKey(fileMessage.Channel)) { + foreach (var l in channelListenersMap[fileMessage.Channel]) { + l?.File(instance, fileMessage); + } + } + if (!string.IsNullOrEmpty(fileMessage.Subscription) && channelGroupListenersMap.ContainsKey(fileMessage.Subscription)) { + foreach (var l in channelGroupListenersMap[fileMessage.Subscription]) { + l?.File(instance, fileMessage); + } + } } - } - else if (currentMessageChannel.Contains("-pnpres")) { + } else if (currentMessageChannel.Contains("-pnpres")) { ResponseBuilder responseBuilder = new ResponseBuilder(configuration, jsonLibrary, log); PNPresenceEventResult presenceEvent = responseBuilder.JsonToObject(payloadContainer, true); if (presenceEvent != null) { foreach (var listener in listeners) { listener?.Presence(instance, presenceEvent); } + if (!string.IsNullOrEmpty(presenceEvent.Channel) && channelListenersMap.ContainsKey(presenceEvent.Channel)) { + foreach (var l in channelListenersMap[presenceEvent.Channel]) { + l?.Presence(instance, presenceEvent); + } + } + if (!string.IsNullOrEmpty(presenceEvent.Subscription) && channelGroupListenersMap.ContainsKey(presenceEvent.Subscription)) { + foreach (var l in channelGroupListenersMap[presenceEvent.Subscription]) { + l?.Presence(instance, presenceEvent); + } + } } - } - else { + + } else { ResponseBuilder responseBuilder = new ResponseBuilder(configuration, jsonLibrary, log); PNMessageResult message = responseBuilder.JsonToObject>(payloadContainer, true); if (message != null) { foreach (var listener in listeners) { listener?.Message(instance, message); } + if (!string.IsNullOrEmpty(message.Channel) && channelListenersMap.ContainsKey(message.Channel)) { + foreach (var l in channelListenersMap[message.Channel]) { + l?.Message(instance, message); + } + } + if (!string.IsNullOrEmpty(message.Subscription) && channelGroupListenersMap.ContainsKey(message.Subscription)) { + foreach (var l in channelGroupListenersMap[message.Subscription]) { + l?.Message(instance, message); + } + } } } } diff --git a/src/Api/PubnubApi/EventEngine/Presence/PresenceEventEngineFactory.cs b/src/Api/PubnubApi/EventEngine/Presence/PresenceEventEngineFactory.cs index 53afdd87f..631729f3e 100644 --- a/src/Api/PubnubApi/EventEngine/Presence/PresenceEventEngineFactory.cs +++ b/src/Api/PubnubApi/EventEngine/Presence/PresenceEventEngineFactory.cs @@ -25,10 +25,10 @@ internal PresenceEventEngine GetEventEngine(string instanceId) } internal PresenceEventEngine InitializeEventEngine(string instanceId, - Pubnub pubnubInstance, IPubnubLog pubnubLog, TelemetryManager telemetryManager, TokenManager tokenManager) + Pubnub pubnubInstance, IPubnubLog pubnubLog, TokenManager tokenManager) { - HeartbeatOperation heartbeatOperation = new HeartbeatOperation(pubnubInstance.PNConfig, pubnubInstance.JsonPluggableLibrary, pubnubInstance.PubnubUnitTest, pubnubLog, telemetryManager, tokenManager, pubnubInstance); - LeaveOperation leaveOperation = new LeaveOperation(pubnubInstance.PNConfig, pubnubInstance.JsonPluggableLibrary, pubnubInstance.PubnubUnitTest, pubnubLog, telemetryManager, tokenManager, pubnubInstance); + HeartbeatOperation heartbeatOperation = new HeartbeatOperation(pubnubInstance.PNConfig, pubnubInstance.JsonPluggableLibrary, pubnubInstance.PubnubUnitTest, pubnubLog, tokenManager, pubnubInstance); + LeaveOperation leaveOperation = new LeaveOperation(pubnubInstance.PNConfig, pubnubInstance.JsonPluggableLibrary, pubnubInstance.PubnubUnitTest, pubnubLog, tokenManager, pubnubInstance); var presenceEventEngine = new PresenceEventEngine(pubnubInstance.PNConfig, heartbeatOperation, leaveOperation); if (engineInstances.TryAdd(instanceId, presenceEventEngine)) { return presenceEventEngine; diff --git a/src/Api/PubnubApi/EventEngine/Subscribe/Common/CommonSubscribeTypes.cs b/src/Api/PubnubApi/EventEngine/Subscribe/Common/CommonSubscribeTypes.cs index c4ca56369..008adb92d 100644 --- a/src/Api/PubnubApi/EventEngine/Subscribe/Common/CommonSubscribeTypes.cs +++ b/src/Api/PubnubApi/EventEngine/Subscribe/Common/CommonSubscribeTypes.cs @@ -1,18 +1,28 @@ using Newtonsoft.Json; using System.Collections.Generic; +namespace PubnubApi +{ + public class SubscriptionCursor + { + public long? Timetoken { get; set; } + public int? Region { get; set; } + public SubscriptionCursor() {} + public SubscriptionCursor(long? timetoken, int? region = null) + { + this.Timetoken = timetoken; + this.Region = region; + } + + } +} + namespace PubnubApi.EventEngine.Subscribe.Common { - public class SubscriptionCursor - { - public long? Timetoken { get; set; } - public int? Region { get; set; } - } - - public class HandshakeResponse - { - [JsonProperty("t")] - public Timetoken Timetoken { get; set; } + public class HandshakeResponse + { + [JsonProperty("t")] + public Timetoken Timetoken { get; set; } [JsonProperty("m")] public object[] Messages { get; set; } diff --git a/src/Api/PubnubApi/EventEngine/Subscribe/Effects/HandshakeEffectHandler.cs b/src/Api/PubnubApi/EventEngine/Subscribe/Effects/HandshakeEffectHandler.cs index edc736288..bf3aa197a 100644 --- a/src/Api/PubnubApi/EventEngine/Subscribe/Effects/HandshakeEffectHandler.cs +++ b/src/Api/PubnubApi/EventEngine/Subscribe/Effects/HandshakeEffectHandler.cs @@ -124,11 +124,11 @@ public override async Task Run(HandshakeReconnectInvocation invocation) { if (retryConfiguration == null) { - eventQueue.Enqueue(new HandshakeReconnectGiveUpEvent() { Status = new PNStatus(new Exception(""), PNOperationType.PNSubscribeOperation, PNStatusCategory.PNConnectionErrorCategory, invocation.Channels, invocation.ChannelGroups ) }); + eventQueue.Enqueue(new HandshakeReconnectGiveUpEvent() { Status = new PNStatus(new Exception(""), PNOperationType.PNSubscribeOperation, PNStatusCategory.PNConnectionErrorCategory, invocation.Channels, invocation.ChannelGroups, invocation.Reason.StatusCode ) }); } else if (!retryConfiguration.RetryPolicy.ShouldRetry(invocation.AttemptedRetries, invocation.Reason)) { - eventQueue.Enqueue(new HandshakeReconnectGiveUpEvent() { Status = new PNStatus(new Exception(""), PNOperationType.PNSubscribeOperation, PNStatusCategory.PNConnectionErrorCategory, invocation.Channels, invocation.ChannelGroups ) }); + eventQueue.Enqueue(new HandshakeReconnectGiveUpEvent() { Status = new PNStatus(new Exception(""), PNOperationType.PNSubscribeOperation, PNStatusCategory.PNConnectionErrorCategory, invocation.Channels, invocation.ChannelGroups, invocation.Reason.StatusCode ) }); } else { diff --git a/src/Api/PubnubApi/EventEngine/Subscribe/Effects/ReceivingEffectHandler.cs b/src/Api/PubnubApi/EventEngine/Subscribe/Effects/ReceivingEffectHandler.cs index f632ad53a..d9a5526cf 100644 --- a/src/Api/PubnubApi/EventEngine/Subscribe/Effects/ReceivingEffectHandler.cs +++ b/src/Api/PubnubApi/EventEngine/Subscribe/Effects/ReceivingEffectHandler.cs @@ -98,11 +98,11 @@ public override async Task Run(ReceiveReconnectInvocation invocation) var retryConfiguration = pubnubConfiguration.RetryConfiguration; if (retryConfiguration == null) { - eventQueue.Enqueue(new ReceiveReconnectGiveUpEvent() { Status = new PNStatus(new Exception(""), PNOperationType.PNSubscribeOperation, PNStatusCategory.PNUnexpectedDisconnectCategory, invocation.Channels, invocation.ChannelGroups ) }); + eventQueue.Enqueue(new ReceiveReconnectGiveUpEvent() { Status = new PNStatus(new Exception(""), PNOperationType.PNSubscribeOperation, PNStatusCategory.PNUnexpectedDisconnectCategory, invocation.Channels, invocation.ChannelGroups, invocation.Reason.StatusCode ) }); } else if (!retryConfiguration.RetryPolicy.ShouldRetry(invocation.AttemptedRetries, invocation.Reason)) { - eventQueue.Enqueue(new ReceiveReconnectGiveUpEvent() { Status = new PNStatus(new Exception(""), PNOperationType.PNSubscribeOperation, PNStatusCategory.PNUnexpectedDisconnectCategory, invocation.Channels, invocation.ChannelGroups ) }); + eventQueue.Enqueue(new ReceiveReconnectGiveUpEvent() { Status = new PNStatus(new Exception(""), PNOperationType.PNSubscribeOperation, PNStatusCategory.PNUnexpectedDisconnectCategory, invocation.Channels, invocation.ChannelGroups, invocation.Reason.StatusCode ) }); } else { diff --git a/src/Api/PubnubApi/EventEngine/Subscribe/Invocations/SubscriptionInvocations.cs b/src/Api/PubnubApi/EventEngine/Subscribe/Invocations/SubscriptionInvocations.cs index 22a8cb808..582e33331 100644 --- a/src/Api/PubnubApi/EventEngine/Subscribe/Invocations/SubscriptionInvocations.cs +++ b/src/Api/PubnubApi/EventEngine/Subscribe/Invocations/SubscriptionInvocations.cs @@ -17,6 +17,7 @@ public class EmitStatusInvocation : Core.IEffectInvocation { // TODO merge status variables into one? public PNStatusCategory StatusCategory; public PNStatus Status; + public int StatusCode; public string Name { get; set; } = "EMIT_STATUS"; public EmitStatusInvocation(PNStatus status) @@ -25,6 +26,7 @@ public EmitStatusInvocation(PNStatus status) if (status != null) { this.StatusCategory = status.Category; + this.StatusCode = status.StatusCode; } } diff --git a/src/Api/PubnubApi/EventEngine/Subscribe/States/HandshakeReconnectingState.cs b/src/Api/PubnubApi/EventEngine/Subscribe/States/HandshakeReconnectingState.cs index 68a5ebf6b..ea803c84b 100644 --- a/src/Api/PubnubApi/EventEngine/Subscribe/States/HandshakeReconnectingState.cs +++ b/src/Api/PubnubApi/EventEngine/Subscribe/States/HandshakeReconnectingState.cs @@ -40,7 +40,7 @@ public override TransitionResult Transition(IEvent e) Channels = this.Channels, ChannelGroups = this.ChannelGroups, }.With( - new EmitStatusInvocation(handshakeReconnectGiveUp.Status) + new EmitStatusInvocation(new PNStatus(handshakeReconnectGiveUp.Status) ) ), Events.HandshakeReconnectFailureEvent handshakeReconnectFailure => new HandshakeReconnectingState() { diff --git a/src/Api/PubnubApi/EventEngine/Subscribe/SubscribeEventEngine.cs b/src/Api/PubnubApi/EventEngine/Subscribe/SubscribeEventEngine.cs index 5b49f0039..b23405b6b 100644 --- a/src/Api/PubnubApi/EventEngine/Subscribe/SubscribeEventEngine.cs +++ b/src/Api/PubnubApi/EventEngine/Subscribe/SubscribeEventEngine.cs @@ -3,7 +3,6 @@ using PubnubApi.EventEngine.Subscribe.States; using System.Collections.Generic; using System.Linq; -using PubnubApi.EventEngine.Subscribe.Common; using System; using PubnubApi.EventEngine.Subscribe.Events; using PubnubApi.EventEngine.Common; @@ -17,15 +16,15 @@ public class SubscribeEventEngine : Engine private readonly Dictionary channelGroupTypeMap = new Dictionary(); private readonly IJsonPluggableLibrary jsonPluggableLibrary; - public string[] Channels { get; set; } = new string[] {}; - public string[] Channelgroups { get; set; } = new string[] {}; + public List Channels { get; set; } = new List(); + public List ChannelGroups { get; set; } = new List(); internal SubscribeEventEngine(Pubnub pubnubInstance, PNConfiguration pubnubConfiguration, SubscribeManager2 subscribeManager, - EventEmitter eventEmitter, + EventEmitter eventEmitter, IJsonPluggableLibrary jsonPluggableLibrary, - Action statusListener = null) + Action statusListener = null) { this.subscribeManager = subscribeManager; this.jsonPluggableLibrary = jsonPluggableLibrary; @@ -55,27 +54,25 @@ internal SubscribeEventEngine(Pubnub pubnubInstance, } public void Subscribe(string[] channels, string[] channelGroups, SubscriptionCursor cursor) { - foreach (var c in channels) - { + Channels.AddRange(channels); + ChannelGroups.AddRange(channelGroups); + + foreach (var c in channels) { channelTypeMap[c] = typeof(T); } - foreach (var c in channelGroups) - { + foreach (var c in channelGroups) { channelGroupTypeMap[c] = typeof(T); } - if (cursor != null) - { + if (cursor != null) { EventQueue.Enqueue(new SubscriptionRestoredEvent() { - Channels = Channels.Concat(channels ?? new string[] {}), - ChannelGroups = Channelgroups.Concat(channelGroups ?? new string[] {}), + Channels = Channels.Concat(channels ?? new string[] { }).Distinct(), + ChannelGroups = ChannelGroups.Concat(channelGroups ?? new string[] { }).Distinct(), Cursor = cursor }); - } - else - { + } else { EventQueue.Enqueue(new SubscriptionChangedEvent() { - Channels = Channels.Concat(channels??new string[] {}), - ChannelGroups = Channelgroups.Concat(channelGroups?? new string[] {}) + Channels = Channels.Concat(channels ?? new string[] { }).Distinct(), + ChannelGroups = ChannelGroups.Concat(channelGroups ?? new string[] { }).Distinct() }); } } @@ -84,7 +81,7 @@ public void Subscribe(string[] channels, string[] channelGroups, SubscriptionCur { Subscribe(channels, channelGroups, cursor); } - + public void UnsubscribeAll() { EventQueue.Enqueue(new UnsubscribeAllEvent()); @@ -92,17 +89,9 @@ public void UnsubscribeAll() public void Unsubscribe(string[] channels, string[] channelGroups) { - var channelNames = new List(); - var groupNames = new List(); - foreach (var channel in channels?? Enumerable.Empty()) { - channelNames.Add($"{channel}-pnpres"); - } - foreach (var cg in channelGroups ?? Enumerable.Empty()) { - groupNames.Add($"{cg}-pnpres"); - } this.EventQueue.Enqueue(new SubscriptionChangedEvent() { - Channels = (this.currentState as SubscriptionState).Channels?.Except(channels?.Union(channelNames)??Enumerable.Empty()), - ChannelGroups = (this.currentState as SubscriptionState).ChannelGroups?.Except(channelGroups?.Union(groupNames)??Enumerable.Empty()) + Channels = this.Channels?.Except(channels ?? Enumerable.Empty()), + ChannelGroups = this.ChannelGroups?.Except(channelGroups ?? Enumerable.Empty()) }); } } diff --git a/src/Api/PubnubApi/EventListener.cs b/src/Api/PubnubApi/EventListener.cs new file mode 100644 index 000000000..2497ec72f --- /dev/null +++ b/src/Api/PubnubApi/EventListener.cs @@ -0,0 +1,63 @@ +using System; +namespace PubnubApi +{ + public class EventListener { + public event Action> onMessage; + public event Action onPresence; + public event Action> onSignal; + public event Action onObject; + public event Action onMessageAction; + public event Action onFile; + public event Action onStatus; + + protected SubscribeCallbackExt listener; + + public EventListener( + Action> messageCallback, + Action presenceCallback, + Action> signalCallback, + Action objectEventCallback, + Action messageActionCallback, + Action fileCallback, + Action statusCallback) : this() { + this.onMessage += messageCallback; + this.onPresence += presenceCallback; + this.onSignal += signalCallback; + this.onObject += objectEventCallback; + this.onMessageAction += messageActionCallback; + this.onFile += fileCallback; + this.onStatus += statusCallback; + } + + public EventListener() { + this.listener = new SubscribeCallbackExt( + (pnObj, pubMsg) => { + onMessage?.Invoke(pnObj, pubMsg); + }, + (pnObj, presenceEvnt) => { + onPresence?.Invoke(pnObj, presenceEvnt); + }, + (pnObj, signalMsg) => { + onSignal?.Invoke(pnObj, signalMsg); + }, + (pnObj, objectEventObj) => { + onObject?.Invoke(pnObj, objectEventObj); + }, + (pnObj, msgActionEvent) => { + onMessageAction?.Invoke(pnObj, msgActionEvent); + }, + (pnObj, fileEvent) => { + onFile?.Invoke(pnObj, fileEvent); + }, + (pnObj, pnStatus) => { + onStatus?.Invoke(pnObj, pnStatus); + } + ); + } + + public static implicit operator SubscribeCallback(EventListener listener) { + return listener.listener; + } + } +} + diff --git a/src/Api/PubnubApi/JsonDataParse/PNMessageActionEventJsonDataParse.cs b/src/Api/PubnubApi/JsonDataParse/PNMessageActionEventJsonDataParse.cs index 0c5bddcd3..e80b54538 100644 --- a/src/Api/PubnubApi/JsonDataParse/PNMessageActionEventJsonDataParse.cs +++ b/src/Api/PubnubApi/JsonDataParse/PNMessageActionEventJsonDataParse.cs @@ -44,7 +44,13 @@ internal static PNMessageActionEventResult GetObject(IJsonPluggableLibrary jsonP } } result.Uuid = listObject[3].ToString(); - result.Channel = listObject[4].ToString(); + if (listObject.Count == 6) { + result.Subscription = listObject[4].ToString(); + result.Channel = listObject[5].ToString(); + } else if (listObject.Count == 5) { + result.Channel = listObject[4].ToString(); + } + } return result; diff --git a/src/Api/PubnubApi/JsonDataParse/PNObjectEventJsonDataParse.cs b/src/Api/PubnubApi/JsonDataParse/PNObjectEventJsonDataParse.cs index 548b3acc7..ea2d2824d 100644 --- a/src/Api/PubnubApi/JsonDataParse/PNObjectEventJsonDataParse.cs +++ b/src/Api/PubnubApi/JsonDataParse/PNObjectEventJsonDataParse.cs @@ -88,8 +88,12 @@ internal static PNObjectEventResult GetObject(IJsonPluggableLibrary jsonPlug, Li } } } - - result.Channel = (listObject.Count == 6) ? listObject[5].ToString() : listObject[4].ToString(); + if (listObject.Count == 6) { + result.Subscription = listObject[4].ToString(); + result.Channel = listObject[5].ToString(); + } else if (listObject.Count == 5) { + result.Channel = listObject[4].ToString(); + } } return result; diff --git a/src/Api/PubnubApi/Model/Consumer/PNStatus.cs b/src/Api/PubnubApi/Model/Consumer/PNStatus.cs index 2c0d34eb3..361ece757 100644 --- a/src/Api/PubnubApi/Model/Consumer/PNStatus.cs +++ b/src/Api/PubnubApi/Model/Consumer/PNStatus.cs @@ -14,7 +14,7 @@ public class PNStatus public PNStatus() { } - public PNStatus(Exception e, PNOperationType operationType, PNStatusCategory category, IEnumerable affectedChannels = null, IEnumerable affectedChannelGroups = null) + public PNStatus(Exception e, PNOperationType operationType, PNStatusCategory category, IEnumerable affectedChannels = null, IEnumerable affectedChannelGroups = null, int? statusCode = null) { this.Error = e != null; this.Operation = operationType; @@ -22,6 +22,7 @@ public PNStatus(Exception e, PNOperationType operationType, PNStatusCategory cat this.AffectedChannels = affectedChannels?.ToList(); this.AffectedChannelGroups = affectedChannelGroups?.ToList(); this.Category = category; + this.StatusCode = statusCode ?? 200; if (!Error) { this.StatusCode = 200; @@ -31,10 +32,17 @@ public PNStatus(Exception e, PNOperationType operationType, PNStatusCategory cat internal PNStatus(object endpointOperation) { this.savedEndpointOperation = endpointOperation; + if(endpointOperation is PNStatus) { + var status = (PNStatus)endpointOperation; + this.Error = status.Error; + this.Category = status.Category; + this.StatusCode = status.StatusCode; + this.ErrorData = status.ErrorData; + } } [JsonConverter(typeof(StringEnumConverter))] - public PNStatusCategory Category { get; internal set; } + public PNStatusCategory Category { get; set; } public PNErrorData ErrorData { get; internal set; } public bool Error { get; internal set; } diff --git a/src/Api/PubnubApi/Model/Consumer/Pubsub/PNMessageActionEventResult.cs b/src/Api/PubnubApi/Model/Consumer/Pubsub/PNMessageActionEventResult.cs index f028d2d21..0bcd3193a 100644 --- a/src/Api/PubnubApi/Model/Consumer/Pubsub/PNMessageActionEventResult.cs +++ b/src/Api/PubnubApi/Model/Consumer/Pubsub/PNMessageActionEventResult.cs @@ -10,5 +10,6 @@ public class PNMessageActionEventResult public PNMessageAction Action { get; internal set; } public string Uuid { get; internal set; } public string Channel { get; internal set; } + public string Subscription { get; internal set; } } } diff --git a/src/Api/PubnubApi/Model/Consumer/Pubsub/PNObjectEventResult.cs b/src/Api/PubnubApi/Model/Consumer/Pubsub/PNObjectEventResult.cs index 2846236b4..e6bf4ebb0 100644 --- a/src/Api/PubnubApi/Model/Consumer/Pubsub/PNObjectEventResult.cs +++ b/src/Api/PubnubApi/Model/Consumer/Pubsub/PNObjectEventResult.cs @@ -19,5 +19,6 @@ public PNObjectEventResult() public PNChannelMetadataResult ChannelMetadata { get; internal set; } //Populate when Type = channel public long Timestamp { get; internal set; } public string Channel { get; internal set; } //Subscribed channel + public string Subscription { get; internal set; } } } diff --git a/src/Api/PubnubApi/Model/Derived/Pubsub/SubscribeCallbackExt.cs b/src/Api/PubnubApi/Model/Derived/Pubsub/SubscribeCallbackExt.cs index 5817f6193..08b35dd7f 100644 --- a/src/Api/PubnubApi/Model/Derived/Pubsub/SubscribeCallbackExt.cs +++ b/src/Api/PubnubApi/Model/Derived/Pubsub/SubscribeCallbackExt.cs @@ -7,181 +7,246 @@ namespace PubnubApi { - public class SubscribeCallbackExt : SubscribeCallback - { - readonly Action> subscribeAction; - readonly Action presenceAction; - readonly Action> signalAction; - readonly Action statusAction; - readonly Action objectEventAction; - readonly Action messageAction; - readonly Action fileAction; - - public SubscribeCallbackExt(Action> messageCallback, Action presenceCallback, Action statusCallback) - { - subscribeAction = messageCallback; - presenceAction = presenceCallback; - statusAction = statusCallback; - signalAction = null; - objectEventAction = null; - fileAction = null; - } - - public SubscribeCallbackExt(Action> signalCallback, Action statusCallback) - { - subscribeAction = null; - presenceAction = null; - statusAction = statusCallback; - signalAction = signalCallback; - objectEventAction = null; - fileAction = null; - } - - public SubscribeCallbackExt(Action objectEventCallback, Action statusCallback) - { - subscribeAction = null; - presenceAction = null; - signalAction = null; - statusAction = statusCallback; - objectEventAction = objectEventCallback; - fileAction = null; - } - - public SubscribeCallbackExt(Action messageActionCallback, Action statusCallback) - { - subscribeAction = null; - presenceAction = null; - signalAction = null; - statusAction = statusCallback; - objectEventAction = null; - messageAction = messageActionCallback; - fileAction = null; - } - - public SubscribeCallbackExt(Action fileCallback, Action statusCallback) - { - subscribeAction = null; - presenceAction = null; - statusAction = statusCallback; - signalAction = null; - objectEventAction = null; - fileAction = fileCallback; - } - - public SubscribeCallbackExt(Action> messageCallback, - Action presenceCallback, - Action> signalCallback, - Action statusCallback) - { - subscribeAction = messageCallback; - presenceAction = presenceCallback; - statusAction = statusCallback; - signalAction = signalCallback; - objectEventAction = null; - } - - public SubscribeCallbackExt(Action> messageCallback, - Action presenceCallback, - Action> signalCallback, - Action objectEventCallback, - Action statusCallback) - { - subscribeAction = messageCallback; - presenceAction = presenceCallback; - statusAction = statusCallback; - signalAction = signalCallback; - objectEventAction = objectEventCallback; - } - - public SubscribeCallbackExt(Action> messageCallback, - Action presenceCallback, - Action> signalCallback, - Action objectEventCallback, - Action messageActionCallback, - Action statusCallback) - { - subscribeAction = messageCallback; - presenceAction = presenceCallback; - statusAction = statusCallback; - signalAction = signalCallback; - objectEventAction = objectEventCallback; - messageAction = messageActionCallback; - } - - public SubscribeCallbackExt(Action> messageCallback, - Action presenceCallback, - Action> signalCallback, - Action objectEventCallback, - Action messageActionCallback, - Action fileCallback, - Action statusCallback) - { - subscribeAction = messageCallback; - presenceAction = presenceCallback; - statusAction = statusCallback; - signalAction = signalCallback; - objectEventAction = objectEventCallback; - messageAction = messageActionCallback; - fileAction = fileCallback; - } - - public override void Message(Pubnub pubnub, PNMessageResult message) - { - PNMessageResult message1 = new PNMessageResult(); - message1.Channel = message.Channel; - message1.Message = (T)(object)message.Message; - message1.Subscription = message.Subscription; - message1.Timetoken = message.Timetoken; - message1.UserMetadata = message.UserMetadata; - message1.Publisher = message.Publisher; - - subscribeAction?.Invoke(pubnub, message1); - } - - public override void Presence(Pubnub pubnub, PNPresenceEventResult presence) - { - presenceAction?.Invoke(pubnub, presence); - } - - public override void Status(Pubnub pubnub, PNStatus status) - { - statusAction?.Invoke(pubnub, status); - } - - public override void Signal(Pubnub pubnub, PNSignalResult signalMessage) - { - PNSignalResult message1 = new PNSignalResult(); - message1.Channel = signalMessage.Channel; - message1.Message = (T)(object)signalMessage.Message; - message1.Subscription = signalMessage.Subscription; - message1.Timetoken = signalMessage.Timetoken; - message1.UserMetadata = signalMessage.UserMetadata; - message1.Publisher = signalMessage.Publisher; - - signalAction?.Invoke(pubnub, message1); - } - - public override void ObjectEvent(Pubnub pubnub, PNObjectEventResult objectEvent) - { - objectEventAction?.Invoke(pubnub, objectEvent); - } - - public override void MessageAction(Pubnub pubnub, PNMessageActionEventResult messageActionEvent) - { - messageAction?.Invoke(pubnub, messageActionEvent); - } - - public override void File(Pubnub pubnub, PNFileEventResult fileEvent) - { - PNFileEventResult message1 = new PNFileEventResult(); - message1.Channel = fileEvent.Channel; - message1.Message = fileEvent.Message; - message1.Subscription = fileEvent.Subscription; - message1.Timetoken = fileEvent.Timetoken; - message1.Publisher = fileEvent.Publisher; - message1.File = fileEvent.File; - - fileAction?.Invoke(pubnub, message1); - } - } + public class SubscribeCallbackExt : SubscribeCallback + { + public Action> subscribeAction; + public Action presenceAction; + public Action> signalAction; + public Action statusAction; + public Action objectEventAction; + public Action messageAction; + public Action fileAction; + + public SubscribeCallbackExt() + { + subscribeAction = null; + presenceAction = null; + statusAction = null; + signalAction = null; + objectEventAction = null; + fileAction = null; + } + public SubscribeCallbackExt(Action statusCallback) + { + subscribeAction = null; + presenceAction = null; + statusAction = statusCallback; + signalAction = null; + objectEventAction = null; + fileAction = null; + } + public SubscribeCallbackExt(Action> messageCallback, Action presenceCallback, Action statusCallback) + { + subscribeAction = messageCallback; + presenceAction = presenceCallback; + statusAction = statusCallback; + signalAction = null; + objectEventAction = null; + fileAction = null; + } + + public SubscribeCallbackExt(Action> messageCallback) + { + subscribeAction = messageCallback; + presenceAction = null; + statusAction = null; + signalAction = null; + objectEventAction = null; + fileAction = null; + } + + public SubscribeCallbackExt(Action presenceCallback) + { + subscribeAction = null; + presenceAction = presenceCallback; + statusAction = null; + signalAction = null; + objectEventAction = null; + fileAction = null; + } + + public SubscribeCallbackExt(Action> messageCallback, Action presenceCallback) + { + subscribeAction = messageCallback; + presenceAction = presenceCallback; + statusAction = null; + signalAction = null; + objectEventAction = null; + fileAction = null; + } + + public SubscribeCallbackExt(Action> signalCallback, Action statusCallback) + { + subscribeAction = null; + presenceAction = null; + statusAction = statusCallback; + signalAction = signalCallback; + objectEventAction = null; + fileAction = null; + } + + public SubscribeCallbackExt(Action objectEventCallback, Action statusCallback) + { + subscribeAction = null; + presenceAction = null; + signalAction = null; + statusAction = statusCallback; + objectEventAction = objectEventCallback; + fileAction = null; + } + + public SubscribeCallbackExt(Action messageActionCallback, Action statusCallback) + { + subscribeAction = null; + presenceAction = null; + signalAction = null; + statusAction = statusCallback; + objectEventAction = null; + messageAction = messageActionCallback; + fileAction = null; + } + + public SubscribeCallbackExt(Action fileCallback, Action statusCallback) + { + subscribeAction = null; + presenceAction = null; + statusAction = statusCallback; + signalAction = null; + objectEventAction = null; + fileAction = fileCallback; + } + + public SubscribeCallbackExt(Action> messageCallback, + Action presenceCallback, + Action> signalCallback, + Action statusCallback) + { + subscribeAction = messageCallback; + presenceAction = presenceCallback; + statusAction = statusCallback; + signalAction = signalCallback; + objectEventAction = null; + } + + public SubscribeCallbackExt(Action> messageCallback, + Action presenceCallback, + Action> signalCallback, + Action objectEventCallback, + Action statusCallback) + { + subscribeAction = messageCallback; + presenceAction = presenceCallback; + statusAction = statusCallback; + signalAction = signalCallback; + objectEventAction = objectEventCallback; + } + + public SubscribeCallbackExt(Action> messageCallback, + Action presenceCallback, + Action> signalCallback, + Action objectEventCallback, + Action messageActionCallback, + Action fileCallback + ) + { + subscribeAction = messageCallback; + presenceAction = presenceCallback; + statusAction = null; + signalAction = signalCallback; + messageAction = messageActionCallback; + objectEventAction = objectEventCallback; + fileAction = fileCallback; + } + + public SubscribeCallbackExt(Action> messageCallback, + Action presenceCallback, + Action> signalCallback, + Action objectEventCallback, + Action messageActionCallback, + Action statusCallback) + { + subscribeAction = messageCallback; + presenceAction = presenceCallback; + statusAction = statusCallback; + signalAction = signalCallback; + objectEventAction = objectEventCallback; + messageAction = messageActionCallback; + } + + public SubscribeCallbackExt(Action> messageCallback, + Action presenceCallback, + Action> signalCallback, + Action objectEventCallback, + Action messageActionCallback, + Action fileCallback, + Action statusCallback) + { + subscribeAction = messageCallback; + presenceAction = presenceCallback; + statusAction = statusCallback; + signalAction = signalCallback; + objectEventAction = objectEventCallback; + messageAction = messageActionCallback; + fileAction = fileCallback; + } + + public override void Message(Pubnub pubnub, PNMessageResult message) + { + PNMessageResult message1 = new PNMessageResult(); + message1.Channel = message.Channel; + message1.Message = (T)(object)message.Message; + message1.Subscription = message.Subscription; + message1.Timetoken = message.Timetoken; + message1.UserMetadata = message.UserMetadata; + message1.Publisher = message.Publisher; + + subscribeAction?.Invoke(pubnub, message1); + } + + public override void Presence(Pubnub pubnub, PNPresenceEventResult presence) + { + presenceAction?.Invoke(pubnub, presence); + } + + public override void Status(Pubnub pubnub, PNStatus status) + { + statusAction?.Invoke(pubnub, status); + } + + public override void Signal(Pubnub pubnub, PNSignalResult signalMessage) + { + PNSignalResult message1 = new PNSignalResult(); + message1.Channel = signalMessage.Channel; + message1.Message = (T)(object)signalMessage.Message; + message1.Subscription = signalMessage.Subscription; + message1.Timetoken = signalMessage.Timetoken; + message1.UserMetadata = signalMessage.UserMetadata; + message1.Publisher = signalMessage.Publisher; + + signalAction?.Invoke(pubnub, message1); + } + + public override void ObjectEvent(Pubnub pubnub, PNObjectEventResult objectEvent) + { + objectEventAction?.Invoke(pubnub, objectEvent); + } + + public override void MessageAction(Pubnub pubnub, PNMessageActionEventResult messageActionEvent) + { + messageAction?.Invoke(pubnub, messageActionEvent); + } + + public override void File(Pubnub pubnub, PNFileEventResult fileEvent) + { + PNFileEventResult message1 = new PNFileEventResult(); + message1.Channel = fileEvent.Channel; + message1.Message = fileEvent.Message; + message1.Subscription = fileEvent.Subscription; + message1.Timetoken = fileEvent.Timetoken; + message1.Publisher = fileEvent.Publisher; + message1.File = fileEvent.File; + + fileAction?.Invoke(pubnub, message1); + } + } } diff --git a/src/Api/PubnubApi/Model/RequestState.cs b/src/Api/PubnubApi/Model/RequestState.cs index cfb8d3014..0659068e5 100644 --- a/src/Api/PubnubApi/Model/RequestState.cs +++ b/src/Api/PubnubApi/Model/RequestState.cs @@ -1,13 +1,14 @@ using System; using System.Net; +using System.Threading; namespace PubnubApi { public sealed class RequestState { public DateTime? TimeQueued { get; internal set; } - public HttpWebRequest Request { get; internal set; } - public HttpWebResponse Response { get; internal set; } + public CancellationTokenSource RequestCancellationTokenSource { get; internal set; } + public TransportResponse Response { get; internal set; } public bool GotJsonResponse { get; internal set; } public PNOperationType ResponseType { get; internal set; } public string[] Channels { get; internal set; } @@ -24,7 +25,7 @@ public sealed class RequestState public RequestState() { PubnubCallback = null; - Request = null; + RequestCancellationTokenSource = null; Response = null; Channels = null; ChannelGroups = null; diff --git a/src/Api/PubnubApi/PNConfiguration.cs b/src/Api/PubnubApi/PNConfiguration.cs index 462f4a4aa..233ca800c 100644 --- a/src/Api/PubnubApi/PNConfiguration.cs +++ b/src/Api/PubnubApi/PNConfiguration.cs @@ -152,7 +152,7 @@ public PNReconnectionPolicy ReconnectionPolicy { public bool MaintainPresenceState { get; set; } = true; - public bool EnableEventEngine { get; set; } + public bool EnableEventEngine { get; set; } = true; public int FileMessagePublishRetryLimit { get; set; } diff --git a/src/Api/PubnubApi/Pubnub.cs b/src/Api/PubnubApi/Pubnub.cs index 23061138f..ee90eed04 100644 --- a/src/Api/PubnubApi/Pubnub.cs +++ b/src/Api/PubnubApi/Pubnub.cs @@ -8,12 +8,10 @@ using PubnubApi.EventEngine.Subscribe.Common; using PubnubApi.Interface; using PubnubApi.EventEngine.Presence; - -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif using PubnubApi.Security.Crypto; using PubnubApi.Security.Crypto.Cryptors; +using PubnubApi.EventEngine.Common; +using System.Collections.Concurrent; namespace PubnubApi { @@ -23,12 +21,12 @@ public class Pubnub private IPubnubUnitTest pubnubUnitTest; private IPubnubLog pubnubLog; private EndPoint.ListenerManager listenerManager; - private readonly EndPoint.TelemetryManager telemetryManager; private readonly EndPoint.TokenManager tokenManager; private object savedSubscribeOperation; private readonly string savedSdkVerion; private SubscribeEventEngineFactory subscribeEventEngineFactory; private PresenceEventEngineFactory presenceEventengineFactory; + private EventEmitter eventEmitter; private List subscribeCallbackListenerList { get; @@ -69,16 +67,17 @@ public ISubscribeOperation Subscribe() if (pubnubConfig[InstanceId].EnableEventEngine) { if (pubnubConfig[InstanceId].PresenceInterval > 0) { - presenceOperation = new PresenceOperation(this, InstanceId, pubnubLog, pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null ,telemetryManager, tokenManager, pubnubUnitTest ,presenceEventengineFactory); + presenceOperation = new PresenceOperation(this, InstanceId, pubnubLog, pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null , tokenManager, pubnubUnitTest ,presenceEventengineFactory); } - EndPoint.SubscribeEndpoint subscribeOperation = new EndPoint.SubscribeEndpoint(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, null, tokenManager, this.subscribeEventEngineFactory, presenceOperation, InstanceId ,this); + EndPoint.SubscribeEndpoint subscribeOperation = new EndPoint.SubscribeEndpoint(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this.subscribeEventEngineFactory, presenceOperation, InstanceId ,this); + subscribeOperation.EventEmitter = this.eventEmitter; subscribeOperation.SubscribeListenerList = subscribeCallbackListenerList; savedSubscribeOperation = subscribeOperation; return subscribeOperation; } else { - EndPoint.SubscribeOperation subscribeOperation = new EndPoint.SubscribeOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, null, tokenManager, this); + EndPoint.SubscribeOperation subscribeOperation = new EndPoint.SubscribeOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); savedSubscribeOperation = subscribeOperation; return subscribeOperation; } @@ -88,12 +87,12 @@ public IUnsubscribeOperation Unsubscribe() { if (pubnubConfig[InstanceId].EnableEventEngine) { - EndPoint.UnsubscribeEndpoint unsubscribeOperation = new EndPoint.UnsubscribeEndpoint(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, subscribeEventEngineFactory, presenceEventengineFactory, this); + EndPoint.UnsubscribeEndpoint unsubscribeOperation = new EndPoint.UnsubscribeEndpoint(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, subscribeEventEngineFactory, presenceEventengineFactory, this); return unsubscribeOperation; } else { - EndPoint.UnsubscribeOperation unsubscribeOperation = new EndPoint.UnsubscribeOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.UnsubscribeOperation unsubscribeOperation = new EndPoint.UnsubscribeOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); unsubscribeOperation.CurrentPubnubInstance(this); return unsubscribeOperation; } @@ -103,256 +102,256 @@ public EndPoint.UnsubscribeAllOperation UnsubscribeAll() { if (pubnubConfig[InstanceId].EnableEventEngine) { - EndPoint.UnsubscribeAllEndpoint unsubscribeAllEndpoint = new EndPoint.UnsubscribeAllEndpoint(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, subscribeEventEngineFactory, presenceEventengineFactory, this); + EndPoint.UnsubscribeAllEndpoint unsubscribeAllEndpoint = new EndPoint.UnsubscribeAllEndpoint(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, subscribeEventEngineFactory, presenceEventengineFactory, this); return unsubscribeAllEndpoint; } else { - EndPoint.UnsubscribeAllOperation unSubscribeAllOperation = new EndPoint.UnsubscribeAllOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.UnsubscribeAllOperation unSubscribeAllOperation = new EndPoint.UnsubscribeAllOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return unSubscribeAllOperation; } } public EndPoint.PublishOperation Publish() { - EndPoint.PublishOperation publishOperation = new EndPoint.PublishOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.PublishOperation publishOperation = new EndPoint.PublishOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); publishOperation.CurrentPubnubInstance(this); return publishOperation; } public EndPoint.FireOperation Fire() { - EndPoint.FireOperation fireOperation = new EndPoint.FireOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.FireOperation fireOperation = new EndPoint.FireOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); fireOperation.CurrentPubnubInstance(this); return fireOperation; } public EndPoint.SignalOperation Signal() { - EndPoint.SignalOperation signalOperation = new EndPoint.SignalOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.SignalOperation signalOperation = new EndPoint.SignalOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return signalOperation; } public EndPoint.HistoryOperation History() { - EndPoint.HistoryOperation historyOperaton = new EndPoint.HistoryOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.HistoryOperation historyOperaton = new EndPoint.HistoryOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return historyOperaton; } public EndPoint.FetchHistoryOperation FetchHistory() { - EndPoint.FetchHistoryOperation historyOperaton = new EndPoint.FetchHistoryOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.FetchHistoryOperation historyOperaton = new EndPoint.FetchHistoryOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return historyOperaton; } public EndPoint.DeleteMessageOperation DeleteMessages() { - EndPoint.DeleteMessageOperation deleteMessageOperaton = new EndPoint.DeleteMessageOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.DeleteMessageOperation deleteMessageOperaton = new EndPoint.DeleteMessageOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return deleteMessageOperaton; } public EndPoint.MessageCountsOperation MessageCounts() { - EndPoint.MessageCountsOperation messageCount = new EndPoint.MessageCountsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.MessageCountsOperation messageCount = new EndPoint.MessageCountsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); messageCount.CurrentPubnubInstance(this); return messageCount; } public EndPoint.HereNowOperation HereNow() { - EndPoint.HereNowOperation hereNowOperation = new EndPoint.HereNowOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.HereNowOperation hereNowOperation = new EndPoint.HereNowOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); hereNowOperation.CurrentPubnubInstance(this); return hereNowOperation; } public EndPoint.WhereNowOperation WhereNow() { - EndPoint.WhereNowOperation whereNowOperation = new EndPoint.WhereNowOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.WhereNowOperation whereNowOperation = new EndPoint.WhereNowOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); whereNowOperation.CurrentPubnubInstance(this); return whereNowOperation; } public EndPoint.TimeOperation Time() { - EndPoint.TimeOperation timeOperation = new EndPoint.TimeOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, this); + EndPoint.TimeOperation timeOperation = new EndPoint.TimeOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, this); timeOperation.CurrentPubnubInstance(this); return timeOperation; } public EndPoint.AuditOperation Audit() { - EndPoint.AuditOperation auditOperation = new EndPoint.AuditOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, this); + EndPoint.AuditOperation auditOperation = new EndPoint.AuditOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, this); auditOperation.CurrentPubnubInstance(this); return auditOperation; } public EndPoint.GrantTokenOperation GrantToken() { - EndPoint.GrantTokenOperation grantOperation = new EndPoint.GrantTokenOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GrantTokenOperation grantOperation = new EndPoint.GrantTokenOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return grantOperation; } public EndPoint.RevokeTokenOperation RevokeToken() { - EndPoint.RevokeTokenOperation revokeTokenOperation = new EndPoint.RevokeTokenOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.RevokeTokenOperation revokeTokenOperation = new EndPoint.RevokeTokenOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return revokeTokenOperation; } public EndPoint.GrantOperation Grant() { - EndPoint.GrantOperation grantOperation = new EndPoint.GrantOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, this); + EndPoint.GrantOperation grantOperation = new EndPoint.GrantOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, this); grantOperation.CurrentPubnubInstance(this); return grantOperation; } public EndPoint.SetStateOperation SetPresenceState() { - EndPoint.SetStateOperation setStateOperation = new EndPoint.SetStateOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.SetStateOperation setStateOperation = new EndPoint.SetStateOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return setStateOperation; } public EndPoint.GetStateOperation GetPresenceState() { - EndPoint.GetStateOperation getStateOperation = new EndPoint.GetStateOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GetStateOperation getStateOperation = new EndPoint.GetStateOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); getStateOperation.CurrentPubnubInstance(this); return getStateOperation; } public EndPoint.AddPushChannelOperation AddPushNotificationsOnChannels() { - EndPoint.AddPushChannelOperation addPushChannelOperation = new EndPoint.AddPushChannelOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.AddPushChannelOperation addPushChannelOperation = new EndPoint.AddPushChannelOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return addPushChannelOperation; } public EndPoint.RemovePushChannelOperation RemovePushNotificationsFromChannels() { - EndPoint.RemovePushChannelOperation removePushChannelOperation = new EndPoint.RemovePushChannelOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.RemovePushChannelOperation removePushChannelOperation = new EndPoint.RemovePushChannelOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return removePushChannelOperation; } public EndPoint.RemoveAllPushChannelsOperation RemoveAllPushNotificationsFromDeviceWithPushToken() { - EndPoint.RemoveAllPushChannelsOperation removeAllPushChannelsOperation = new EndPoint.RemoveAllPushChannelsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.RemoveAllPushChannelsOperation removeAllPushChannelsOperation = new EndPoint.RemoveAllPushChannelsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); removeAllPushChannelsOperation.CurrentPubnubInstance(this); return removeAllPushChannelsOperation; } public EndPoint.AuditPushChannelOperation AuditPushChannelProvisions() { - EndPoint.AuditPushChannelOperation auditPushChannelOperation = new EndPoint.AuditPushChannelOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.AuditPushChannelOperation auditPushChannelOperation = new EndPoint.AuditPushChannelOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); auditPushChannelOperation.CurrentPubnubInstance(this); return auditPushChannelOperation; } public EndPoint.SetUuidMetadataOperation SetUuidMetadata() { - EndPoint.SetUuidMetadataOperation setUuidMetadataOperation = new EndPoint.SetUuidMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.SetUuidMetadataOperation setUuidMetadataOperation = new EndPoint.SetUuidMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return setUuidMetadataOperation; } public EndPoint.RemoveUuidMetadataOperation RemoveUuidMetadata() { - EndPoint.RemoveUuidMetadataOperation removeUuidMetadataOperation = new EndPoint.RemoveUuidMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.RemoveUuidMetadataOperation removeUuidMetadataOperation = new EndPoint.RemoveUuidMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return removeUuidMetadataOperation; } public EndPoint.GetAllUuidMetadataOperation GetAllUuidMetadata() { - EndPoint.GetAllUuidMetadataOperation getAllUuidMetadataOperation = new EndPoint.GetAllUuidMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GetAllUuidMetadataOperation getAllUuidMetadataOperation = new EndPoint.GetAllUuidMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return getAllUuidMetadataOperation; } public EndPoint.GetUuidMetadataOperation GetUuidMetadata() { - EndPoint.GetUuidMetadataOperation getUuidMetadataOperation = new EndPoint.GetUuidMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GetUuidMetadataOperation getUuidMetadataOperation = new EndPoint.GetUuidMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return getUuidMetadataOperation; } public EndPoint.SetChannelMetadataOperation SetChannelMetadata() { - EndPoint.SetChannelMetadataOperation setChannelMetadataOperation = new EndPoint.SetChannelMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.SetChannelMetadataOperation setChannelMetadataOperation = new EndPoint.SetChannelMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return setChannelMetadataOperation; } public EndPoint.RemoveChannelMetadataOperation RemoveChannelMetadata() { - EndPoint.RemoveChannelMetadataOperation removeChannelMetadataOperation = new EndPoint.RemoveChannelMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.RemoveChannelMetadataOperation removeChannelMetadataOperation = new EndPoint.RemoveChannelMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return removeChannelMetadataOperation; } public EndPoint.GetAllChannelMetadataOperation GetAllChannelMetadata() { - EndPoint.GetAllChannelMetadataOperation getAllChannelMetadataOperation = new EndPoint.GetAllChannelMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GetAllChannelMetadataOperation getAllChannelMetadataOperation = new EndPoint.GetAllChannelMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return getAllChannelMetadataOperation; } public EndPoint.GetChannelMetadataOperation GetChannelMetadata() { - EndPoint.GetChannelMetadataOperation getSingleSpaceOperation = new EndPoint.GetChannelMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GetChannelMetadataOperation getSingleSpaceOperation = new EndPoint.GetChannelMetadataOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return getSingleSpaceOperation; } public EndPoint.GetMembershipsOperation GetMemberships() { - EndPoint.GetMembershipsOperation getMembershipOperation = new EndPoint.GetMembershipsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GetMembershipsOperation getMembershipOperation = new EndPoint.GetMembershipsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return getMembershipOperation; } public EndPoint.SetMembershipsOperation SetMemberships() { - EndPoint.SetMembershipsOperation setMembershipsOperation = new EndPoint.SetMembershipsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.SetMembershipsOperation setMembershipsOperation = new EndPoint.SetMembershipsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return setMembershipsOperation; } public EndPoint.RemoveMembershipsOperation RemoveMemberships() { - EndPoint.RemoveMembershipsOperation removeMembershipsOperation = new EndPoint.RemoveMembershipsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.RemoveMembershipsOperation removeMembershipsOperation = new EndPoint.RemoveMembershipsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return removeMembershipsOperation; } public EndPoint.ManageMembershipsOperation ManageMemberships() { - EndPoint.ManageMembershipsOperation manageMembershipsOperation = new EndPoint.ManageMembershipsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.ManageMembershipsOperation manageMembershipsOperation = new EndPoint.ManageMembershipsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return manageMembershipsOperation; } public EndPoint.GetChannelMembersOperation GetChannelMembers() { - EndPoint.GetChannelMembersOperation getChannelMembersOperation = new EndPoint.GetChannelMembersOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GetChannelMembersOperation getChannelMembersOperation = new EndPoint.GetChannelMembersOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return getChannelMembersOperation; } public EndPoint.SetChannelMembersOperation SetChannelMembers() { - EndPoint.SetChannelMembersOperation setChannelMembersOperation = new EndPoint.SetChannelMembersOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.SetChannelMembersOperation setChannelMembersOperation = new EndPoint.SetChannelMembersOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return setChannelMembersOperation; } public EndPoint.RemoveChannelMembersOperation RemoveChannelMembers() { - EndPoint.RemoveChannelMembersOperation removeChannelMembersOperation = new EndPoint.RemoveChannelMembersOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.RemoveChannelMembersOperation removeChannelMembersOperation = new EndPoint.RemoveChannelMembersOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return removeChannelMembersOperation; } public EndPoint.ManageChannelMembersOperation ManageChannelMembers() { - EndPoint.ManageChannelMembersOperation channelMembersOperation = new EndPoint.ManageChannelMembersOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.ManageChannelMembersOperation channelMembersOperation = new EndPoint.ManageChannelMembersOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return channelMembersOperation; } public EndPoint.AddMessageActionOperation AddMessageAction() { - EndPoint.AddMessageActionOperation addMessageActionOperation = new EndPoint.AddMessageActionOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.AddMessageActionOperation addMessageActionOperation = new EndPoint.AddMessageActionOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return addMessageActionOperation; } public EndPoint.RemoveMessageActionOperation RemoveMessageAction() { - EndPoint.RemoveMessageActionOperation removeMessageActionOperation = new EndPoint.RemoveMessageActionOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.RemoveMessageActionOperation removeMessageActionOperation = new EndPoint.RemoveMessageActionOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return removeMessageActionOperation; } public EndPoint.GetMessageActionsOperation GetMessageActions() { - EndPoint.GetMessageActionsOperation getMessageActionsOperation = new EndPoint.GetMessageActionsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GetMessageActionsOperation getMessageActionsOperation = new EndPoint.GetMessageActionsOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return getMessageActionsOperation; } @@ -362,35 +361,35 @@ public EndPoint.GetMessageActionsOperation GetMessageActions() public EndPoint.AddChannelsToChannelGroupOperation AddChannelsToChannelGroup() { - EndPoint.AddChannelsToChannelGroupOperation addChannelToChannelGroupOperation = new EndPoint.AddChannelsToChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.AddChannelsToChannelGroupOperation addChannelToChannelGroupOperation = new EndPoint.AddChannelsToChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); addChannelToChannelGroupOperation.CurrentPubnubInstance(this); return addChannelToChannelGroupOperation; } public EndPoint.RemoveChannelsFromChannelGroupOperation RemoveChannelsFromChannelGroup() { - EndPoint.RemoveChannelsFromChannelGroupOperation removeChannelsFromChannelGroupOperation = new EndPoint.RemoveChannelsFromChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.RemoveChannelsFromChannelGroupOperation removeChannelsFromChannelGroupOperation = new EndPoint.RemoveChannelsFromChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); removeChannelsFromChannelGroupOperation.CurrentPubnubInstance(this); return removeChannelsFromChannelGroupOperation; } public EndPoint.DeleteChannelGroupOperation DeleteChannelGroup() { - EndPoint.DeleteChannelGroupOperation deleteChannelGroupOperation = new EndPoint.DeleteChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.DeleteChannelGroupOperation deleteChannelGroupOperation = new EndPoint.DeleteChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); deleteChannelGroupOperation.CurrentPubnubInstance(this); return deleteChannelGroupOperation; } public EndPoint.ListChannelsForChannelGroupOperation ListChannelsForChannelGroup() { - EndPoint.ListChannelsForChannelGroupOperation listChannelsForChannelGroupOperation = new EndPoint.ListChannelsForChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, null, tokenManager, this); + EndPoint.ListChannelsForChannelGroupOperation listChannelsForChannelGroupOperation = new EndPoint.ListChannelsForChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); listChannelsForChannelGroupOperation.CurrentPubnubInstance(this); return listChannelsForChannelGroupOperation; } public EndPoint.ListAllChannelGroupOperation ListChannelGroups() { - EndPoint.ListAllChannelGroupOperation listAllChannelGroupOperation = new EndPoint.ListAllChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, null, tokenManager, this); + EndPoint.ListAllChannelGroupOperation listAllChannelGroupOperation = new EndPoint.ListAllChannelGroupOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); listAllChannelGroupOperation.CurrentPubnubInstance(this); return listAllChannelGroupOperation; } @@ -406,7 +405,7 @@ public bool AddListener(SubscribeCallback listener) { if (listenerManager == null) { - listenerManager = new EndPoint.ListenerManager(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, null, tokenManager, this); + listenerManager = new EndPoint.ListenerManager(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); } return listenerManager.AddListener(listener); } @@ -425,44 +424,44 @@ public bool RemoveListener(SubscribeCallback listener) public EndPoint.SendFileOperation SendFile() { - EndPoint.SendFileOperation uploadFileOperation = new EndPoint.SendFileOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.SendFileOperation uploadFileOperation = new EndPoint.SendFileOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return uploadFileOperation; } public EndPoint.GetFileUrlOperation GetFileUrl() { - EndPoint.GetFileUrlOperation getFileUrlOperation = new EndPoint.GetFileUrlOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.GetFileUrlOperation getFileUrlOperation = new EndPoint.GetFileUrlOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return getFileUrlOperation; } public EndPoint.DownloadFileOperation DownloadFile() { - EndPoint.DownloadFileOperation downloadFileOperation = new EndPoint.DownloadFileOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.DownloadFileOperation downloadFileOperation = new EndPoint.DownloadFileOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return downloadFileOperation; } public EndPoint.ListFilesOperation ListFiles() { - EndPoint.ListFilesOperation listFilesOperation = new EndPoint.ListFilesOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.ListFilesOperation listFilesOperation = new EndPoint.ListFilesOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return listFilesOperation; } public EndPoint.DeleteFileOperation DeleteFile() { - EndPoint.DeleteFileOperation deleteFileOperation = new EndPoint.DeleteFileOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.DeleteFileOperation deleteFileOperation = new EndPoint.DeleteFileOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return deleteFileOperation; } public EndPoint.PublishFileMessageOperation PublishFileMessage() { - EndPoint.PublishFileMessageOperation publshFileMessageOperation = new EndPoint.PublishFileMessageOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.PublishFileMessageOperation publshFileMessageOperation = new EndPoint.PublishFileMessageOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); return publshFileMessageOperation; } #region "PubNub API Other Methods" public void TerminateCurrentSubscriberRequest() { - EndPoint.OtherOperation endpoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, null, tokenManager, this); + EndPoint.OtherOperation endpoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); endpoint.CurrentPubnubInstance(this); endpoint.TerminateCurrentSubscriberRequest(); } @@ -498,7 +497,7 @@ public void ChangeUserId(UserId newUserId) } throw new MissingMemberException("UserId cannot be null/empty"); } - EndPoint.OtherOperation endPoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.OtherOperation endPoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); endPoint.CurrentPubnubInstance(this); endPoint.ChangeUserId(newUserId); } @@ -520,21 +519,21 @@ public static DateTime TranslatePubnubUnixNanoSecondsToDateTime(string unixNanoS public UserId GetCurrentUserId() { - EndPoint.OtherOperation endPoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, telemetryManager, tokenManager, this); + EndPoint.OtherOperation endPoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); endPoint.CurrentPubnubInstance(this); return endPoint.GetCurrentUserId(); } public List GetSubscribedChannels() { - EndPoint.OtherOperation endpoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, null, tokenManager, this); + EndPoint.OtherOperation endpoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); endpoint.CurrentPubnubInstance(this); return endpoint.GetSubscribedChannels(); } public List GetSubscribedChannelGroups() { - EndPoint.OtherOperation endpoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, null, tokenManager, this); + EndPoint.OtherOperation endpoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); endpoint.CurrentPubnubInstance(this); return endpoint.GetSubscribedChannelGroups(); } @@ -542,7 +541,7 @@ public List GetSubscribedChannelGroups() public void Destroy() { savedSubscribeOperation = null; - EndPoint.OtherOperation endpoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, null, tokenManager, this); + EndPoint.OtherOperation endpoint = new EndPoint.OtherOperation(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, JsonPluggableLibrary, pubnubUnitTest, pubnubLog, tokenManager, this); endpoint.CurrentPubnubInstance(this); endpoint.EndPendingRequests(); } @@ -964,10 +963,18 @@ public void SetJsonPluggableLibrary(IJsonPluggableLibrary customJson) public static string Version { get; private set; } - + internal IHttpClientService httpClientService; + internal Middleware transportMiddleware; public string InstanceId { get; private set; } + public Channel Channel(string name) => new Channel(name, this, eventEmitter); + public ChannelGroup ChannelGroup(string name) => new ChannelGroup(name, this, eventEmitter); + public ChannelMetadata ChannelMetadata(string id) => new ChannelMetadata(id, this, eventEmitter); + public UserMetadata UserMetadata(string id) => new UserMetadata(id, this, eventEmitter); + + public SubscriptionSet SubscriptionSet(string[] channels, string[] channelGroups = null, SubscriptionOptions? options = null) => new SubscriptionSet(channels, channelGroups?? new string[] {}, options, this, eventEmitter); + #endregion #region "Constructors" @@ -992,16 +999,12 @@ public Pubnub(PNConfiguration config) PNPlatform.Print(config, pubnubLog); } - if (config.EnableTelemetry) - { - telemetryManager = new EndPoint.TelemetryManager(pubnubConfig[InstanceId], pubnubLog); - } CheckAndInitializeEmptyStringValues(config); tokenManager = new EndPoint.TokenManager(pubnubConfig[InstanceId], JsonPluggableLibrary, pubnubLog, this.InstanceId); - + //Initialize JsonPluggableLibrary JsonPluggableLibrary = new NewtonsoftJsonDotNet(config, pubnubLog); - + //Check PresenceTimeout if (config.PresenceTimeout < 20) { @@ -1014,10 +1017,11 @@ public Pubnub(PNConfiguration config) //Check required UserId CheckRequiredUserId(config); - + eventEmitter = new EventEmitter(pubnubConfig.ContainsKey(InstanceId) ? pubnubConfig[InstanceId] : null, subscribeCallbackListenerList, JsonPluggableLibrary, tokenManager, pubnubLog, this); //Check CryptoModule usage CheckCryptoModuleUsageForLogging(config); - + httpClientService = new HttpClientService(); + transportMiddleware = new Middleware(httpClientService,config, this, tokenManager); } #if UNITY diff --git a/src/Api/PubnubApi/PubnubApi.csproj b/src/Api/PubnubApi/PubnubApi.csproj index 737369102..2703e9eee 100644 --- a/src/Api/PubnubApi/PubnubApi.csproj +++ b/src/Api/PubnubApi/PubnubApi.csproj @@ -1,6 +1,7 @@  + net60 latest True pubnub.snk @@ -9,7 +10,6 @@ PubNub C# .NET - Web Data Push API Pubnub true - net48 @@ -59,6 +59,10 @@ 0436; + + + + @@ -134,4 +138,8 @@ + + + + diff --git a/src/Api/PubnubApi/PubnubCoreBase.cs b/src/Api/PubnubApi/PubnubCoreBase.cs index 5f14faa7e..c223a4463 100644 --- a/src/Api/PubnubApi/PubnubCoreBase.cs +++ b/src/Api/PubnubApi/PubnubCoreBase.cs @@ -14,15 +14,13 @@ using System.Globalization; using System.Linq; using System.Threading.Tasks; -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 -using System.Net.Http; -using System.Net.Http.Headers; -#endif -#if !NET35 && !NET40 -using System.Collections.Concurrent; -#endif +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +//using System.Net.Http; +//using System.Net.Http.Headers; +//#endif using PubnubApi.Security.Crypto; using PubnubApi.Security.Crypto.Cryptors; +using System.Collections.Concurrent; #endregion namespace PubnubApi @@ -47,15 +45,8 @@ public abstract class PubnubCoreBase private static IJsonPluggableLibrary jsonLib; private static IPubnubUnitTest unitTest; private static ConcurrentDictionary pubnubLog { get; } = new ConcurrentDictionary(); - private static EndPoint.TelemetryManager pubnubTelemetryMgr; protected static ConcurrentDictionary PubnubTokenMgrCollection { get; } = new ConcurrentDictionary(); private static EndPoint.DuplicationManager pubnubSubscribeDuplicationManager { get; set; } -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - private static HttpClient httpClientSubscribe { get; set; } - private static HttpClient httpClientNonsubscribe { get; set; } - private static HttpClient httpClientNetworkStatus { get; set; } - private static PubnubHttpClientHandler pubnubHttpClientHandler { get; set; } -#endif private bool clientNetworkStatusInternetStatus = true; protected static ConcurrentDictionary SubscribeDisconnected { get; set; } = new ConcurrentDictionary(); @@ -102,11 +93,11 @@ protected static ConcurrentDictionary>(); - protected static ConcurrentDictionary> ChannelRequest + protected static ConcurrentDictionary> ChannelRequest { get; set; - } = new ConcurrentDictionary>(); + } = new ConcurrentDictionary>(); protected static ConcurrentDictionary> ChannelInternetStatus { @@ -150,7 +141,7 @@ protected static ConcurrentDictionary SubscribeRequestTracker set; } = new ConcurrentDictionary(); - protected PubnubCoreBase(PNConfiguration pubnubConfiguation, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnitTest, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) + protected PubnubCoreBase(PNConfiguration pubnubConfiguation, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnitTest, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) { if (pubnubConfiguation == null) { @@ -159,15 +150,15 @@ protected PubnubCoreBase(PNConfiguration pubnubConfiguation, IJsonPluggableLibra if (jsonPluggableLibrary == null) { - InternalConstructor(pubnubConfiguation, new NewtonsoftJsonDotNet(pubnubConfiguation,log), pubnubUnitTest, log, telemetryManager, tokenManager, instance); + InternalConstructor(pubnubConfiguation, new NewtonsoftJsonDotNet(pubnubConfiguation,log), pubnubUnitTest, log, tokenManager, instance); } else { - InternalConstructor(pubnubConfiguation, jsonPluggableLibrary, pubnubUnitTest, log, telemetryManager, tokenManager, instance); + InternalConstructor(pubnubConfiguation, jsonPluggableLibrary, pubnubUnitTest, log, tokenManager, instance); } } - private void InternalConstructor(PNConfiguration pubnubConfiguation, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnitTest, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, EndPoint.TokenManager tokenManager, Pubnub instance) + private void InternalConstructor(PNConfiguration pubnubConfiguation, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubUnitTest pubnubUnitTest, IPubnubLog log, EndPoint.TokenManager tokenManager, Pubnub instance) { PubnubInstance = instance; pubnubConfig.AddOrUpdate(instance.InstanceId, pubnubConfiguation, (k,o)=> pubnubConfiguation); @@ -175,60 +166,9 @@ private void InternalConstructor(PNConfiguration pubnubConfiguation, IJsonPlugga unitTest = pubnubUnitTest; pubnubLog.AddOrUpdate(instance.InstanceId, log, (k, o) => log); PubnubTokenMgrCollection.AddOrUpdate(instance.InstanceId, tokenManager, (k,o)=> tokenManager); - pubnubTelemetryMgr = telemetryManager; pubnubSubscribeDuplicationManager = new EndPoint.DuplicationManager(pubnubConfiguation, jsonPluggableLibrary, log); CurrentUserId.AddOrUpdate(instance.InstanceId, pubnubConfiguation.UserId, (k,o) => pubnubConfiguation.UserId); - -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - if (httpClientSubscribe == null) - { - if (pubnubConfiguation.Proxy != null) - { - HttpClientHandler httpClientHandler = new HttpClientHandler(); - if (httpClientHandler.SupportsProxy) - { - httpClientHandler.Proxy = pubnubConfiguation.Proxy; - httpClientHandler.UseProxy = true; - } - pubnubHttpClientHandler = new PubnubHttpClientHandler("PubnubHttpClientHandler", httpClientHandler, pubnubConfiguation, jsonLib, unitTest, log); - httpClientSubscribe = new HttpClient(pubnubHttpClientHandler); - } - else - { - httpClientSubscribe = new HttpClient(); - } - httpClientSubscribe.DefaultRequestHeaders.Accept.Clear(); - httpClientSubscribe.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - httpClientSubscribe.Timeout = TimeSpan.FromSeconds(pubnubConfiguation.SubscribeTimeout); - } - if (httpClientNonsubscribe == null) - { - if (pubnubConfiguation.Proxy != null) - { - HttpClientHandler httpClientHandler = new HttpClientHandler(); - if (httpClientHandler.SupportsProxy) - { - httpClientHandler.Proxy = pubnubConfiguation.Proxy; - httpClientHandler.UseProxy = true; - } - pubnubHttpClientHandler = new PubnubHttpClientHandler("PubnubHttpClientHandler", httpClientHandler, pubnubConfiguation, jsonLib, unitTest, log); - httpClientNonsubscribe = new HttpClient(pubnubHttpClientHandler); - } - else - { - httpClientNonsubscribe = new HttpClient(); - } - httpClientNonsubscribe.DefaultRequestHeaders.Accept.Clear(); - httpClientNonsubscribe.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - httpClientNonsubscribe.Timeout = TimeSpan.FromSeconds(pubnubConfiguation.NonSubscribeRequestTimeout); - } - pubnubHttp = new PubnubHttp(pubnubConfiguation, jsonLib, log, pubnubTelemetryMgr, httpClientSubscribe, httpClientNonsubscribe); -#else - pubnubHttp = new PubnubHttp(pubnubConfiguation, jsonLib, log, pubnubTelemetryMgr); -#endif - - UpdatePubnubNetworkTcpCheckIntervalInSeconds(); if (pubnubConfiguation.PresenceInterval > 10) { @@ -303,23 +243,7 @@ protected bool CheckInternetConnectionStatus(bool systemActive, PNOperationTy ClientNetworkStatus.JsonLibrary = jsonLib; ClientNetworkStatus.PubnubUnitTest = unitTest; ClientNetworkStatus.PubnubLog = currentLog; -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - if (httpClientNetworkStatus == null) - { - if (currentConfig.Proxy != null && pubnubHttpClientHandler != null) - { - httpClientNetworkStatus = new HttpClient(pubnubHttpClientHandler); - } - else - { - httpClientNetworkStatus = new HttpClient(); - } - httpClientNetworkStatus.DefaultRequestHeaders.Accept.Clear(); - httpClientNetworkStatus.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - httpClientNetworkStatus.Timeout = TimeSpan.FromSeconds(currentConfig.NonSubscribeRequestTimeout); - } - ClientNetworkStatus.RefHttpClient = httpClientNetworkStatus; -#endif + ClientNetworkStatus.PubnubInstance = PubnubInstance; if (!ClientNetworkStatus.IsInternetCheckRunning()) { clientNetworkStatusInternetStatus = ClientNetworkStatus.CheckInternetStatus(PubnetSystemActive, type, callback, channels, channelGroups); @@ -353,7 +277,7 @@ protected static long GetTimetokenFromMultiplexResult(List result) } else { - var _ = Int64.TryParse(result[1].ToString(), out jsonTimetoken); + var _ = long.TryParse(result[1].ToString(), out jsonTimetoken); } } @@ -837,7 +761,7 @@ private void ResponseToUserCallback(List result, PNOperationType type if (fileObjDic != null && fileObjDic.ContainsKey("id") && fileObjDic.ContainsKey("name")) { fileMessage.File = new PNFile { Id = fileObjDic["id"].ToString(), Name = fileObjDic["name"].ToString() }; - IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(currentConfig, jsonLib, unitTest, currentLog, pubnubTelemetryMgr, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); + IUrlRequestBuilder urlBuilder = new UrlRequestBuilder(currentConfig, jsonLib, unitTest, currentLog, (PubnubInstance != null && !string.IsNullOrEmpty(PubnubInstance.InstanceId) && PubnubTokenMgrCollection.ContainsKey(PubnubInstance.InstanceId)) ? PubnubTokenMgrCollection[PubnubInstance.InstanceId] : null, (PubnubInstance != null) ? PubnubInstance.InstanceId : ""); Uri fileUrlRequest = urlBuilder.BuildGetFileUrlOrDeleteReqest("GET", "", fileMessage.Channel, fileMessage.File.Id, fileMessage.File.Name, null, type); fileMessage.File.Url = fileUrlRequest.ToString(); } @@ -1404,7 +1328,7 @@ internal protected List ProcessJsonResponse(RequestState asyncRequ return result; } - private PNStatus GetStatusIfError(RequestState asyncRequestState, string jsonString) + protected PNStatus GetStatusIfError(RequestState asyncRequestState, string jsonString) { PNStatus status = null; if (string.IsNullOrEmpty(jsonString)) { return status; } @@ -1889,53 +1813,6 @@ protected string BuildJsonUserState(string[] channels, string[] channelGroups, b #region "Terminate requests and Timers" - protected void TerminatePendingWebRequest() - { - TerminatePendingWebRequest(null); - } - - protected void TerminatePendingWebRequest(RequestState state) - { - PNConfiguration currentConfig; - IPubnubLog currentLog; - if (state != null && state.Request != null) - { - try - { - if (pubnubConfig.TryGetValue(PubnubInstance.InstanceId, out currentConfig) && pubnubLog.TryGetValue(PubnubInstance.InstanceId, out currentLog)) - { - LoggingMethod.WriteToLog(currentLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, TerminatePendingWebRequest - {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), state.Request.RequestUri.ToString()), currentConfig.LogVerbosity); - } - state.Request.Abort(); - } - catch { /* ignore */ } - } - else - { - ICollection keyCollection = ChannelRequest[PubnubInstance.InstanceId].Keys; - foreach (string key in keyCollection.ToList()) - { - HttpWebRequest currentRequest; - if (ChannelRequest[PubnubInstance.InstanceId].TryGetValue(key, out currentRequest) && currentRequest != null) - { - TerminatePendingWebRequest(currentRequest); - } - } - } - } - - protected static void TerminatePendingWebRequest(HttpWebRequest request) - { - if (request != null) - { - try - { - request.Abort(); - } - catch { /* ignore */ } - } - } - private void RemoveChannelDictionary() { RemoveChannelDictionary(null); @@ -1946,13 +1823,13 @@ private void RemoveChannelDictionary(RequestState state) PNConfiguration currentConfig; IPubnubLog currentLog; - if (state != null && state.Request != null) + if (state != null && state.RequestCancellationTokenSource != null) { string channel = (state.Channels != null) ? string.Join(",", state.Channels.OrderBy(x => x).ToArray()) : ","; if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(channel)) { - HttpWebRequest removedRequest; + CancellationTokenSource removedRequest; bool removeKey = ChannelRequest[PubnubInstance.InstanceId].TryRemove(channel, out removedRequest); if (pubnubConfig.TryGetValue(PubnubInstance.InstanceId, out currentConfig) && pubnubLog.TryGetValue(PubnubInstance.InstanceId, out currentLog)) { @@ -1975,7 +1852,7 @@ private void RemoveChannelDictionary(RequestState state) List keysList = keyCollection.ToList(); foreach (string key in keysList) { - HttpWebRequest currentRequest; + CancellationTokenSource currentRequest; if (ChannelRequest[PubnubInstance.InstanceId].TryGetValue(key, out currentRequest) && currentRequest != null) { bool removeKey = ChannelRequest[PubnubInstance.InstanceId].TryRemove(key, out currentRequest); @@ -2116,14 +1993,6 @@ protected static void TerminatePresenceHeartbeatTimer() } } - protected static void TerminateTelemetry() - { - if (pubnubTelemetryMgr != null) - { - pubnubTelemetryMgr.Destroy(); - } - } - protected void TerminateTokenManagerCollection() { if (PubnubTokenMgrCollection != null && PubnubTokenMgrCollection.Count > 0) @@ -2313,11 +2182,10 @@ internal void EndPendingRequests() } RemoveChannelDictionary(); - TerminatePendingWebRequest(); + //TerminatePendingWebRequest(); TerminateReconnectTimer(); RemoveUserState(); - PubnubCoreBase.TerminatePresenceHeartbeatTimer(); - TerminateTelemetry(); + TerminatePresenceHeartbeatTimer(); TerminateDedupeManager(); TerminateTokenManagerCollection(); @@ -2362,35 +2230,6 @@ internal void EndPendingRequests() internal static void RemoveHttpClients() { //Conditionalmethod logic -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - if (httpClientNetworkStatus != null) - { - try{ - httpClientNetworkStatus.CancelPendingRequests(); - httpClientNetworkStatus.Dispose(); - httpClientNetworkStatus = null; - } - catch { /* ignore */ } - } - if (httpClientSubscribe != null) - { - try{ - httpClientSubscribe.CancelPendingRequests(); - httpClientSubscribe.Dispose(); - httpClientSubscribe = null; - } - catch { /* ignore */ } - } - if (httpClientNonsubscribe != null) - { - try{ - httpClientNonsubscribe.CancelPendingRequests(); - httpClientNonsubscribe.Dispose(); - httpClientNonsubscribe = null; - } - catch { /* ignore */ } - } -#endif } internal void TerminateCurrentSubscriberRequest() @@ -2399,32 +2238,22 @@ internal void TerminateCurrentSubscriberRequest() if (channels != null) { string multiChannel = (channels.Length > 0) ? string.Join(",", channels.OrderBy(x => x).ToArray()) : ","; - HttpWebRequest request; + CancellationTokenSource request; if (ChannelRequest[PubnubInstance.InstanceId].ContainsKey(multiChannel) && ChannelRequest[PubnubInstance.InstanceId].TryGetValue(multiChannel, out request) && request != null) { PNConfiguration currentConfig; IPubnubLog currentLog; if (pubnubConfig.TryGetValue(PubnubInstance.InstanceId, out currentConfig) && pubnubLog.TryGetValue(PubnubInstance.InstanceId, out currentLog)) { - LoggingMethod.WriteToLog(currentLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} TerminateCurrentSubsciberRequest {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.RequestUri.ToString()), currentConfig.LogVerbosity); + LoggingMethod.WriteToLog(currentLog, string.Format(CultureInfo.InvariantCulture, "DateTime {0} TerminateCurrentSubsciberRequest {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.IsCancellationRequested), currentConfig.LogVerbosity); } try { - request.Abort(); + request.Cancel(); } catch { /* ignore */ } } } -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - if (httpClientSubscribe != null) - { - try - { - httpClientSubscribe.CancelPendingRequests(); - } - catch { /* ignore */ } - } -#endif } #endregion @@ -2518,7 +2347,7 @@ internal void InitializeDefaultVariableObjectStates() { if (!ChannelRequest.ContainsKey(PubnubInstance.InstanceId)) { - ChannelRequest.GetOrAdd(PubnubInstance.InstanceId, new ConcurrentDictionary()); + ChannelRequest.GetOrAdd(PubnubInstance.InstanceId, new ConcurrentDictionary()); } if (!ChannelInternetStatus.ContainsKey(PubnubInstance.InstanceId)) { diff --git a/src/Api/PubnubApi/PubnubHttp.cs b/src/Api/PubnubApi/PubnubHttp.cs index 818e23166..b8efcd42a 100644 --- a/src/Api/PubnubApi/PubnubHttp.cs +++ b/src/Api/PubnubApi/PubnubHttp.cs @@ -1,1415 +1,1365 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.IO; -using System.Net; -using System.Collections; -using System.Threading.Tasks; -using System.Globalization; -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 -using System.Net.Http; -using System.Net.Http.Headers; -#endif - -namespace PubnubApi -{ - public class PubnubHttp : IPubnubHttp - { - private readonly PNConfiguration pubnubConfig; - private readonly IJsonPluggableLibrary jsonLib; - private readonly IPubnubLog pubnubLog; - private readonly EndPoint.TelemetryManager pubnubTelemetryMgr; -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - private static HttpClient httpClientSubscribe; - private static HttpClient httpClientNonsubscribe; -#endif - -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - public PubnubHttp(PNConfiguration config, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubLog log, EndPoint.TelemetryManager telemetryManager, HttpClient refHttpClientSubscribe, HttpClient refHttpClientNonsubscribe) -#else - public PubnubHttp(PNConfiguration config, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubLog log, EndPoint.TelemetryManager telemetryManager) -#endif - { - pubnubConfig = config; - jsonLib = jsonPluggableLibrary; - pubnubLog = log; - pubnubTelemetryMgr = telemetryManager; -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - httpClientSubscribe = refHttpClientSubscribe; - httpClientNonsubscribe = refHttpClientNonsubscribe; -#endif - } - - HttpWebRequest IPubnubHttp.SetProxy(HttpWebRequest request) - { -#if !NETSTANDARD10 - if (pubnubConfig.Proxy != null) - { - request.Proxy = pubnubConfig.Proxy; - } -#endif - return request; - } - - HttpWebRequest IPubnubHttp.SetTimeout(RequestState pubnubRequestState, HttpWebRequest request) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - request.Timeout = GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000; -#endif - return request; - } - - HttpWebRequest IPubnubHttp.SetNoCache(HttpWebRequest request) - { - request.Headers["Cache-Control"] = "no-cache"; - request.Headers["Pragma"] = "no-cache"; - - return request; - } - - HttpWebRequest IPubnubHttp.SetServicePointConnectionLimit(RequestState pubnubRequestState, HttpWebRequest request) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - if (pubnubRequestState.ResponseType == PNOperationType.PNHeartbeatOperation) - { - int estimateConnectionLimit = pubnubConfig.SubscribeTimeout/pubnubConfig.PresenceInterval; - if (estimateConnectionLimit > request.ServicePoint.ConnectionLimit) - { - request.ServicePoint.ConnectionLimit = estimateConnectionLimit; - } - } -#endif - return request; - } - - HttpWebRequest IPubnubHttp.SetServicePointSetTcpKeepAlive(RequestState pubnubRequestState, HttpWebRequest request) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - if (pubnubConfig.PresenceInterval > 0) - { - request.ServicePoint.SetTcpKeepAlive(true, pubnubConfig.PresenceInterval * 1000, 1000); - } -#endif - return request; - } - - HttpWebRequest IPubnubHttp.SetTcpKeepAlive(HttpWebRequest request) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - request.KeepAlive = true; -#endif - return request; - } - - async Task IPubnubHttp.SendRequestAndGetJsonResponse(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request) - { - if (pubnubConfig.UseClassicHttpWebRequest) - { - return await SendRequestAndGetJsonResponseClassicHttp(requestUri, pubnubRequestState, request).ConfigureAwait(false); - } - else - { -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - if (pubnubConfig.UseTaskFactoryAsyncInsteadOfHttpClient) - { - return await SendRequestAndGetJsonResponseTaskFactory(pubnubRequestState, request).ConfigureAwait(false); - } - else - { - return await SendRequestAndGetJsonResponseHttpClient(requestUri, pubnubRequestState, request).ConfigureAwait(false); - } -#else - return await SendRequestAndGetJsonResponseTaskFactory(pubnubRequestState, request).ConfigureAwait(false); -#endif - } - - } - - async Task IPubnubHttp.SendRequestAndGetStreamResponse(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request) - { - if (pubnubConfig.UseClassicHttpWebRequest) - { - return await SendRequestAndGetStreamResponseClassicHttp(pubnubRequestState, request).ConfigureAwait(false); - } - else - { -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - if (pubnubConfig.UseTaskFactoryAsyncInsteadOfHttpClient) - { - return await SendRequestAndGetStreamResponseTaskFactory(pubnubRequestState, request).ConfigureAwait(false); - } - else - { - return await SendRequestAndGetStreamResponseHttpClient(requestUri, pubnubRequestState).ConfigureAwait(false); - } -#else - return await SendRequestAndGetStreamResponseTaskFactory(pubnubRequestState, request).ConfigureAwait(false); -#endif - } - - } - - async Task IPubnubHttp.SendRequestAndGetJsonResponseWithPOST(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request, byte[] postData, string contentType) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, postData bytearray len= {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), postData.Length), pubnubConfig.LogVerbosity); - if (pubnubConfig.UseClassicHttpWebRequest) - { - return await SendRequestAndGetJsonResponseClassicHttpWithPOST(pubnubRequestState, request, postData, contentType).ConfigureAwait(false); - } - else - { -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - if (pubnubConfig.UseTaskFactoryAsyncInsteadOfHttpClient) - { - return await SendRequestAndGetJsonResponseTaskFactoryWithPOST(pubnubRequestState, request, postData, contentType).ConfigureAwait(false); - } - else - { - return await SendRequestAndGetJsonResponseHttpClientWithPOST(requestUri, pubnubRequestState, postData, contentType).ConfigureAwait(false); - } -#else - return await SendRequestAndGetJsonResponseTaskFactoryWithPOST(pubnubRequestState, request, postData, contentType).ConfigureAwait(false); -#endif - } - } - - async Task IPubnubHttp.SendRequestAndGetJsonResponseWithPATCH(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request, byte[] patchData, string contentType) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, patchData = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), Encoding.UTF8.GetString(patchData, 0, patchData.Length)), pubnubConfig.LogVerbosity); - if (pubnubConfig.UseClassicHttpWebRequest) - { - return await SendRequestAndGetJsonResponseClassicHttpWithPATCH(pubnubRequestState, request, patchData).ConfigureAwait(false); - } - else - { -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - if (pubnubConfig.UseTaskFactoryAsyncInsteadOfHttpClient) - { - return await SendRequestAndGetJsonResponseTaskFactoryWithPATCH(pubnubRequestState, request, patchData, contentType).ConfigureAwait(false); - } - else - { - return await SendRequestAndGetJsonResponseHttpClientWithPATCH(requestUri, pubnubRequestState, patchData, contentType).ConfigureAwait(false); - } -#else - return await SendRequestAndGetJsonResponseTaskFactoryWithPATCH(pubnubRequestState, request, patchData, contentType).ConfigureAwait(false); -#endif - } - } - -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 - async Task SendRequestAndGetJsonResponseHttpClient(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request) - { - string jsonString = ""; - HttpResponseMessage response = null; - CancellationTokenSource cts = new CancellationTokenSource(); - try - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseHttpClient", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - cts.CancelAfter(GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000); - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - if (pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation) - { - response = await httpClientSubscribe.GetAsync(requestUri, cts.Token).ConfigureAwait(false); - } - else if (string.Compare(FindHttpGetOrDeleteMethod(pubnubRequestState), "DELETE", StringComparison.CurrentCultureIgnoreCase) == 0) - { - response = await httpClientNonsubscribe.DeleteAsync(requestUri, cts.Token).ConfigureAwait(false); - } - else - { - response = await httpClientNonsubscribe.GetAsync(requestUri, cts.Token).ConfigureAwait(false); - } - if (response.IsSuccessStatusCode || response.Content != null) - { - var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType); - } - using (StreamReader streamReader = new StreamReader(stream)) - { - jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); - pubnubRequestState.GotJsonResponse = true; - } - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); - } - else - { - stopWatch.Stop(); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); - } - - } - catch (HttpRequestException httpReqEx) - { - if (httpReqEx.InnerException is WebException) - { - WebException currentWebException = httpReqEx.InnerException as WebException; - if (currentWebException != null) - { - if (currentWebException.Response != null) - { - pubnubRequestState.Response = currentWebException.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(currentWebException.Response.GetResponseStream())) - { - //Need to return this response - jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from HttpClient WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; - } - } - } +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using System.Threading; +//using System.IO; +//using System.Net; +//using System.Collections; +//using System.Threading.Tasks; +//using System.Globalization; +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +//using System.Net.Http; +//using System.Net.Http.Headers; +//#endif + +//namespace PubnubApi +//{ +// public class PubnubHttp : IPubnubHttp +// { +// private readonly PNConfiguration pubnubConfig; +// private readonly IJsonPluggableLibrary jsonLib; +// private readonly IPubnubLog pubnubLog; +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +// private static HttpClient httpClientSubscribe; +// private static HttpClient httpClientNonsubscribe; +//#endif + +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +// public PubnubHttp(PNConfiguration config, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubLog log, HttpClient refHttpClientSubscribe, HttpClient refHttpClientNonsubscribe) +//#else +// public PubnubHttp(PNConfiguration config, IJsonPluggableLibrary jsonPluggableLibrary, IPubnubLog log) +//#endif +// { +// pubnubConfig = config; +// jsonLib = jsonPluggableLibrary; +// pubnubLog = log; +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +// httpClientSubscribe = refHttpClientSubscribe; +// httpClientNonsubscribe = refHttpClientNonsubscribe; +//#endif +// } + +// HttpWebRequest IPubnubHttp.SetProxy(HttpWebRequest request) +// { +//#if !NETSTANDARD10 +// if (pubnubConfig.Proxy != null) +// { +// request.Proxy = pubnubConfig.Proxy; +// } +//#endif +// return request; +// } + +// HttpWebRequest IPubnubHttp.SetTimeout(RequestState pubnubRequestState, HttpWebRequest request) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// request.Timeout = GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000; +//#endif +// return request; +// } + +// HttpWebRequest IPubnubHttp.SetNoCache(HttpWebRequest request) +// { +// request.Headers["Cache-Control"] = "no-cache"; +// request.Headers["Pragma"] = "no-cache"; + +// return request; +// } + +// HttpWebRequest IPubnubHttp.SetServicePointConnectionLimit(RequestState pubnubRequestState, HttpWebRequest request) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// if (pubnubRequestState.ResponseType == PNOperationType.PNHeartbeatOperation) +// { +// int estimateConnectionLimit = pubnubConfig.SubscribeTimeout/pubnubConfig.PresenceInterval; +// if (estimateConnectionLimit > request.ServicePoint.ConnectionLimit) +// { +// request.ServicePoint.ConnectionLimit = estimateConnectionLimit; +// } +// } +//#endif +// return request; +// } + +// HttpWebRequest IPubnubHttp.SetServicePointSetTcpKeepAlive(RequestState pubnubRequestState, HttpWebRequest request) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// if (pubnubConfig.PresenceInterval > 0) +// { +// request.ServicePoint.SetTcpKeepAlive(true, pubnubConfig.PresenceInterval * 1000, 1000); +// } +//#endif +// return request; +// } + +// HttpWebRequest IPubnubHttp.SetTcpKeepAlive(HttpWebRequest request) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// request.KeepAlive = true; +//#endif +// return request; +// } + +// async Task IPubnubHttp.SendRequestAndGetJsonResponse(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request) +// { +// if (pubnubConfig.UseClassicHttpWebRequest) +// { +// return await SendRequestAndGetJsonResponseClassicHttp(requestUri, pubnubRequestState, request).ConfigureAwait(false); +// } +// else +// { +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +// if (pubnubConfig.UseTaskFactoryAsyncInsteadOfHttpClient) +// { +// return await SendRequestAndGetJsonResponseTaskFactory(pubnubRequestState, request).ConfigureAwait(false); +// } +// else +// { +// return await SendRequestAndGetJsonResponseHttpClient(requestUri, pubnubRequestState, request).ConfigureAwait(false); +// } +//#else +// return await SendRequestAndGetJsonResponseTaskFactory(pubnubRequestState, request).ConfigureAwait(false); +//#endif +// } + +// } + +// async Task IPubnubHttp.SendRequestAndGetStreamResponse(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request) +// { +// if (pubnubConfig.UseClassicHttpWebRequest) +// { +// return await SendRequestAndGetStreamResponseClassicHttp(pubnubRequestState, request).ConfigureAwait(false); +// } +// else +// { +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +// if (pubnubConfig.UseTaskFactoryAsyncInsteadOfHttpClient) +// { +// return await SendRequestAndGetStreamResponseTaskFactory(pubnubRequestState, request).ConfigureAwait(false); +// } +// else +// { +// return await SendRequestAndGetStreamResponseHttpClient(requestUri, pubnubRequestState).ConfigureAwait(false); +// } +//#else +// return await SendRequestAndGetStreamResponseTaskFactory(pubnubRequestState, request).ConfigureAwait(false); +//#endif +// } + +// } + +// async Task IPubnubHttp.SendRequestAndGetJsonResponseWithPOST(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request, byte[] postData, string contentType) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, postData bytearray len= {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), postData.Length), pubnubConfig.LogVerbosity); +// if (pubnubConfig.UseClassicHttpWebRequest) +// { +// return await SendRequestAndGetJsonResponseClassicHttpWithPOST(pubnubRequestState, request, postData, contentType).ConfigureAwait(false); +// } +// else +// { +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +// if (pubnubConfig.UseTaskFactoryAsyncInsteadOfHttpClient) +// { +// return await SendRequestAndGetJsonResponseTaskFactoryWithPOST(pubnubRequestState, request, postData, contentType).ConfigureAwait(false); +// } +// else +// { +// return await SendRequestAndGetJsonResponseHttpClientWithPOST(requestUri, pubnubRequestState, postData, contentType).ConfigureAwait(false); +// } +//#else +// return await SendRequestAndGetJsonResponseTaskFactoryWithPOST(pubnubRequestState, request, postData, contentType).ConfigureAwait(false); +//#endif +// } +// } + +// async Task IPubnubHttp.SendRequestAndGetJsonResponseWithPATCH(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request, byte[] patchData, string contentType) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, patchData = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), Encoding.UTF8.GetString(patchData, 0, patchData.Length)), pubnubConfig.LogVerbosity); +// if (pubnubConfig.UseClassicHttpWebRequest) +// { +// return await SendRequestAndGetJsonResponseClassicHttpWithPATCH(pubnubRequestState, request, patchData).ConfigureAwait(false); +// } +// else +// { +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +// if (pubnubConfig.UseTaskFactoryAsyncInsteadOfHttpClient) +// { +// return await SendRequestAndGetJsonResponseTaskFactoryWithPATCH(pubnubRequestState, request, patchData, contentType).ConfigureAwait(false); +// } +// else +// { +// return await SendRequestAndGetJsonResponseHttpClientWithPATCH(requestUri, pubnubRequestState, patchData, contentType).ConfigureAwait(false); +// } +//#else +// return await SendRequestAndGetJsonResponseTaskFactoryWithPATCH(pubnubRequestState, request, patchData, contentType).ConfigureAwait(false); +//#endif +// } +// } + +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 && !NETSTANDARD10 +// async Task SendRequestAndGetJsonResponseHttpClient(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request) +// { +// string jsonString = ""; +// HttpResponseMessage response = null; +// CancellationTokenSource cts = new CancellationTokenSource(); +// try +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseHttpClient", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); +// cts.CancelAfter(GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000); +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +// if (pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation) +// { +// response = await httpClientSubscribe.GetAsync(requestUri, cts.Token).ConfigureAwait(false); +// } +// else if (string.Compare(FindHttpGetOrDeleteMethod(pubnubRequestState), "DELETE", StringComparison.CurrentCultureIgnoreCase) == 0) +// { +// response = await httpClientNonsubscribe.DeleteAsync(requestUri, cts.Token).ConfigureAwait(false); +// } +// else +// { +// response = await httpClientNonsubscribe.GetAsync(requestUri, cts.Token).ConfigureAwait(false); +// } +// if (response.IsSuccessStatusCode || response.Content != null) +// { +// var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); +// stopWatch.Stop(); +// using (StreamReader streamReader = new StreamReader(stream)) +// { +// jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +// pubnubRequestState.GotJsonResponse = true; +// } +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); +// } +// else +// { +// stopWatch.Stop(); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); +// } + +// } +// catch (HttpRequestException httpReqEx) +// { +// if (httpReqEx.InnerException is WebException) +// { +// WebException currentWebException = httpReqEx.InnerException as WebException; +// if (currentWebException != null) +// { +// if (currentWebException.Response != null) +// { +// pubnubRequestState.Response = currentWebException.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(currentWebException.Response.GetResponseStream())) +// { +// //Need to return this response +// jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from HttpClient WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return jsonString; +// } +// } +// } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClient InnerException WebException status {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ((WebException)httpReqEx.InnerException).Status.ToString()), pubnubConfig.LogVerbosity); - throw httpReqEx.InnerException; - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClient HttpRequestException {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), httpReqEx.Message), pubnubConfig.LogVerbosity); - throw; - } - catch (Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClient Exception {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); - throw; - } - finally - { - if (response != null && response.Content != null) - { - response.Content.Dispose(); - pubnubRequestState.Response = null; - pubnubRequestState.Request = null; - } - } - return jsonString; - } - - async Task SendRequestAndGetStreamResponseHttpClient(Uri requestUri, RequestState pubnubRequestState) - { - byte[] streamBytes = null; - HttpResponseMessage response = null; - CancellationTokenSource cts = new CancellationTokenSource(); - try - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetStreamResponseHttpClient", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - cts.CancelAfter(GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000); - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - response = await httpClientNonsubscribe.GetAsync(requestUri, cts.Token).ConfigureAwait(false); - if (response.IsSuccessStatusCode || response.Content != null) - { - var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType); - } - using (MemoryStream ms = new MemoryStream()) - { - stream.CopyTo(ms); - streamBytes = ms.ToArray(); - } - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); - } - else - { - stopWatch.Stop(); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); - } - - } - catch (HttpRequestException httpReqEx) - { - if (httpReqEx.InnerException is WebException) - { - WebException currentWebException = httpReqEx.InnerException as WebException; - if (currentWebException != null) - { - if (currentWebException.Response != null) - { - pubnubRequestState.Response = currentWebException.Response as HttpWebResponse; - var errorStream = currentWebException.Response.GetResponseStream(); - using (MemoryStream ms = new MemoryStream()) - { - errorStream.CopyTo(ms); - streamBytes = ms.ToArray(); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved Stream Bytes from HttpClient WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - } - } - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetStreamResponseHttpClient InnerException WebException status {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ((WebException)httpReqEx.InnerException).Status.ToString()), pubnubConfig.LogVerbosity); - throw httpReqEx.InnerException; - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetStreamResponseHttpClient HttpRequestException {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), httpReqEx.Message), pubnubConfig.LogVerbosity); - throw; - } - catch (Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetStreamResponseHttpClient Exception {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); - throw; - } - finally - { - if (response != null && response.Content != null) - { - response.Content.Dispose(); - pubnubRequestState.Response = null; - pubnubRequestState.Request = null; - } - } - return streamBytes; - } - - async Task SendRequestAndGetJsonResponseHttpClientWithPOST(Uri requestUri, RequestState pubnubRequestState, byte[] postData, string contentType) - { - string jsonString = ""; - HttpResponseMessage response = null; - CancellationTokenSource cts = new CancellationTokenSource(); - try - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetJsonResponseHttpClientPOST Before httpClient.GetAsync", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - cts.CancelAfter(GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000); - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - ByteArrayContent postDataContent = new ByteArrayContent(postData); - postDataContent.Headers.Remove("Content-Type"); - if (string.IsNullOrEmpty(contentType)) - { - postDataContent.Headers.TryAddWithoutValidation("Content-Type", "application/json"); - } - else - { - postDataContent.Headers.TryAddWithoutValidation("Content-Type", contentType); - } - if (pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation) - { - response = await httpClientSubscribe.PostAsync(requestUri, postDataContent, cts.Token).ConfigureAwait(false); - } - else - { - response = await httpClientNonsubscribe.PostAsync(requestUri, postDataContent, cts.Token).ConfigureAwait(false); - } - - if (response.IsSuccessStatusCode || response.Content != null) - { - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got POST HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); - if ((int)response.StatusCode == 204 && pubnubRequestState.ResponseType == PNOperationType.PNFileUploadOperation) - { - return "{}"; - } - else - { - var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - using (StreamReader streamReader = new StreamReader(stream)) - { - jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); - pubnubRequestState.GotJsonResponse = true; - } - } - } - else - { - stopWatch.Stop(); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No POST HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); - } - - } - catch (HttpRequestException httpReqEx) - { - if (httpReqEx.InnerException is WebException) - { - WebException currentWebException = httpReqEx.InnerException as WebException; - if (currentWebException != null) - { - if (currentWebException.Response != null) - { - pubnubRequestState.Response = currentWebException.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(currentWebException.Response.GetResponseStream())) - { - //Need to return this response - jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from HttpClient POST WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; - } - } - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST InnerException WebException status {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ((WebException)httpReqEx.InnerException).Status.ToString()), pubnubConfig.LogVerbosity); - throw httpReqEx.InnerException; - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST HttpRequestException {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), httpReqEx.Message), pubnubConfig.LogVerbosity); - throw; - } - catch (Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST Exception {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); - throw; - } - finally - { - if (response != null && response.Content != null) - { - response.Content.Dispose(); - pubnubRequestState.Response = null; - pubnubRequestState.Request = null; - } - } - return jsonString; - } - - async Task SendRequestAndGetJsonResponseHttpClientWithPATCH(Uri requestUri, RequestState pubnubRequestState, byte[] patchData, string contentType) - { - string jsonString = ""; - HttpResponseMessage response = null; - CancellationTokenSource cts = new CancellationTokenSource(); - try - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetJsonResponseHttpClientWithPATCH Before httpClient.SendAsync", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - cts.CancelAfter(GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000); - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - HttpMethod httpMethod = new HttpMethod("PATCH"); - ByteArrayContent patchDataContent = new ByteArrayContent(patchData); - patchDataContent.Headers.Remove("Content-Type"); - if (string.IsNullOrEmpty(contentType)) - { - patchDataContent.Headers.TryAddWithoutValidation("Content-Type", "application/json"); - } - else - { - patchDataContent.Headers.TryAddWithoutValidation("Content-Type", contentType); - } - - HttpRequestMessage requestMsg = new HttpRequestMessage(httpMethod, requestUri) - { - Content = patchDataContent - }; - if (pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation) - { - response = await httpClientSubscribe.SendAsync(requestMsg, cts.Token).ConfigureAwait(false); - } - else - { - response = await httpClientNonsubscribe.SendAsync(requestMsg, cts.Token).ConfigureAwait(false); - } - - if (response.IsSuccessStatusCode || response.Content != null) - { - var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - using (StreamReader streamReader = new StreamReader(stream)) - { - jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); - pubnubRequestState.GotJsonResponse = true; - } - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got POST HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); - } - else - { - stopWatch.Stop(); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No POST HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); - } - - } - catch (HttpRequestException httpReqEx) - { - if (httpReqEx.InnerException is WebException) - { - WebException currentWebException = httpReqEx.InnerException as WebException; - if (currentWebException != null) - { - if (currentWebException.Response != null) - { - pubnubRequestState.Response = currentWebException.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(currentWebException.Response.GetResponseStream())) - { - //Need to return this response - jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from HttpClient POST WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; - } - } - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST InnerException WebException status {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ((WebException)httpReqEx.InnerException).Status.ToString()), pubnubConfig.LogVerbosity); - throw httpReqEx.InnerException; - } - - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST HttpRequestException {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), httpReqEx.Message), pubnubConfig.LogVerbosity); - throw; - } - catch (Exception ex) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST Exception {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); - throw; - } - finally - { - if (response != null && response.Content != null) - { - response.Content.Dispose(); - pubnubRequestState.Response = null; - pubnubRequestState.Request = null; - } - } - return jsonString; - } -#endif - - async Task SendRequestAndGetJsonResponseTaskFactory(RequestState pubnubRequestState, HttpWebRequest request) - { - HttpWebResponse response = null; - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseTaskFactory", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - try - { - request.Method = FindHttpGetOrDeleteMethod(pubnubRequestState); - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - var _ = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); - response = await Task.Factory.FromAsync(request.BeginGetResponse, asyncPubnubResult => (HttpWebResponse)request.EndGetResponse(asyncPubnubResult), pubnubRequestState).ConfigureAwait(false); - stopWatch.Stop(); - if (pubnubConfig.EnableTelemetry && pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - if (response != null) - { - pubnubRequestState.Response = response; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got PubnubWebResponse for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.RequestUri.ToString())); - using (StreamReader streamReader = new StreamReader(response.GetResponseStream())) - { - //Need to return this response - #if NET35 || NET40 - string jsonString = streamReader.ReadToEnd(); - #else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); - #endif - System.Diagnostics.Debug.WriteLine(jsonString); - pubnubRequestState.GotJsonResponse = true; - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetJsonResponseTaskFactory => Retrieved JSON", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - - if (pubnubRequestState.Response != null) - { - #if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); - #endif - pubnubRequestState.Response = null; - pubnubRequestState.Request = null; - } - - return jsonString; - } - } - else - { - return ""; - } - } - catch (WebException ex) - { - if (ex.Response != null) - { - pubnubRequestState.Response = ex.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) - { - //Need to return this response -#if NET35 || NET40 - string jsonString = streamReader.ReadToEnd(); -#else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); -#endif - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; - } - } - - if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 - && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) - { - throw; - } - return ""; - } - catch - { - throw; - } - } - - async Task SendRequestAndGetStreamResponseTaskFactory(RequestState pubnubRequestState, HttpWebRequest request) - { - HttpWebResponse response = null; - byte[] streamBytes; - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetStreamResponseTaskFactory", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - try - { - request.Method = FindHttpGetOrDeleteMethod(pubnubRequestState); - var _ = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - response = await Task.Factory.FromAsync(request.BeginGetResponse, asyncPubnubResult => (HttpWebResponse)request.EndGetResponse(asyncPubnubResult), pubnubRequestState).ConfigureAwait(false); - stopWatch.Stop(); - if (pubnubConfig.EnableTelemetry && pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - pubnubRequestState.Response = response; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got PubnubWebResponse for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.RequestUri.ToString())); - int statusCode = (int)pubnubRequestState.Response.StatusCode; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, status code = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), statusCode)); - using (Stream stream = response.GetResponseStream()) - { - long totalSize = 0; - long receivedSize = 0; - //Allocate 1K buffer - byte[] buffer = new byte[1024]; - using(MemoryStream ms = new MemoryStream()) - { -#if NET35 || NET40 - int bytesRead = stream.Read(buffer, 0, buffer.Length); -#else - int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); -#endif - receivedSize += bytesRead; - while (bytesRead > 0) - { - ms.Write(buffer, 0, bytesRead); - bytesRead = stream.Read(buffer, 0, buffer.Length); - receivedSize += bytesRead; - } - streamBytes = ms.ToArray(); - } - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, totalsize = {1}; received = {2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), totalSize, receivedSize)); - //Need to return this response - pubnubRequestState.GotJsonResponse = true; - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved Stream", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - - if (pubnubRequestState.Response != null) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); -#endif - pubnubRequestState.Response = null; - pubnubRequestState.Request = null; - } - - return streamBytes; - } - } - catch (WebException ex) - { - if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 - && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) - { - throw; - } - return null; - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Exception in SendRequestAndGetStreamResponseTaskFactory {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex)); - throw; - } - } - - async Task SendRequestAndGetJsonResponseTaskFactoryWithPOST(RequestState pubnubRequestState, HttpWebRequest request, byte[] postData, string contentType) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before Task.Factory.FromAsync With POST", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - try - { - request.Method = "POST"; - Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); - - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - - request.ContentType = contentType; - - using (var requestStream = await Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, pubnubRequestState).ConfigureAwait(false)) - { -#if NET35 || NET40 - requestStream.Write(postData, 0, postData.Length); - requestStream.Flush(); -#else - await requestStream.WriteAsync(postData, 0, postData.Length).ConfigureAwait(false); - await requestStream.FlushAsync().ConfigureAwait(false); -#endif - - } - - WebResponse response = await Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, pubnubRequestState).ConfigureAwait(false); - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - pubnubRequestState.Response = response as HttpWebResponse; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got PubnubWebResponse With POST for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.RequestUri.ToString())); - int statusCode = (int)pubnubRequestState.Response.StatusCode; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, statusCode {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), statusCode)); - if (statusCode == 204 && pubnubRequestState.ResponseType == PNOperationType.PNFileUploadOperation) - { - return "{}"; - } - else - { - using (StreamReader streamReader = new StreamReader(response.GetResponseStream())) - { - //Need to return this response -#if NET35 || NET40 - string jsonString = streamReader.ReadToEnd(); -#else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); -#endif - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With POST", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - pubnubRequestState.GotJsonResponse = true; - - if (pubnubRequestState.Response != null) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); -#endif - pubnubRequestState.Response = null; - pubnubRequestState.Request = null; - } - - return jsonString; - } - } - } - catch (WebException ex) - { - if (ex.Response != null) - { - pubnubRequestState.Response = ex.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) - { - //Need to return this response -#if NET35 || NET40 - string jsonString = streamReader.ReadToEnd(); -#else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); -#endif - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With POST from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; - } - } - - if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 - && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) - { - throw; - } - return ""; - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Exception in SendRequestAndGetJsonResponseTaskFactoryWithPOST {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex)); - throw; - } - } - - async Task SendRequestAndGetJsonResponseTaskFactoryWithPATCH(RequestState pubnubRequestState, HttpWebRequest request, byte[] patchData, string contentType) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before Task.Factory.FromAsync With PATCH", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - try - { - request.Method = "PATCH"; - Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); - - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - - request.ContentType = "application/json"; - - using (var requestStream = await Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, pubnubRequestState).ConfigureAwait(false)) - { -#if NET35 || NET40 - requestStream.Write(patchData, 0, patchData.Length); - requestStream.Flush(); -#else - await requestStream.WriteAsync(patchData, 0, patchData.Length).ConfigureAwait(false); - await requestStream.FlushAsync().ConfigureAwait(false); -#endif - - } - - WebResponse response = await Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, pubnubRequestState).ConfigureAwait(false); - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - pubnubRequestState.Response = response as HttpWebResponse; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got PubnubWebResponse With PATCH for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.RequestUri.ToString())); - using (StreamReader streamReader = new StreamReader(response.GetResponseStream())) - { - //Need to return this response -#if NET35 || NET40 - string jsonString = streamReader.ReadToEnd(); -#else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); -#endif - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With PATCH", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - pubnubRequestState.GotJsonResponse = true; - - if (pubnubRequestState.Response != null) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); -#endif - pubnubRequestState.Response = null; - pubnubRequestState.Request = null; - } - - return jsonString; - } - } - catch (WebException ex) - { - if (ex.Response != null) - { - pubnubRequestState.Response = ex.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) - { - //Need to return this response -#if NET35 || NET40 - string jsonString = streamReader.ReadToEnd(); -#else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); -#endif - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With PATCH from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; - } - } - - if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 - && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) - { - throw; - } - return ""; - } - catch - { - throw; - } - } - - async Task SendRequestAndGetJsonResponseClassicHttp(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseClassicHttp", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - var taskComplete = new TaskCompletionSource(); - try - { - request.Method = FindHttpGetOrDeleteMethod(pubnubRequestState); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before BeginGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - request.BeginGetResponse(new AsyncCallback( - async (asynchronousResult) => { - RequestState asyncRequestState = asynchronousResult.AsyncState as RequestState; - HttpWebRequest asyncWebRequest = asyncRequestState.Request as HttpWebRequest; - if (asyncWebRequest != null) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before EndGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - HttpWebResponse asyncWebResponse = (HttpWebResponse)asyncWebRequest.EndGetResponse(asynchronousResult); - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - asyncRequestState.Response = asyncWebResponse; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, After EndGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - using (StreamReader streamReader = new StreamReader(asyncWebResponse.GetResponseStream())) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Inside StreamReader", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - //Need to return this response - string jsonString = streamReader.ReadToEnd(); - asyncRequestState.GotJsonResponse = true; - - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetJsonResponseClassicHttp => Retrieved JSON", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - taskComplete.TrySetResult(jsonString); - } - if (asyncRequestState.Response != null) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); -#endif - asyncRequestState.Response = null; - asyncRequestState.Request = null; - } - } - } - ), pubnubRequestState); - - Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); - return taskComplete.Task.Result; - } - catch (WebException ex) - { - if (ex.Response != null) - { - pubnubRequestState.Response = ex.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) - { - //Need to return this response -#if NET35 || NET40 - await Task.Factory.StartNew(() => { }).ConfigureAwait(false); - string jsonString = streamReader.ReadToEnd(); -#else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); -#endif - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; - } - } +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClient InnerException WebException status {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ((WebException)httpReqEx.InnerException).Status.ToString()), pubnubConfig.LogVerbosity); +// throw httpReqEx.InnerException; +// } + +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClient HttpRequestException {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), httpReqEx.Message), pubnubConfig.LogVerbosity); +// throw; +// } +// catch (Exception ex) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClient Exception {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); +// throw; +// } +// finally +// { +// if (response != null && response.Content != null) +// { +// response.Content.Dispose(); +// pubnubRequestState.Response = null; +// pubnubRequestState.RequestCancellationTokenSource = null; +// } +// } +// return jsonString; +// } + +// async Task SendRequestAndGetStreamResponseHttpClient(Uri requestUri, RequestState pubnubRequestState) +// { +// byte[] streamBytes = null; +// HttpResponseMessage response = null; +// CancellationTokenSource cts = new CancellationTokenSource(); +// try +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetStreamResponseHttpClient", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); +// cts.CancelAfter(GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000); +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +// response = await httpClientNonsubscribe.GetAsync(requestUri, cts.Token).ConfigureAwait(false); +// if (response.IsSuccessStatusCode || response.Content != null) +// { +// var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); +// stopWatch.Stop(); +// using (MemoryStream ms = new MemoryStream()) +// { +// stream.CopyTo(ms); +// streamBytes = ms.ToArray(); +// } +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); +// } +// else +// { +// stopWatch.Stop(); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); +// } + +// } +// catch (HttpRequestException httpReqEx) +// { +// if (httpReqEx.InnerException is WebException) +// { +// WebException currentWebException = httpReqEx.InnerException as WebException; +// if (currentWebException != null) +// { +// if (currentWebException.Response != null) +// { +// pubnubRequestState.Response = currentWebException.Response as HttpWebResponse; +// var errorStream = currentWebException.Response.GetResponseStream(); +// using (MemoryStream ms = new MemoryStream()) +// { +// errorStream.CopyTo(ms); +// streamBytes = ms.ToArray(); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved Stream Bytes from HttpClient WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// } +// } +// } + +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetStreamResponseHttpClient InnerException WebException status {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ((WebException)httpReqEx.InnerException).Status.ToString()), pubnubConfig.LogVerbosity); +// throw httpReqEx.InnerException; +// } + +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetStreamResponseHttpClient HttpRequestException {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), httpReqEx.Message), pubnubConfig.LogVerbosity); +// throw; +// } +// catch (Exception ex) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetStreamResponseHttpClient Exception {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); +// throw; +// } +// finally +// { +// if (response != null && response.Content != null) +// { +// response.Content.Dispose(); +// pubnubRequestState.Response = null; +// pubnubRequestState.RequestCancellationTokenSource = null; +// } +// } +// return streamBytes; +// } + +// async Task SendRequestAndGetJsonResponseHttpClientWithPOST(Uri requestUri, RequestState pubnubRequestState, byte[] postData, string contentType) +// { +// string jsonString = ""; +// HttpResponseMessage response = null; +// CancellationTokenSource cts = new CancellationTokenSource(); +// try +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetJsonResponseHttpClientPOST Before httpClient.GetAsync", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// cts.CancelAfter(GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000); +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +// ByteArrayContent postDataContent = new ByteArrayContent(postData); +// postDataContent.Headers.Remove("Content-Type"); +// if (string.IsNullOrEmpty(contentType)) +// { +// postDataContent.Headers.TryAddWithoutValidation("Content-Type", "application/json"); +// } +// else +// { +// postDataContent.Headers.TryAddWithoutValidation("Content-Type", contentType); +// } +// if (pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation) +// { +// response = await httpClientSubscribe.PostAsync(requestUri, postDataContent, cts.Token).ConfigureAwait(false); +// } +// else +// { +// response = await httpClientNonsubscribe.PostAsync(requestUri, postDataContent, cts.Token).ConfigureAwait(false); +// } + +// if (response.IsSuccessStatusCode || response.Content != null) +// { +// stopWatch.Stop(); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got POST HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); +// if ((int)response.StatusCode == 204 && pubnubRequestState.ResponseType == PNOperationType.PNFileUploadOperation) +// { +// return "{}"; +// } +// else +// { +// var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); +// using (StreamReader streamReader = new StreamReader(stream)) +// { +// jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +// pubnubRequestState.GotJsonResponse = true; +// } +// } +// } +// else +// { +// stopWatch.Stop(); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No POST HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); +// } + +// } +// catch (HttpRequestException httpReqEx) +// { +// if (httpReqEx.InnerException is WebException) +// { +// WebException currentWebException = httpReqEx.InnerException as WebException; +// if (currentWebException != null) +// { +// if (currentWebException.Response != null) +// { +// pubnubRequestState.Response = currentWebException.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(currentWebException.Response.GetResponseStream())) +// { +// //Need to return this response +// jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from HttpClient POST WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return jsonString; +// } +// } +// } + +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST InnerException WebException status {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ((WebException)httpReqEx.InnerException).Status.ToString()), pubnubConfig.LogVerbosity); +// throw httpReqEx.InnerException; +// } + +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST HttpRequestException {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), httpReqEx.Message), pubnubConfig.LogVerbosity); +// throw; +// } +// catch (Exception ex) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST Exception {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); +// throw; +// } +// finally +// { +// if (response != null && response.Content != null) +// { +// response.Content.Dispose(); +// pubnubRequestState.Response = null; +// pubnubRequestState.RequestCancellationTokenSource = null; +// } +// } +// return jsonString; +// } + +// async Task SendRequestAndGetJsonResponseHttpClientWithPATCH(Uri requestUri, RequestState pubnubRequestState, byte[] patchData, string contentType) +// { +// string jsonString = ""; +// HttpResponseMessage response = null; +// CancellationTokenSource cts = new CancellationTokenSource(); +// try +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetJsonResponseHttpClientWithPATCH Before httpClient.SendAsync", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// cts.CancelAfter(GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000); +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +// HttpMethod httpMethod = new HttpMethod("PATCH"); +// ByteArrayContent patchDataContent = new ByteArrayContent(patchData); +// patchDataContent.Headers.Remove("Content-Type"); +// if (string.IsNullOrEmpty(contentType)) +// { +// patchDataContent.Headers.TryAddWithoutValidation("Content-Type", "application/json"); +// } +// else +// { +// patchDataContent.Headers.TryAddWithoutValidation("Content-Type", contentType); +// } + +// HttpRequestMessage requestMsg = new HttpRequestMessage(httpMethod, requestUri) +// { +// Content = patchDataContent +// }; +// if (pubnubRequestState.ResponseType == PNOperationType.PNSubscribeOperation) +// { +// response = await httpClientSubscribe.SendAsync(requestMsg, cts.Token).ConfigureAwait(false); +// } +// else +// { +// response = await httpClientNonsubscribe.SendAsync(requestMsg, cts.Token).ConfigureAwait(false); +// } + +// if (response.IsSuccessStatusCode || response.Content != null) +// { +// var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); +// stopWatch.Stop(); +// using (StreamReader streamReader = new StreamReader(stream)) +// { +// jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +// pubnubRequestState.GotJsonResponse = true; +// } +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got POST HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); +// } +// else +// { +// stopWatch.Stop(); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, No POST HttpResponseMessage for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), requestUri)); +// } + +// } +// catch (HttpRequestException httpReqEx) +// { +// if (httpReqEx.InnerException is WebException) +// { +// WebException currentWebException = httpReqEx.InnerException as WebException; +// if (currentWebException != null) +// { +// if (currentWebException.Response != null) +// { +// pubnubRequestState.Response = currentWebException.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(currentWebException.Response.GetResponseStream())) +// { +// //Need to return this response +// jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from HttpClient POST WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return jsonString; +// } +// } +// } + +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST InnerException WebException status {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ((WebException)httpReqEx.InnerException).Status.ToString()), pubnubConfig.LogVerbosity); +// throw httpReqEx.InnerException; +// } + +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST HttpRequestException {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), httpReqEx.Message), pubnubConfig.LogVerbosity); +// throw; +// } +// catch (Exception ex) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, SendRequestAndGetJsonResponseHttpClientPOST Exception {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex.Message), pubnubConfig.LogVerbosity); +// throw; +// } +// finally +// { +// if (response != null && response.Content != null) +// { +// response.Content.Dispose(); +// pubnubRequestState.Response = null; +// pubnubRequestState.RequestCancellationTokenSource = null; +// } +// } +// return jsonString; +// } +//#endif + +// async Task SendRequestAndGetJsonResponseTaskFactory(RequestState pubnubRequestState, HttpWebRequest request) +// { +// HttpWebResponse response = null; +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseTaskFactory", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); +// try +// { +// request.Method = FindHttpGetOrDeleteMethod(pubnubRequestState); +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +// var _ = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); +// response = await Task.Factory.FromAsync(request.BeginGetResponse, asyncPubnubResult => (HttpWebResponse)request.EndGetResponse(asyncPubnubResult), pubnubRequestState).ConfigureAwait(false); +// stopWatch.Stop(); +// if (response != null) +// { +// pubnubRequestState.Response = response; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got PubnubWebResponse for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.RequestUri.ToString())); +// using (StreamReader streamReader = new StreamReader(response.GetResponseStream())) +// { +// //Need to return this response +// #if NET35 || NET40 +// string jsonString = streamReader.ReadToEnd(); +// #else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +// #endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// pubnubRequestState.GotJsonResponse = true; +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetJsonResponseTaskFactory => Retrieved JSON", DateTime.Now.ToString(CultureInfo.InvariantCulture))); + +// if (pubnubRequestState.Response != null) +// { +// #if NET35 || NET40 || NET45 || NET461 || NET48 +// pubnubRequestState.Response.Close(); +// #endif +// pubnubRequestState.Response = null; +// pubnubRequestState.RequestCancellationTokenSource = null; +// } + +// return jsonString; +// } +// } +// else +// { +// return ""; +// } +// } +// catch (WebException ex) +// { +// if (ex.Response != null) +// { +// pubnubRequestState.Response = ex.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) +// { +// //Need to return this response +//#if NET35 || NET40 +// string jsonString = streamReader.ReadToEnd(); +//#else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +//#endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return jsonString; +// } +// } + +// if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 +// && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) +// { +// throw; +// } +// return ""; +// } +// catch +// { +// throw; +// } +// } + +// async Task SendRequestAndGetStreamResponseTaskFactory(RequestState pubnubRequestState, HttpWebRequest request) +// { +// HttpWebResponse response = null; +// byte[] streamBytes; +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetStreamResponseTaskFactory", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); +// try +// { +// request.Method = FindHttpGetOrDeleteMethod(pubnubRequestState); +// var _ = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +// response = await Task.Factory.FromAsync(request.BeginGetResponse, asyncPubnubResult => (HttpWebResponse)request.EndGetResponse(asyncPubnubResult), pubnubRequestState).ConfigureAwait(false); +// stopWatch.Stop(); +// pubnubRequestState.Response = response; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got PubnubWebResponse for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.RequestUri.ToString())); +// int statusCode = (int)pubnubRequestState.Response.StatusCode; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, status code = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), statusCode)); +// using (Stream stream = response.GetResponseStream()) +// { +// long totalSize = 0; +// long receivedSize = 0; +// //Allocate 1K buffer +// byte[] buffer = new byte[1024]; +// using(MemoryStream ms = new MemoryStream()) +// { +//#if NET35 || NET40 +// int bytesRead = stream.Read(buffer, 0, buffer.Length); +//#else +// int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); +//#endif +// receivedSize += bytesRead; +// while (bytesRead > 0) +// { +// ms.Write(buffer, 0, bytesRead); +// bytesRead = stream.Read(buffer, 0, buffer.Length); +// receivedSize += bytesRead; +// } +// streamBytes = ms.ToArray(); +// } +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, totalsize = {1}; received = {2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), totalSize, receivedSize)); +// //Need to return this response +// pubnubRequestState.GotJsonResponse = true; +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved Stream", DateTime.Now.ToString(CultureInfo.InvariantCulture))); + +// if (pubnubRequestState.Response != null) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// pubnubRequestState.Response.Close(); +//#endif +// pubnubRequestState.Response = null; +// pubnubRequestState.RequestCancellationTokenSource = null; +// } + +// return streamBytes; +// } +// } +// catch (WebException ex) +// { +// if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 +// && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) +// { +// throw; +// } +// return null; +// } +// catch (Exception ex) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Exception in SendRequestAndGetStreamResponseTaskFactory {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex)); +// throw; +// } +// } + +// async Task SendRequestAndGetJsonResponseTaskFactoryWithPOST(RequestState pubnubRequestState, HttpWebRequest request, byte[] postData, string contentType) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before Task.Factory.FromAsync With POST", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// try +// { +// request.Method = "POST"; +// Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); + +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); + +// request.ContentType = contentType; + +// using (var requestStream = await Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, pubnubRequestState).ConfigureAwait(false)) +// { +//#if NET35 || NET40 +// requestStream.Write(postData, 0, postData.Length); +// requestStream.Flush(); +//#else +// await requestStream.WriteAsync(postData, 0, postData.Length).ConfigureAwait(false); +// await requestStream.FlushAsync().ConfigureAwait(false); +//#endif + +// } + +// WebResponse response = await Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, pubnubRequestState).ConfigureAwait(false); +// stopWatch.Stop(); +// pubnubRequestState.Response = response as HttpWebResponse; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got PubnubWebResponse With POST for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.RequestUri.ToString())); +// int statusCode = (int)pubnubRequestState.Response.StatusCode; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, statusCode {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), statusCode)); +// if (statusCode == 204 && pubnubRequestState.ResponseType == PNOperationType.PNFileUploadOperation) +// { +// return "{}"; +// } +// else +// { +// using (StreamReader streamReader = new StreamReader(response.GetResponseStream())) +// { +// //Need to return this response +//#if NET35 || NET40 +// string jsonString = streamReader.ReadToEnd(); +//#else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +//#endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With POST", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// pubnubRequestState.GotJsonResponse = true; + +// if (pubnubRequestState.Response != null) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// pubnubRequestState.Response.Close(); +//#endif +// pubnubRequestState.Response = null; +// pubnubRequestState.RequestCancellationTokenSource = null; +// } + +// return jsonString; +// } +// } +// } +// catch (WebException ex) +// { +// if (ex.Response != null) +// { +// pubnubRequestState.Response = ex.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) +// { +// //Need to return this response +//#if NET35 || NET40 +// string jsonString = streamReader.ReadToEnd(); +//#else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +//#endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With POST from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return jsonString; +// } +// } + +// if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 +// && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) +// { +// throw; +// } +// return ""; +// } +// catch (Exception ex) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Exception in SendRequestAndGetJsonResponseTaskFactoryWithPOST {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ex)); +// throw; +// } +// } + +// async Task SendRequestAndGetJsonResponseTaskFactoryWithPATCH(RequestState pubnubRequestState, HttpWebRequest request, byte[] patchData, string contentType) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before Task.Factory.FromAsync With PATCH", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// try +// { +// request.Method = "PATCH"; +// Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); + +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); + +// request.ContentType = "application/json"; + +// using (var requestStream = await Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, pubnubRequestState).ConfigureAwait(false)) +// { +//#if NET35 || NET40 +// requestStream.Write(patchData, 0, patchData.Length); +// requestStream.Flush(); +//#else +// await requestStream.WriteAsync(patchData, 0, patchData.Length).ConfigureAwait(false); +// await requestStream.FlushAsync().ConfigureAwait(false); +//#endif + +// } + +// WebResponse response = await Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, pubnubRequestState).ConfigureAwait(false); +// stopWatch.Stop(); +// pubnubRequestState.Response = response as HttpWebResponse; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Got PubnubWebResponse With PATCH for {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), request.RequestUri.ToString())); +// using (StreamReader streamReader = new StreamReader(response.GetResponseStream())) +// { +// //Need to return this response +//#if NET35 || NET40 +// string jsonString = streamReader.ReadToEnd(); +//#else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +//#endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With PATCH", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// pubnubRequestState.GotJsonResponse = true; + +// if (pubnubRequestState.Response != null) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// pubnubRequestState.Response.Close(); +//#endif +// pubnubRequestState.Response = null; +// pubnubRequestState.RequestCancellationTokenSource = null; +// } + +// return jsonString; +// } +// } +// catch (WebException ex) +// { +// if (ex.Response != null) +// { +// pubnubRequestState.Response = ex.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) +// { +// //Need to return this response +//#if NET35 || NET40 +// string jsonString = streamReader.ReadToEnd(); +//#else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +//#endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With PATCH from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return jsonString; +// } +// } + +// if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 +// && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) +// { +// throw; +// } +// return ""; +// } +// catch +// { +// throw; +// } +// } + +// async Task SendRequestAndGetJsonResponseClassicHttp(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseClassicHttp", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); +// var taskComplete = new TaskCompletionSource(); +// try +// { +// request.Method = FindHttpGetOrDeleteMethod(pubnubRequestState); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before BeginGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +// request.BeginGetResponse(new AsyncCallback( +// async (asynchronousResult) => { +// RequestState asyncRequestState = asynchronousResult.AsyncState as RequestState; +// HttpWebRequest asyncWebRequest = asyncRequestState.RequestCancellationTokenSource as HttpWebRequest; +// if (asyncWebRequest != null) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before EndGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// HttpWebResponse asyncWebResponse = (HttpWebResponse)asyncWebRequest.EndGetResponse(asynchronousResult); +// stopWatch.Stop(); +// asyncRequestState.Response = asyncWebResponse; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, After EndGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// using (StreamReader streamReader = new StreamReader(asyncWebResponse.GetResponseStream())) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Inside StreamReader", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// //Need to return this response +// string jsonString = streamReader.ReadToEnd(); +// asyncRequestState.GotJsonResponse = true; + +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetJsonResponseClassicHttp => Retrieved JSON", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// taskComplete.TrySetResult(jsonString); +// } +// if (asyncRequestState.Response != null) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// pubnubRequestState.Response.Close(); +//#endif +// asyncRequestState.Response = null; +// asyncRequestState.RequestCancellationTokenSource = null; +// } +// } +// } +// ), pubnubRequestState); + +// Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); +// return taskComplete.Task.Result; +// } +// catch (WebException ex) +// { +// if (ex.Response != null) +// { +// pubnubRequestState.Response = ex.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) +// { +// //Need to return this response +//#if NET35 || NET40 +// await Task.Factory.StartNew(() => { }).ConfigureAwait(false); +// string jsonString = streamReader.ReadToEnd(); +//#else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +//#endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return jsonString; +// } +// } - if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 - && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) - { - taskComplete.TrySetException(ex); - } - return ""; - } - catch (Exception ex) - { - taskComplete.TrySetException(ex); - return ""; - } - } - - async Task SendRequestAndGetStreamResponseClassicHttp(RequestState pubnubRequestState, HttpWebRequest request) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetStreamResponseClassicHttp", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - var taskComplete = new TaskCompletionSource(); - try - { - request.Method = FindHttpGetOrDeleteMethod(pubnubRequestState); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before BeginGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - request.BeginGetResponse(new AsyncCallback( - async (asynchronousResult) => { - RequestState asyncRequestState = asynchronousResult.AsyncState as RequestState; - HttpWebRequest asyncWebRequest = asyncRequestState.Request as HttpWebRequest; - if (asyncWebRequest != null) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before EndGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - HttpWebResponse asyncWebResponse = (HttpWebResponse)asyncWebRequest.EndGetResponse(asynchronousResult); - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - asyncRequestState.Response = asyncWebResponse; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, After EndGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - using (StreamReader streamReader = new StreamReader(asyncWebResponse.GetResponseStream())) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Inside StreamReader", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - //Need to return this response - string jsonString = streamReader.ReadToEnd(); - asyncRequestState.GotJsonResponse = true; - - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetStreamResponseClassicHttp => Retrieved JSON", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - taskComplete.TrySetResult(null); - } - if (asyncRequestState.Response != null) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); -#endif - asyncRequestState.Response = null; - asyncRequestState.Request = null; - } - } - } - ), pubnubRequestState); - - Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); - return taskComplete.Task.Result; - } - catch (WebException ex) - { - if (ex.Response != null) - { - pubnubRequestState.Response = ex.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) - { - //Need to return this response -#if NET35 || NET40 - await Task.Factory.StartNew(() => { }).ConfigureAwait(false); - string jsonString = streamReader.ReadToEnd(); -#else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); -#endif - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return null; - } - } - - if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 - && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) - { - taskComplete.TrySetException(ex); - } - return null; - } - catch (Exception ex) - { - taskComplete.TrySetException(ex); - return null; - } - } - - async Task SendRequestAndGetJsonResponseClassicHttpWithPOST(RequestState pubnubRequestState, HttpWebRequest request, byte[] postData, string contentType) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseClassicHttpWithPOST", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - var taskComplete = new TaskCompletionSource(); - try - { - request.Method = "POST"; - request.ContentType = contentType; - - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 - using (var requestStream = await Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, pubnubRequestState).ConfigureAwait(false)) - { - requestStream.Write(postData, 0, postData.Length); - requestStream.Flush(); - } -#else - using (var requestStream = request.GetRequestStream()) - { - requestStream.Write(postData, 0, postData.Length); - requestStream.Flush(); - } -#endif - - IAsyncResult asyncResult = request.BeginGetResponse(new AsyncCallback( - async (asynchronousResult) => { - RequestState asyncRequestState = asynchronousResult.AsyncState as RequestState; - HttpWebRequest asyncWebRequest = asyncRequestState.Request as HttpWebRequest; - if (asyncWebRequest != null) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before EndGetResponse With POST ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - HttpWebResponse asyncWebResponse = (HttpWebResponse)asyncWebRequest.EndGetResponse(asynchronousResult); - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - asyncRequestState.Response = asyncWebResponse; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, After EndGetResponse With POST ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - using (StreamReader streamReader = new StreamReader(asyncWebResponse.GetResponseStream())) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Inside StreamReader With POST ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - //Need to return this response - string jsonString = streamReader.ReadToEnd(); - asyncRequestState.GotJsonResponse = true; - - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With POST ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - taskComplete.TrySetResult(jsonString); - } - if (asyncRequestState.Response != null) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); -#endif - asyncRequestState.Response = null; - asyncRequestState.Request = null; - } - - } - } - ), pubnubRequestState); - - Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); - return taskComplete.Task.Result; - } - catch (WebException ex) - { - if (ex.Response != null) - { - pubnubRequestState.Response = ex.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) - { - //Need to return this response -#if NET35 || NET40 - await Task.Factory.StartNew(() => { }).ConfigureAwait(false); - string jsonString = streamReader.ReadToEnd(); -#else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); -#endif - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With POST from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; - } - } - - if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 - && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) - { - taskComplete.TrySetException(ex); - } - return ""; - } - catch (Exception ex) - { - taskComplete.TrySetException(ex); - return ""; - } - } - - async Task SendRequestAndGetJsonResponseClassicHttpWithPATCH(RequestState pubnubRequestState, HttpWebRequest request, byte[] patchData) - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseClassicHttpWithPATCH", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - var taskComplete = new TaskCompletionSource(); - try - { - request.Method = "PATCH"; - request.ContentType = "application/json"; - - System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); -#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 - using (var requestStream = await Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, pubnubRequestState).ConfigureAwait(false)) - { - requestStream.Write(patchData, 0, patchData.Length); - requestStream.Flush(); - } -#else - using (var requestStream = request.GetRequestStream()) - { - requestStream.Write(patchData, 0, patchData.Length); - requestStream.Flush(); - } -#endif - - IAsyncResult asyncResult = request.BeginGetResponse(new AsyncCallback( - async (asynchronousResult) => { - RequestState asyncRequestState = asynchronousResult.AsyncState as RequestState; - HttpWebRequest asyncWebRequest = asyncRequestState.Request as HttpWebRequest; - if (asyncWebRequest != null) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before EndGetResponse With PATCH ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - HttpWebResponse asyncWebResponse = (HttpWebResponse)asyncWebRequest.EndGetResponse(asynchronousResult); - stopWatch.Stop(); - if (pubnubTelemetryMgr != null) - { - await pubnubTelemetryMgr.StoreLatency(stopWatch.ElapsedMilliseconds, pubnubRequestState.ResponseType).ConfigureAwait(false); - } - asyncRequestState.Response = asyncWebResponse; - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, After EndGetResponse With PATCH ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - using (StreamReader streamReader = new StreamReader(asyncWebResponse.GetResponseStream())) - { - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Inside StreamReader With PATCH ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - //Need to return this response - string jsonString = streamReader.ReadToEnd(); - asyncRequestState.GotJsonResponse = true; - - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With PATCH ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - taskComplete.TrySetResult(jsonString); - } - if (asyncRequestState.Response != null) - { -#if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); -#endif - asyncRequestState.Response = null; - asyncRequestState.Request = null; - } - - } - } - ), pubnubRequestState); - - Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); - return taskComplete.Task.Result; - } - catch (WebException ex) - { - if (ex.Response != null) - { - pubnubRequestState.Response = ex.Response as HttpWebResponse; - using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) - { - //Need to return this response -#if NET35 || NET40 - await Task.Factory.StartNew(() => { }).ConfigureAwait(false); - string jsonString = streamReader.ReadToEnd(); -#else - string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); -#endif - System.Diagnostics.Debug.WriteLine(jsonString); - System.Diagnostics.Debug.WriteLine(""); - System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With PATCH from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; - } - } - - if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 - && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) - { - taskComplete.TrySetException(ex); - } - return ""; - } - catch (Exception ex) - { - taskComplete.TrySetException(ex); - return ""; - } - } - - protected void OnPubnubWebRequestTimeout(object state, bool timeout) - { - if (timeout && state != null) - { - RequestState currentState = state as RequestState; - if (currentState != null) - { - HttpWebRequest request = currentState.Request; - if (request != null) - { - string currentMultiChannel = (currentState.Channels == null) ? "" : string.Join(",", currentState.Channels.OrderBy(x => x).ToArray()); - string currentMultiChannelGroup = (currentState.ChannelGroups == null) ? "" : string.Join(",", currentState.ChannelGroups.OrderBy(x => x).ToArray()); - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, OnPubnubWebRequestTimeout: client request timeout reached.Request abort for channel={1} ;channelgroup={2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentMultiChannel, currentMultiChannelGroup), pubnubConfig.LogVerbosity); - currentState.Timeout = true; - try - { - request.Abort(); - } - catch { /* ignore */ } - } - } - else - { - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, OnPubnubWebRequestTimeout: client request timeout reached. However state is unknown", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - } - } - } - - protected void OnPubnubWebRequestTimeout(System.Object requestState) - { - RequestState currentState = requestState as RequestState; - if (currentState != null && currentState.Response == null && currentState.Request != null) - { - currentState.Timeout = true; - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, **WP7 OnPubnubWebRequestTimeout** Initiated at {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentState.TimeQueued.GetValueOrDefault().ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - - try - { - currentState.Request.Abort(); - } - catch { /* ignore */ } - - if (currentState.ResponseType != PNOperationType.PNSubscribeOperation - && currentState.ResponseType != PNOperationType.Presence - && currentState.ResponseType != PNOperationType.PNHeartbeatOperation - && currentState.ResponseType != PNOperationType.Leave) - { - PNStatusCategory errorCategory = PNStatusCategory.PNTimeoutCategory; - PNStatus status = new StatusBuilder(pubnubConfig, jsonLib).CreateStatusResponse(currentState.ResponseType, errorCategory, currentState, (int)HttpStatusCode.NotFound, new PNException("Request timeout")); - - if (currentState.Channels != null && currentState.Channels.Length > 0) - { - status.AffectedChannels.AddRange(currentState.Channels); - } - - if (currentState.ChannelGroups != null && currentState.ChannelGroups.Length > 0) - { - status.AffectedChannels.AddRange(currentState.ChannelGroups); - } - - if (currentState.PubnubCallback != null) - { - currentState.PubnubCallback.OnResponse(default(T), status); - } - } - } - } - - protected int GetTimeoutInSecondsForResponseType(PNOperationType type) - { - int timeout; - if (type == PNOperationType.PNSubscribeOperation || type == PNOperationType.Presence) - { - timeout = pubnubConfig.SubscribeTimeout; - } - else if (type == PNOperationType.PNGenerateFileUploadUrlOperation) - { - timeout = pubnubConfig.NonSubscribeRequestTimeout*3; - } - else if (type == PNOperationType.PNFileUploadOperation || type == PNOperationType.PNDownloadFileOperation) - { - timeout = pubnubConfig.NonSubscribeRequestTimeout * 25; - } - else - { - timeout = pubnubConfig.NonSubscribeRequestTimeout; - } - return timeout; - } - - private static string FindHttpGetOrDeleteMethod(RequestState pubnubRequestState) - { - return (pubnubRequestState != null && (pubnubRequestState.ResponseType == PNOperationType.PNDeleteMessageOperation - || pubnubRequestState.ResponseType == PNOperationType.PNDeleteUuidMetadataOperation - || pubnubRequestState.ResponseType == PNOperationType.PNDeleteChannelMetadataOperation - || pubnubRequestState.ResponseType == PNOperationType.PNRemoveMessageActionOperation - || pubnubRequestState.ResponseType == PNOperationType.PNAccessManagerRevokeToken - || pubnubRequestState.ResponseType == PNOperationType.PNDeleteFileOperation)) ? "DELETE" : "GET"; - - } - } -} +// if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 +// && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) +// { +// taskComplete.TrySetException(ex); +// } +// return ""; +// } +// catch (Exception ex) +// { +// taskComplete.TrySetException(ex); +// return ""; +// } +// } + +// async Task SendRequestAndGetStreamResponseClassicHttp(RequestState pubnubRequestState, HttpWebRequest request) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetStreamResponseClassicHttp", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); +// var taskComplete = new TaskCompletionSource(); +// try +// { +// request.Method = FindHttpGetOrDeleteMethod(pubnubRequestState); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before BeginGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +// request.BeginGetResponse(new AsyncCallback( +// async (asynchronousResult) => { +// RequestState asyncRequestState = asynchronousResult.AsyncState as RequestState; +// HttpWebRequest asyncWebRequest = asyncRequestState.RequestCancellationTokenSource as HttpWebRequest; +// if (asyncWebRequest != null) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before EndGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// HttpWebResponse asyncWebResponse = (HttpWebResponse)asyncWebRequest.EndGetResponse(asynchronousResult); +// stopWatch.Stop(); +// asyncRequestState.Response = asyncWebResponse; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, After EndGetResponse", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// using (StreamReader streamReader = new StreamReader(asyncWebResponse.GetResponseStream())) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Inside StreamReader", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// //Need to return this response +// string jsonString = streamReader.ReadToEnd(); +// asyncRequestState.GotJsonResponse = true; + +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, SendRequestAndGetStreamResponseClassicHttp => Retrieved JSON", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// taskComplete.TrySetResult(null); +// } +// if (asyncRequestState.Response != null) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// pubnubRequestState.Response.Close(); +//#endif +// asyncRequestState.Response = null; +// asyncRequestState.RequestCancellationTokenSource = null; +// } +// } +// } +// ), pubnubRequestState); + +// Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); +// return taskComplete.Task.Result; +// } +// catch (WebException ex) +// { +// if (ex.Response != null) +// { +// pubnubRequestState.Response = ex.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) +// { +// //Need to return this response +//#if NET35 || NET40 +// await Task.Factory.StartNew(() => { }).ConfigureAwait(false); +// string jsonString = streamReader.ReadToEnd(); +//#else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +//#endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return null; +// } +// } + +// if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 +// && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) +// { +// taskComplete.TrySetException(ex); +// } +// return null; +// } +// catch (Exception ex) +// { +// taskComplete.TrySetException(ex); +// return null; +// } +// } + +// async Task SendRequestAndGetJsonResponseClassicHttpWithPOST(RequestState pubnubRequestState, HttpWebRequest request, byte[] postData, string contentType) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseClassicHttpWithPOST", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); +// var taskComplete = new TaskCompletionSource(); +// try +// { +// request.Method = "POST"; +// request.ContentType = contentType; + +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 +// using (var requestStream = await Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, pubnubRequestState).ConfigureAwait(false)) +// { +// requestStream.Write(postData, 0, postData.Length); +// requestStream.Flush(); +// } +//#else +// using (var requestStream = request.GetRequestStream()) +// { +// requestStream.Write(postData, 0, postData.Length); +// requestStream.Flush(); +// } +//#endif + +// IAsyncResult asyncResult = request.BeginGetResponse(new AsyncCallback( +// async (asynchronousResult) => { +// RequestState asyncRequestState = asynchronousResult.AsyncState as RequestState; +// HttpWebRequest asyncWebRequest = asyncRequestState.RequestCancellationTokenSource as HttpWebRequest; +// if (asyncWebRequest != null) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before EndGetResponse With POST ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// HttpWebResponse asyncWebResponse = (HttpWebResponse)asyncWebRequest.EndGetResponse(asynchronousResult); +// stopWatch.Stop(); +// asyncRequestState.Response = asyncWebResponse; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, After EndGetResponse With POST ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// using (StreamReader streamReader = new StreamReader(asyncWebResponse.GetResponseStream())) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Inside StreamReader With POST ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// //Need to return this response +// string jsonString = streamReader.ReadToEnd(); +// asyncRequestState.GotJsonResponse = true; + +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With POST ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// taskComplete.TrySetResult(jsonString); +// } +// if (asyncRequestState.Response != null) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// pubnubRequestState.Response.Close(); +//#endif +// asyncRequestState.Response = null; +// asyncRequestState.RequestCancellationTokenSource = null; +// } + +// } +// } +// ), pubnubRequestState); + +// Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); +// return taskComplete.Task.Result; +// } +// catch (WebException ex) +// { +// if (ex.Response != null) +// { +// pubnubRequestState.Response = ex.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) +// { +// //Need to return this response +//#if NET35 || NET40 +// await Task.Factory.StartNew(() => { }).ConfigureAwait(false); +// string jsonString = streamReader.ReadToEnd(); +//#else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +//#endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With POST from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return jsonString; +// } +// } + +// if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 +// && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) +// { +// taskComplete.TrySetException(ex); +// } +// return ""; +// } +// catch (Exception ex) +// { +// taskComplete.TrySetException(ex); +// return ""; +// } +// } + +// async Task SendRequestAndGetJsonResponseClassicHttpWithPATCH(RequestState pubnubRequestState, HttpWebRequest request, byte[] patchData) +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, Inside SendRequestAndGetJsonResponseClassicHttpWithPATCH", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); +// var taskComplete = new TaskCompletionSource(); +// try +// { +// request.Method = "PATCH"; +// request.ContentType = "application/json"; + +// System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); +// stopWatch.Start(); +//#if !NET35 && !NET40 && !NET45 && !NET461 && !NET48 +// using (var requestStream = await Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, pubnubRequestState).ConfigureAwait(false)) +// { +// requestStream.Write(patchData, 0, patchData.Length); +// requestStream.Flush(); +// } +//#else +// using (var requestStream = request.GetRequestStream()) +// { +// requestStream.Write(patchData, 0, patchData.Length); +// requestStream.Flush(); +// } +//#endif + +// IAsyncResult asyncResult = request.BeginGetResponse(new AsyncCallback( +// async (asynchronousResult) => { +// RequestState asyncRequestState = asynchronousResult.AsyncState as RequestState; +// HttpWebRequest asyncWebRequest = asyncRequestState.RequestCancellationTokenSource as HttpWebRequest; +// if (asyncWebRequest != null) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Before EndGetResponse With PATCH ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// HttpWebResponse asyncWebResponse = (HttpWebResponse)asyncWebRequest.EndGetResponse(asynchronousResult); +// stopWatch.Stop(); +// asyncRequestState.Response = asyncWebResponse; +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, After EndGetResponse With PATCH ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// using (StreamReader streamReader = new StreamReader(asyncWebResponse.GetResponseStream())) +// { +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Inside StreamReader With PATCH ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// //Need to return this response +// string jsonString = streamReader.ReadToEnd(); +// asyncRequestState.GotJsonResponse = true; + +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With PATCH ", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// taskComplete.TrySetResult(jsonString); +// } +// if (asyncRequestState.Response != null) +// { +//#if NET35 || NET40 || NET45 || NET461 || NET48 +// pubnubRequestState.Response.Close(); +//#endif +// asyncRequestState.Response = null; +// asyncRequestState.RequestCancellationTokenSource = null; +// } + +// } +// } +// ), pubnubRequestState); + +// Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite); +// return taskComplete.Task.Result; +// } +// catch (WebException ex) +// { +// if (ex.Response != null) +// { +// pubnubRequestState.Response = ex.Response as HttpWebResponse; +// using (StreamReader streamReader = new StreamReader(ex.Response.GetResponseStream())) +// { +// //Need to return this response +//#if NET35 || NET40 +// await Task.Factory.StartNew(() => { }).ConfigureAwait(false); +// string jsonString = streamReader.ReadToEnd(); +//#else +// string jsonString = await streamReader.ReadToEndAsync().ConfigureAwait(false); +//#endif +// System.Diagnostics.Debug.WriteLine(jsonString); +// System.Diagnostics.Debug.WriteLine(""); +// System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "DateTime {0}, Retrieved JSON With PATCH from WebException response", DateTime.Now.ToString(CultureInfo.InvariantCulture))); +// return jsonString; +// } +// } + +// if (ex.Message.IndexOf("The request was aborted: The request was canceled", StringComparison.OrdinalIgnoreCase) == -1 +// && ex.Message.IndexOf("Machine suspend mode enabled. No request will be processed.", StringComparison.OrdinalIgnoreCase) == -1) +// { +// taskComplete.TrySetException(ex); +// } +// return ""; +// } +// catch (Exception ex) +// { +// taskComplete.TrySetException(ex); +// return ""; +// } +// } + +// protected void OnPubnubWebRequestTimeout(object state, bool timeout) +// { +// if (timeout && state != null) +// { +// RequestState currentState = state as RequestState; +// if (currentState != null) +// { +// HttpWebRequest request = currentState.RequestCancellationTokenSource; +// if (request != null) +// { +// string currentMultiChannel = (currentState.Channels == null) ? "" : string.Join(",", currentState.Channels.OrderBy(x => x).ToArray()); +// string currentMultiChannelGroup = (currentState.ChannelGroups == null) ? "" : string.Join(",", currentState.ChannelGroups.OrderBy(x => x).ToArray()); +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, OnPubnubWebRequestTimeout: client request timeout reached.Request abort for channel={1} ;channelgroup={2}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentMultiChannel, currentMultiChannelGroup), pubnubConfig.LogVerbosity); +// currentState.Timeout = true; +// try +// { +// request.Abort(); +// } +// catch { /* ignore */ } +// } +// } +// else +// { +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, OnPubnubWebRequestTimeout: client request timeout reached. However state is unknown", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); +// } +// } +// } + +// protected void OnPubnubWebRequestTimeout(System.Object requestState) +// { +// RequestState currentState = requestState as RequestState; +// if (currentState != null && currentState.Response == null && currentState.RequestCancellationTokenSource != null) +// { +// currentState.Timeout = true; +// LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, **WP7 OnPubnubWebRequestTimeout** Initiated at {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), currentState.TimeQueued.GetValueOrDefault().ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); + +// try +// { +// currentState.RequestCancellationTokenSource.Abort(); +// } +// catch { /* ignore */ } + +// if (currentState.ResponseType != PNOperationType.PNSubscribeOperation +// && currentState.ResponseType != PNOperationType.Presence +// && currentState.ResponseType != PNOperationType.PNHeartbeatOperation +// && currentState.ResponseType != PNOperationType.Leave) +// { +// PNStatusCategory errorCategory = PNStatusCategory.PNTimeoutCategory; +// PNStatus status = new StatusBuilder(pubnubConfig, jsonLib).CreateStatusResponse(currentState.ResponseType, errorCategory, currentState, (int)HttpStatusCode.NotFound, new PNException("Request timeout")); + +// if (currentState.Channels != null && currentState.Channels.Length > 0) +// { +// status.AffectedChannels.AddRange(currentState.Channels); +// } + +// if (currentState.ChannelGroups != null && currentState.ChannelGroups.Length > 0) +// { +// status.AffectedChannels.AddRange(currentState.ChannelGroups); +// } + +// if (currentState.PubnubCallback != null) +// { +// currentState.PubnubCallback.OnResponse(default(T), status); +// } +// } +// } +// } + +// protected int GetTimeoutInSecondsForResponseType(PNOperationType type) +// { +// int timeout; +// if (type == PNOperationType.PNSubscribeOperation || type == PNOperationType.Presence) +// { +// timeout = pubnubConfig.SubscribeTimeout; +// } +// else if (type == PNOperationType.PNGenerateFileUploadUrlOperation) +// { +// timeout = pubnubConfig.NonSubscribeRequestTimeout*3; +// } +// else if (type == PNOperationType.PNFileUploadOperation || type == PNOperationType.PNDownloadFileOperation) +// { +// timeout = pubnubConfig.NonSubscribeRequestTimeout * 25; +// } +// else +// { +// timeout = pubnubConfig.NonSubscribeRequestTimeout; +// } +// return timeout; +// } + +// private static string FindHttpGetOrDeleteMethod(RequestState pubnubRequestState) +// { +// return (pubnubRequestState != null && (pubnubRequestState.ResponseType == PNOperationType.PNDeleteMessageOperation +// || pubnubRequestState.ResponseType == PNOperationType.PNDeleteUuidMetadataOperation +// || pubnubRequestState.ResponseType == PNOperationType.PNDeleteChannelMetadataOperation +// || pubnubRequestState.ResponseType == PNOperationType.PNRemoveMessageActionOperation +// || pubnubRequestState.ResponseType == PNOperationType.PNAccessManagerRevokeToken +// || pubnubRequestState.ResponseType == PNOperationType.PNDeleteFileOperation)) ? "DELETE" : "GET"; + +// } +// } +//} diff --git a/src/Api/PubnubApi/Transport/HttpClientService.cs b/src/Api/PubnubApi/Transport/HttpClientService.cs new file mode 100644 index 000000000..7637dd0a1 --- /dev/null +++ b/src/Api/PubnubApi/Transport/HttpClientService.cs @@ -0,0 +1,131 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using System.Linq; +using System.Text; + +namespace PubnubApi +{ + public class HttpClientService : IHttpClientService + { + private readonly HttpClient _httpClient; + + public HttpClientService() + { + _httpClient = new HttpClient(); + } + + public async Task GetRequest(TransportRequest transportRequest) + { + TransportResponse response; + try { + if (transportRequest.Timeout.HasValue) _httpClient.Timeout = (TimeSpan)transportRequest.Timeout; + HttpRequestMessage requestMessage = new HttpRequestMessage(method: HttpMethod.Get, requestUri: transportRequest.RequestUrl); + if (transportRequest.Headers.Keys.Count > 0) { + foreach (var kvp in transportRequest.Headers) { + requestMessage.Headers.Add(kvp.Key, kvp.Value); + } + } + var httpResult = await _httpClient.SendAsync(request: requestMessage, cancellationToken: transportRequest.CancellationToken); + var responseContent = await httpResult.Content.ReadAsByteArrayAsync(); + response = new TransportResponse() { + StatusCode = (int)httpResult.StatusCode, + Content = responseContent, + Headers = httpResult.Headers.ToDictionary(h => h.Key, h => h.Value), + RequestUrl = httpResult.RequestMessage.RequestUri.AbsolutePath + }; + } catch (Exception ex) { + response = new TransportResponse() { + RequestUrl = transportRequest.RequestUrl, + Error = ex + }; + } + return response; + } + + public async Task PostRequest(TransportRequest transportRequest) + { + if (transportRequest.Timeout.HasValue) _httpClient.Timeout = (TimeSpan)transportRequest.Timeout; + HttpContent postData = null; + + if (!string.IsNullOrEmpty(transportRequest.BodyContentString)) { + postData = new StringContent(transportRequest.BodyContentString, Encoding.UTF8, "application/json"); + } else if (transportRequest.BodyContentBytes != null) { + postData = new ByteArrayContent(transportRequest.FormData); + postData.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); + } + HttpRequestMessage requestMessage = new HttpRequestMessage(method: HttpMethod.Post, requestUri: transportRequest.RequestUrl) { Content = postData }; + if (transportRequest.Headers.Keys.Count > 0) { + foreach (var kvp in transportRequest.Headers) { + requestMessage.Headers.Add(kvp.Key, kvp.Value); + } + } + var httpResult = await _httpClient.SendAsync(request: requestMessage, cancellationToken: transportRequest.CancellationToken); + var responseContent = await httpResult.Content.ReadAsByteArrayAsync(); + var response = new TransportResponse() { + StatusCode = (int)httpResult.StatusCode, + Content = responseContent, + Headers = httpResult.Headers.ToDictionary(h => h.Key, h => h.Value), + RequestUrl = httpResult.RequestMessage.RequestUri.AbsolutePath + }; + return response; + } + + public async Task PutRequest(TransportRequest transportRequest) + { + if (transportRequest.Timeout.HasValue) _httpClient.Timeout = (TimeSpan)transportRequest.Timeout; + HttpContent postData = null; + + if (!string.IsNullOrEmpty(transportRequest.BodyContentString)) { + postData = new StringContent(transportRequest.BodyContentString, Encoding.UTF8, "application/json"); + } else if (transportRequest.BodyContentBytes != null) { + postData = new ByteArrayContent(transportRequest.FormData); + postData.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); + } + HttpRequestMessage requestMessage = new HttpRequestMessage(method: HttpMethod.Put, requestUri: transportRequest.RequestUrl) { Content = postData }; + if (transportRequest.Headers.Keys.Count > 0) { + foreach (var kvp in transportRequest.Headers) { + requestMessage.Headers.Add(kvp.Key, kvp.Value); + } + } + var httpResult = await _httpClient.SendAsync(request: requestMessage, cancellationToken: transportRequest.CancellationToken); + var responseContent = await httpResult.Content.ReadAsByteArrayAsync(); + var response = new TransportResponse() { + StatusCode = (int)httpResult.StatusCode, + Content = responseContent, + Headers = httpResult.Headers.ToDictionary(h => h.Key, h => h.Value), + RequestUrl = httpResult.RequestMessage.RequestUri.AbsolutePath + }; + return response; + } + + public async Task DeleteRequest(TransportRequest transportRequest) + { + TransportResponse response; + try { + if (transportRequest.Timeout.HasValue) _httpClient.Timeout = (TimeSpan)transportRequest.Timeout; + HttpRequestMessage requestMessage = new HttpRequestMessage(method: HttpMethod.Delete, requestUri: transportRequest.RequestUrl); + if (transportRequest.Headers.Keys.Count > 0) { + foreach (var kvp in transportRequest.Headers) { + requestMessage.Headers.Add(kvp.Key, kvp.Value); + } + } + var httpResult = await _httpClient.SendAsync(request: requestMessage, cancellationToken: transportRequest.CancellationToken); + var responseContent = await httpResult.Content.ReadAsByteArrayAsync(); + response = new TransportResponse() { + StatusCode = (int)httpResult.StatusCode, + Content = responseContent, + Headers = httpResult.Headers.ToDictionary(h => h.Key, h => h.Value), + RequestUrl = httpResult.RequestMessage.RequestUri.AbsolutePath + }; + } catch (Exception ex) { + response = new TransportResponse() { + RequestUrl = transportRequest.RequestUrl, + Error = ex + }; + } + return response; + } + } +} + diff --git a/src/Api/PubnubApi/Transport/Middleware.cs b/src/Api/PubnubApi/Transport/Middleware.cs new file mode 100644 index 000000000..3410ff7ad --- /dev/null +++ b/src/Api/PubnubApi/Transport/Middleware.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PubnubApi.EndPoint; +using PubnubApi.Security.Crypto.Common; + +namespace PubnubApi +{ + public class Middleware : ITransportMiddleware + { + private PNConfiguration configuration; + private Pubnub pnInstance; + private TokenManager tokenManager; + private IHttpClientService httpClientService; + + public Middleware(IHttpClientService httpClientService, PNConfiguration configuration, Pubnub pnInstance, TokenManager tokenManager) + { + this.configuration = configuration; + this.pnInstance = pnInstance; + this.tokenManager = tokenManager; + this.httpClientService = httpClientService; + } + + public TransportRequest PreapareTransportRequest(RequestParameter requestParameter, PNOperationType operationType) + { + long timeStamp = TranslateUtcDateTimeToSeconds(DateTime.UtcNow); + string requestid = Guid.NewGuid().ToString(); + string instanceId = pnInstance.InstanceId; + + Dictionary commonQueryParameters = new Dictionary + { + { "uuid",UriUtil.EncodeUriComponent(configuration.UserId.ToString(),PNOperationType.PNSubscribeOperation, false, false, true)}, + { "pnsdk", UriUtil.EncodeUriComponent(Pubnub.Version, PNOperationType.PNSubscribeOperation, false, false, true) } + }; + + if (configuration.IncludeInstanceIdentifier) + { + commonQueryParameters.Add("requestid", requestid); + } + if (configuration.IncludeInstanceIdentifier && !string.IsNullOrEmpty(instanceId) && instanceId.Trim().Length > 0) + { + commonQueryParameters.Add("instanceid", instanceId); + } + if (!string.IsNullOrEmpty(configuration.SecretKey)) + { + commonQueryParameters.Add("timestamp", timeStamp.ToString(CultureInfo.InvariantCulture)); + } + + var excludedAuthOperationTypes = new[] { + PNOperationType.PNTimeOperation, + PNOperationType.PNAccessManagerGrant, + PNOperationType.PNAccessManagerGrantToken, + PNOperationType.PNAccessManagerRevokeToken, + PNOperationType.ChannelGroupGrantAccess, + PNOperationType.PNAccessManagerAudit, + PNOperationType.ChannelGroupAuditAccess + }; + if (!excludedAuthOperationTypes.Contains(operationType)) + { + string authToken = tokenManager?.AuthToken?.Trim(); + string authKey = configuration.AuthKey?.Trim(); + + if (!string.IsNullOrEmpty(authToken)) + { + commonQueryParameters.Add("auth", UriUtil.EncodeUriComponent(authToken, operationType, false, false, false)); + } + else if (!string.IsNullOrEmpty(authKey)) + { + commonQueryParameters.Add("auth", UriUtil.EncodeUriComponent(authKey, operationType, false, false, false)); + } + } + requestParameter.Query = requestParameter.Query.Union(commonQueryParameters).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + var queryString = UriUtil.BuildQueryString(requestParameter.Query); + var pathString = GeneratePathString(requestParameter.PathSegment, operationType); + if (!string.IsNullOrEmpty(configuration.SecretKey)) + { + string signature = ""; + StringBuilder string_to_sign = new StringBuilder(); + string_to_sign.AppendFormat(CultureInfo.InvariantCulture, "{0}\n", requestParameter.RequestType); + string_to_sign.AppendFormat(CultureInfo.InvariantCulture, "{0}\n", configuration.PublishKey); + string_to_sign.AppendFormat(CultureInfo.InvariantCulture, "{0}\n", pathString); + string_to_sign.AppendFormat(CultureInfo.InvariantCulture, "{0}\n", queryString); + if (!string.IsNullOrEmpty(requestParameter.BodyContentString)) string_to_sign.Append(requestParameter.BodyContentString); + signature = Util.PubnubAccessManagerSign(configuration.SecretKey, string_to_sign.ToString()); + signature = string.Format(CultureInfo.InvariantCulture, "v2.{0}", signature.TrimEnd(new[] { '=' })); + requestParameter.Query.Add("signature", signature); + } + var urlString = $"{(configuration.Secure ? "https://" : "http://")}{configuration.Origin}{pathString}?{UriUtil.BuildQueryString(requestParameter.Query)}"; + + var transporRequest = new TransportRequest() + { + RequestType = requestParameter.RequestType, + RequestUrl = urlString, + BodyContentString = requestParameter.BodyContentString, + FormData = requestParameter.FormData + }; + return transporRequest; + } + + public Task Send(TransportRequest transportRequest) + { + switch (transportRequest.RequestType) + { + case Constants.GET: + return httpClientService.GetRequest(transportRequest); + case Constants.POST: + return httpClientService.PostRequest(transportRequest); + case Constants.PUT: + return httpClientService.PutRequest(transportRequest); + case Constants.DELETE: + return httpClientService.DeleteRequest(transportRequest); + default: + return httpClientService.GetRequest(transportRequest); + } + } + + private string GeneratePathString(List pathSegments, PNOperationType operationType) + { + StringBuilder pathString = new StringBuilder(); + foreach (var component in pathSegments) + { + pathString.Append('/'); + + if ((operationType == PNOperationType.PNPublishOperation || operationType == PNOperationType.PNPublishFileMessageOperation) && component == pathSegments.Last()) + { + pathString.Append(UriUtil.EncodeUriComponent(component, operationType, false, true, false)); + } + else if (operationType == PNOperationType.PNAccessManagerRevokeToken) + { + pathString.Append(UriUtil.EncodeUriComponent(component, operationType, false, false, false)); + } + else + { + pathString.Append(UriUtil.EncodeUriComponent(component, operationType, true, false, false)); + } + } + return pathString.ToString(); + } + + private long TranslateUtcDateTimeToSeconds(DateTime dotNetUTCDateTime) + { + TimeSpan timeSpan = dotNetUTCDateTime - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + long timeStamp = Convert.ToInt64(timeSpan.TotalSeconds); + return timeStamp; + } + } +} diff --git a/src/Api/PubnubApi/Transport/RequestParameter.cs b/src/Api/PubnubApi/Transport/RequestParameter.cs new file mode 100644 index 000000000..1602fa800 --- /dev/null +++ b/src/Api/PubnubApi/Transport/RequestParameter.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace PubnubApi +{ + public class RequestParameter + { + public string RequestType { get; set; } + public List PathSegment { get; set; } + public Dictionary Query { get; set; } = new Dictionary(); + public string BodyContentString { get; set; } + public byte[] FormData { get; set; } + } +} diff --git a/src/Api/PubnubApi/TransportContract/IHttpClientService.cs b/src/Api/PubnubApi/TransportContract/IHttpClientService.cs new file mode 100644 index 000000000..77503762a --- /dev/null +++ b/src/Api/PubnubApi/TransportContract/IHttpClientService.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; + +namespace PubnubApi +{ + public interface IHttpClientService + { + Task DeleteRequest(TransportRequest transportRequest); + Task GetRequest(TransportRequest transportRequest); + Task PostRequest(TransportRequest transportRequest); + Task PutRequest(TransportRequest transportRequest); + } +} \ No newline at end of file diff --git a/src/Api/PubnubApi/TransportContract/IMiddleware.cs b/src/Api/PubnubApi/TransportContract/IMiddleware.cs new file mode 100644 index 000000000..a1305473d --- /dev/null +++ b/src/Api/PubnubApi/TransportContract/IMiddleware.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace PubnubApi +{ + public interface ITransportMiddleware + { + TransportRequest PreapareTransportRequest(RequestParameter requestParameter, PNOperationType operationType); + Task Send(TransportRequest transportRequest); + } +} \ No newline at end of file diff --git a/src/Api/PubnubApi/TransportContract/TransportRequest.cs b/src/Api/PubnubApi/TransportContract/TransportRequest.cs new file mode 100644 index 000000000..882764815 --- /dev/null +++ b/src/Api/PubnubApi/TransportContract/TransportRequest.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace PubnubApi +{ + public class TransportRequest + { + public string RequestType { get; set; } + public Dictionary Headers { get; set; } = new Dictionary(); + public string RequestUrl { get; set; } + public byte[] FormData { get; set; } = default; + public string BodyContentString { get; set; } + public byte[] BodyContentBytes { get; set; } + public CancellationToken CancellationToken { get; set; } = default; + public TimeSpan? Timeout { get; set; } = null; + } +} \ No newline at end of file diff --git a/src/Api/PubnubApi/TransportContract/TransportResponse.cs b/src/Api/PubnubApi/TransportContract/TransportResponse.cs new file mode 100644 index 000000000..ae106ec0b --- /dev/null +++ b/src/Api/PubnubApi/TransportContract/TransportResponse.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace PubnubApi +{ + public class TransportResponse + { + public int StatusCode { get; set; } + public byte[] Content { get; set; } + public Dictionary> Headers { get; set; } + public string RequestUrl { get; set; } + public Exception Error { get; set; } + } +} \ No newline at end of file diff --git a/src/Api/PubnubApiPCL/PubnubApiPCL.csproj b/src/Api/PubnubApiPCL/PubnubApiPCL.csproj index 9c0ac329d..e790e6a4a 100644 --- a/src/Api/PubnubApiPCL/PubnubApiPCL.csproj +++ b/src/Api/PubnubApiPCL/PubnubApiPCL.csproj @@ -1,7 +1,7 @@  - net6.0;netstandard1.3;netstandard1.4;netstandard2.0 + netstandard1.3;netstandard1.4;netstandard2.0;net6.0 latest true True @@ -187,7 +187,6 @@ - EndPoint\TimeOperation.cs @@ -272,6 +271,14 @@ + + + + + + + + HttpUtility\HttpUtility.cs @@ -572,6 +579,9 @@ Proxy\PubnubProxy.cs + + EventListener.cs + Pubnub.cs @@ -597,6 +607,9 @@ Push\Mpns\MpnsToastNotification.cs + + Constants.cs + @@ -605,6 +618,13 @@ + + + + + + + Security\MD5.cs diff --git a/src/Api/PubnubApiUWP/PubnubApiUWP.csproj b/src/Api/PubnubApiUWP/PubnubApiUWP.csproj index 04da2ab34..2ab8ea9d9 100644 --- a/src/Api/PubnubApiUWP/PubnubApiUWP.csproj +++ b/src/Api/PubnubApiUWP/PubnubApiUWP.csproj @@ -302,7 +302,6 @@ - EndPoint\TimeOperation.cs @@ -388,6 +387,14 @@ + + + + + + + + HttpUtility\HttpUtility.cs @@ -621,6 +628,13 @@ + + + + + + + Model\Derived\PNTimeResultExt.cs @@ -691,6 +705,9 @@ Proxy\PubnubProxy.cs + + EventListener.cs + Pubnub.cs @@ -716,6 +733,9 @@ Push\Mpns\MpnsToastNotification.cs + + Constants.cs + Security\Crypto\CryptoModule.cs diff --git a/src/Api/PubnubApiUnity/PubnubApiUnity.csproj b/src/Api/PubnubApiUnity/PubnubApiUnity.csproj index 4ad1d573c..e96a00d5b 100644 --- a/src/Api/PubnubApiUnity/PubnubApiUnity.csproj +++ b/src/Api/PubnubApiUnity/PubnubApiUnity.csproj @@ -213,6 +213,14 @@ + + + + + + + + EndPoint\PubSub\UnsubscribeAllOperation.cs @@ -241,7 +249,6 @@ - EndPoint\TimeOperation.cs @@ -575,6 +582,9 @@ Proxy\PubnubProxy.cs + + EventListener.cs + Pubnub.cs @@ -597,6 +607,9 @@ Push\Mpns\MpnsToastNotification.cs + + Constants.cs + @@ -605,6 +618,13 @@ + + + + + + + Security\MD5.cs diff --git a/src/Examples/PubnubApi.WinFormExample/PubnubApi.WinFormExample.csproj b/src/Examples/PubnubApi.WinFormExample/PubnubApi.WinFormExample.csproj index 4fb3d5cfb..d53cd663a 100644 --- a/src/Examples/PubnubApi.WinFormExample/PubnubApi.WinFormExample.csproj +++ b/src/Examples/PubnubApi.WinFormExample/PubnubApi.WinFormExample.csproj @@ -51,8 +51,9 @@ ..\..\packages\PeterO.Numbers.1.8.2\lib\net40\Numbers.dll - - ..\..\packages\Pubnub.6.3.0\lib\net45\Pubnub.dll + + ..\..\packages\Pubnub.6.20.1\lib\net45\Pubnub.dll + True diff --git a/src/Examples/PubnubApi.WinFormExample/packages.config b/src/Examples/PubnubApi.WinFormExample/packages.config index c70d10d97..1784a9c7d 100644 --- a/src/Examples/PubnubApi.WinFormExample/packages.config +++ b/src/Examples/PubnubApi.WinFormExample/packages.config @@ -7,8 +7,9 @@ - + + diff --git a/src/UnitTests/AcceptanceTests/Steps/EventEngineSteps.cs b/src/UnitTests/AcceptanceTests/Steps/EventEngineSteps.cs index cd87ebdc8..62345b8c6 100644 --- a/src/UnitTests/AcceptanceTests/Steps/EventEngineSteps.cs +++ b/src/UnitTests/AcceptanceTests/Steps/EventEngineSteps.cs @@ -11,6 +11,7 @@ using TechTalk.SpecFlow.Assist; using System.Net.Http; using System.Diagnostics; +using PubnubApi.EventEngine.Subscribe.Common; namespace AcceptanceTests.Steps { @@ -26,17 +27,19 @@ public class EventEngineSteps private readonly ScenarioContext _scenarioContext; private Pubnub pn; private PNConfiguration config = null; - private string channel = "my_channel"; - private string channelGroup = "my_channelgroup"; + private string channel = "test"; + private string channelGroup = "test"; private string publishMsg = "hello_world"; PNPublishResult publishResult = null; SubscribeCallback subscribeCallback = null; + SubscribeCallback statusCallback = null; private PNMessageResult messageResult = null; ManualResetEvent messageReceivedEvent = new ManualResetEvent(false); ManualResetEvent statusReceivedEvent = new ManualResetEvent(false); ManualResetEvent presenceEvent = new ManualResetEvent(false); PNStatus pnStatus = null; PubnubError pnError = null; + SubscriptionSet subscriptionFirstSecond; IPubnubUnitTest unitTest; static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) @@ -242,14 +245,25 @@ public void GivenTheDemoKeysetWithEventEngineEnabled() } else { - config.LogVerbosity = PNLogVerbosity.NONE; - } - config.EnableEventEngine = true; - - messageReceivedEvent = new ManualResetEvent(false); - statusReceivedEvent = new ManualResetEvent(false); - - subscribeCallback = new SubscribeCallbackExt( + config.LogVerbosity = PNLogVerbosity.NONE; + } + config.EnableEventEngine = true; + + messageReceivedEvent = new ManualResetEvent(false); + statusReceivedEvent = new ManualResetEvent(false); + + statusCallback = new SubscribeCallbackExt(delegate (Pubnub pnObj, PNStatus status) { + pnStatus = status; + Console.WriteLine("{0} {1} {2}", pnStatus.Operation, pnStatus.Category, pnStatus.StatusCode); + if (currentContract == "subscribeHandshakeFailure" && pn.PubnubUnitTest.Attempts == 3) { + statusReceivedEvent.Set(); + } + if (pnStatus.Category == PNStatusCategory.PNConnectedCategory) { + statusReceivedEvent.Set(); + } + }); + + subscribeCallback = new SubscribeCallbackExt( delegate (Pubnub pnObj, PNMessageResult pubMsg) { Console.WriteLine($"Message received in listener. {pn.JsonPluggableLibrary.SerializeToJsonString(pubMsg)}"); @@ -276,22 +290,7 @@ public void GivenTheDemoKeysetWithEventEngineEnabled() delegate (Pubnub pnObj, PNFileEventResult fileEvent) { System.Diagnostics.Debug.WriteLine(pn.JsonPluggableLibrary.SerializeToJsonString(fileEvent)); - }, - delegate (Pubnub pnObj, PNStatus status) - { - pnStatus = status; - Console.WriteLine("{0} {1} {2}", pnStatus.Operation, pnStatus.Category, pnStatus.StatusCode); - if (currentContract == "subscribeHandshakeFailure" && pn.PubnubUnitTest.Attempts == 3) - { - statusReceivedEvent.Set(); - } - if (pnStatus.Category == PNStatusCategory.PNConnectedCategory) - { - statusReceivedEvent.Set(); - } - } - ); - + }); } [Given(@"the demo keyset with Presence EE enabled")] @@ -324,7 +323,16 @@ public void GivenTheDemoKeysetWithPresenceEEenabled() messageReceivedEvent = new ManualResetEvent(false); statusReceivedEvent = new ManualResetEvent(false); presenceEvent = new ManualResetEvent(false); - + statusCallback = new SubscribeCallbackExt( + delegate (Pubnub pnObj, PNStatus status) + { + pnStatus = status; + if (pnStatus.Category == PNStatusCategory.PNConnectedCategory) + { + statusReceivedEvent.Set(); + } + } + ); subscribeCallback = new SubscribeCallbackExt( delegate (Pubnub pnObj, PNMessageResult pubMsg) { @@ -336,16 +344,7 @@ public void GivenTheDemoKeysetWithPresenceEEenabled() { Console.WriteLine(pn.JsonPluggableLibrary.SerializeToJsonString(presenceEvnt)); presenceEvent.Set(); - }, - delegate (Pubnub pnObj, PNStatus status) - { - pnStatus = status; - if (pnStatus.Category == PNStatusCategory.PNConnectedCategory) - { - statusReceivedEvent.Set(); - } - } - ); + }); } [Given(@"heartbeatInterval set to '(.*)', timeout set to '(.*)' and suppressLeaveEvents set to '(.*)'")] public void GivenPresenceConfiguration(string heartbeatInterval, string timeout, string suppressLeaveEvents) @@ -365,10 +364,10 @@ public void WhenIJoinChannels(string first, string second, string third) statusReceivedEvent = new ManualResetEvent(false); presenceEvent = new ManualResetEvent(false); - pn.AddListener(subscribeCallback); - pn.Subscribe() - .Channels(new string[] { first, second, third }) - .Execute(); + pn.AddListener(statusCallback); + SubscriptionSet subscriptionSet = pn.SubscriptionSet(new string[] { first, second, third }); + subscriptionSet.AddListener(subscribeCallback); + subscriptionSet.Subscribe(); } [When(@"I join '(.*)', '(.*)', '(.*)' channels with presence")] @@ -382,11 +381,17 @@ public void WhenIJoinChannelsWithPresence(string first, string second, string th statusReceivedEvent = new ManualResetEvent(false); presenceEvent = new ManualResetEvent(false); - pn.AddListener(subscribeCallback); - pn.Subscribe() - .Channels(new string[] { first, second, third }) - .WithPresence() - .Execute(); + pn.AddListener(statusCallback); + + Subscription subscriptionFirst = pn.Channel(first).Subscription(SubscriptionOptions.ReceivePresenceEvents); + Subscription subscriptionSecond = pn.Channel(second).Subscription(SubscriptionOptions.ReceivePresenceEvents); + subscriptionFirstSecond = subscriptionFirst.Add(subscriptionSecond); + SubscriptionSet subscriptionSet = pn.SubscriptionSet(new string[] { third }, new string[] { }, SubscriptionOptions.ReceivePresenceEvents); + + subscriptionSet.Add(subscriptionFirstSecond); + + subscriptionSet.AddListener(subscribeCallback); + subscriptionSet.Subscribe(); } [Then(@"I wait '(.*)' seconds")] @@ -441,11 +446,10 @@ public void WhenISubscribe() messageReceivedEvent = new ManualResetEvent(false); statusReceivedEvent = new ManualResetEvent(false); - pn.AddListener(subscribeCallback); - pn.Subscribe() - .Channels(channel.Split(',')) - .ChannelGroups(channelGroup.Split(',')) - .Execute(); + pn.AddListener(statusCallback); + SubscriptionSet subscription = pn.SubscriptionSet(channel.Split(','), channelGroup.Split(',')); + subscription.AddListener(subscribeCallback); + subscription.Subscribe(); statusReceivedEvent.WaitOne (10*1000); if (pnStatus != null && pnStatus.Category == PNStatusCategory.PNConnectedCategory) { @@ -470,12 +474,10 @@ public void WhenISubscribeWithTimetoken(long p0) messageReceivedEvent = new ManualResetEvent(false); statusReceivedEvent = new ManualResetEvent(false); - pn.AddListener(subscribeCallback); - pn.Subscribe() - .Channels(channel.Split(',')) - .ChannelGroups(channelGroup.Split(',')) - .WithTimetoken(p0) - .Execute(); + pn.AddListener(statusCallback); + SubscriptionSet subscription = pn.SubscriptionSet(channel.Split(','), channelGroup.Split(',')); + subscription.AddListener(subscribeCallback); + subscription.Subscribe(new SubscriptionCursor(p0)); statusReceivedEvent.WaitOne (10*1000); if (pnStatus != null && pnStatus.Category == PNStatusCategory.PNConnectedCategory) { @@ -545,9 +547,7 @@ public void ThenIObserveTheFollowing(Table table) [Then(@"I leave '(.*)' and '(.*)' channels with presence")] public void ThenILeaveAndChannelsWithPresence(string first0, string second1) { - pn.Unsubscribe() - .Channels(new string[] { first0, second1 }) - .Execute(); + subscriptionFirstSecond.Unsubscribe(); } [Given(@"a linear reconnection policy with (.*) retries")]