diff --git a/.pubnub.yml b/.pubnub.yml index f1758e58f..c16b1646e 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,8 +1,15 @@ name: c-sharp -version: "6.14.0" +version: "6.15.0" schema: 1 scm: github.com/pubnub/c-sharp changelog: + - date: 2023-03-16 + version: v6.15.0 + changes: + - type: feature + text: "Sending files as raw byte arrays." + - type: improvement + text: "Added TcpKeepAlive and ConnectionLimit to improve performance." - date: 2023-02-27 version: v6.14.0 changes: @@ -706,7 +713,7 @@ features: - QUERY-PARAM supported-platforms: - - version: Pubnub 'C#' 6.14.0 + version: Pubnub 'C#' 6.15.0 platforms: - Windows 10 and up - Windows Server 2008 and up @@ -716,7 +723,7 @@ supported-platforms: - .Net Framework 4.5 - .Net Framework 4.6.1+ - - version: PubnubPCL 'C#' 6.14.0 + version: PubnubPCL 'C#' 6.15.0 platforms: - Xamarin.Android - Xamarin.iOS @@ -736,7 +743,7 @@ supported-platforms: - .Net Core - .Net 6.0 - - version: PubnubUWP 'C#' 6.14.0 + version: PubnubUWP 'C#' 6.15.0 platforms: - Windows Phone 10 - Universal Windows Apps @@ -760,7 +767,7 @@ sdks: distribution-type: source distribution-repository: GitHub package-name: Pubnub - location: https://github.com/pubnub/c-sharp/releases/tag/v6.14.0.0 + location: https://github.com/pubnub/c-sharp/releases/tag/v6.15.0.0 requires: - name: ".Net" @@ -1043,7 +1050,7 @@ sdks: distribution-type: source distribution-repository: GitHub package-name: PubNubPCL - location: https://github.com/pubnub/c-sharp/releases/tag/v6.14.0.0 + location: https://github.com/pubnub/c-sharp/releases/tag/v6.15.0.0 requires: - name: ".Net Core" @@ -1402,7 +1409,7 @@ sdks: distribution-type: source distribution-repository: GitHub package-name: PubnubUWP - location: https://github.com/pubnub/c-sharp/releases/tag/v6.14.0.0 + location: https://github.com/pubnub/c-sharp/releases/tag/v6.15.0.0 requires: - name: "Universal Windows Platform Development" diff --git a/CHANGELOG b/CHANGELOG index 9318e023d..17489de74 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +v6.15.0 - March 16 2023 +----------------------------- +- Added: sending files as raw byte arrays. + +- Modified: added TcpKeepAlive and ConnectionLimit to improve performance. + v6.14.0 - February 27 2023 ----------------------------- - Modified: undeprecated GrantToken methods/properties. diff --git a/src/Api/PubnubApi/ClientNetworkStatus.cs b/src/Api/PubnubApi/ClientNetworkStatus.cs index 99801f902..15bcc07a7 100644 --- a/src/Api/PubnubApi/ClientNetworkStatus.cs +++ b/src/Api/PubnubApi/ClientNetworkStatus.cs @@ -303,6 +303,9 @@ private static async Task GetTimeWithTaskFactoryAsync(Uri requestUri) 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) diff --git a/src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs b/src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs index 1ca0157b1..05a6c3ba6 100644 --- a/src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs +++ b/src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs @@ -25,6 +25,7 @@ public class SendFileOperation : PubnubCoreBase private object publishMessage; private string sendFileFullPath; private string sendFileName = ""; + private byte[] sendFileBytes = null; private string currentFileCipherKey; private string currentFileId; private bool storeInHistory = true; @@ -90,7 +91,8 @@ public SendFileOperation File(string fileNameWithFullPath) { this.sendFileFullPath = fileNameWithFullPath; #if !NETSTANDARD10 && !NETSTANDARD11 - if (System.IO.File.Exists(fileNameWithFullPath)) + // manually set filename should take precedence + if (System.IO.File.Exists(fileNameWithFullPath) && string.IsNullOrEmpty(sendFileName)) { sendFileName = System.IO.Path.GetFileName(fileNameWithFullPath); } @@ -100,6 +102,28 @@ public SendFileOperation File(string fileNameWithFullPath) #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; @@ -167,7 +191,7 @@ private void ProcessFileUpload(Dictionary externalQueryParam, PN requestState.UsePostMethod = true; - byte[] sendFileByteArray = GetByteArrayFromFilePath(sendFileFullPath); + byte[] sendFileByteArray = sendFileBytes ?? GetByteArrayFromFilePath(sendFileFullPath); string dataBoundary = String.Format(CultureInfo.InvariantCulture, "----------{0:N}", Guid.NewGuid()); @@ -269,7 +293,7 @@ private async Task> ProcessFileUpload(Dictionary(PNOperationType type, string[] chan pubnubRequestState.Reconnect = reconnect; pubnubRequestState.Timetoken = Convert.ToInt64(timetoken.ToString(), CultureInfo.InvariantCulture); pubnubRequestState.Region = region; + pubnubRequestState.TimeQueued = DateTime.Now; // Wait for message string json = ""; @@ -1417,6 +1418,7 @@ void OnPresenceHeartbeatIntervalTimeout(System.Object presenceHeartbeatState) requestState.PubnubCallback = null; requestState.Reconnect = false; requestState.Response = null; + requestState.TimeQueued = DateTime.Now; UrlProcessRequest(request, requestState, false).ContinueWith(r => { diff --git a/src/Api/PubnubApi/Interface/IPubnubHttp.cs b/src/Api/PubnubApi/Interface/IPubnubHttp.cs index 580dd10a6..7358956be 100644 --- a/src/Api/PubnubApi/Interface/IPubnubHttp.cs +++ b/src/Api/PubnubApi/Interface/IPubnubHttp.cs @@ -11,8 +11,9 @@ public interface IPubnubHttp HttpWebRequest SetTimeout(RequestState pubnubRequestState, HttpWebRequest request); HttpWebRequest SetNoCache(HttpWebRequest request); - - HttpWebRequest SetServicePointSetTcpKeepAlive(HttpWebRequest request); + HttpWebRequest SetServicePointConnectionLimit(RequestState pubnubRequestState, HttpWebRequest request); + HttpWebRequest SetServicePointSetTcpKeepAlive(RequestState pubnubRequestState, HttpWebRequest request); + HttpWebRequest SetTcpKeepAlive(HttpWebRequest request); Task SendRequestAndGetJsonResponse(Uri requestUri, RequestState pubnubRequestState, HttpWebRequest request); diff --git a/src/Api/PubnubApi/Model/RequestState.cs b/src/Api/PubnubApi/Model/RequestState.cs index d3a0214a5..cfb8d3014 100644 --- a/src/Api/PubnubApi/Model/RequestState.cs +++ b/src/Api/PubnubApi/Model/RequestState.cs @@ -5,6 +5,7 @@ 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 bool GotJsonResponse { get; internal set; } diff --git a/src/Api/PubnubApi/Properties/AssemblyInfo.cs b/src/Api/PubnubApi/Properties/AssemblyInfo.cs index fcd5627b7..7543a3920 100644 --- a/src/Api/PubnubApi/Properties/AssemblyInfo.cs +++ b/src/Api/PubnubApi/Properties/AssemblyInfo.cs @@ -11,8 +11,8 @@ [assembly: AssemblyProduct("Pubnub C# SDK")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("6.14.0.0")] -[assembly: AssemblyFileVersion("6.14.0.0")] +[assembly: AssemblyVersion("6.15.0.0")] +[assembly: AssemblyFileVersion("6.15.0.0")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. diff --git a/src/Api/PubnubApi/PubnubApi.csproj b/src/Api/PubnubApi/PubnubApi.csproj index 21ab79d48..598646bc3 100644 --- a/src/Api/PubnubApi/PubnubApi.csproj +++ b/src/Api/PubnubApi/PubnubApi.csproj @@ -13,7 +13,7 @@ Pubnub - 6.14.0.0 + 6.15.0.0 PubNub C# .NET - Web Data Push API Pandu Masabathula PubNub @@ -21,7 +21,8 @@ http://pubnub.s3.amazonaws.com/2011/powered-by-pubnub/pubnub-icon-600x600.png true https://github.com/pubnub/c-sharp/ - Undeprecated GrantToken methods/properties. + Sending files as raw byte arrays. +Added TcpKeepAlive and ConnectionLimit to improve performance. Web Data Push Real-time Notifications ESB Message Broadcasting Distributed Computing PubNub is a Massively Scalable Web Push Service for Web and Mobile Games. This is a cloud-based service for broadcasting messages to thousands of web and mobile clients simultaneously diff --git a/src/Api/PubnubApi/PubnubCoreBase.cs b/src/Api/PubnubApi/PubnubCoreBase.cs index e61a51598..0b818f936 100644 --- a/src/Api/PubnubApi/PubnubCoreBase.cs +++ b/src/Api/PubnubApi/PubnubCoreBase.cs @@ -1076,10 +1076,12 @@ internal protected async Task> UrlProcessRequest(Uri #else // Create Request HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri); - + request = pubnubHttp.SetServicePointConnectionLimit(pubnubRequestState, request); request = pubnubHttp.SetNoCache(request); request = pubnubHttp.SetProxy(request); request = pubnubHttp.SetTimeout(pubnubRequestState, request); + request = pubnubHttp.SetServicePointSetTcpKeepAlive(pubnubRequestState, request); + request = pubnubHttp.SetTcpKeepAlive(request); if (string.IsNullOrEmpty(contentType)) { contentType = "application/json"; diff --git a/src/Api/PubnubApi/PubnubHttp.cs b/src/Api/PubnubApi/PubnubHttp.cs index 1935a6cb2..4f0d7aeb5 100644 --- a/src/Api/PubnubApi/PubnubHttp.cs +++ b/src/Api/PubnubApi/PubnubHttp.cs @@ -69,10 +69,37 @@ HttpWebRequest IPubnubHttp.SetNoCache(HttpWebRequest request) 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.SetServicePointSetTcpKeepAlive(HttpWebRequest request) + HttpWebRequest IPubnubHttp.SetTcpKeepAlive(HttpWebRequest request) { - //do nothing +#if NET35 || NET40 || NET45 || NET461 || NET48 + request.KeepAlive = true; +#endif return request; } @@ -559,40 +586,47 @@ async Task SendRequestAndGetJsonResponseTaskFactory(RequestState p 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(); + 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); } - 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}, Retrieved JSON", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - - if (pubnubRequestState.Response != null) + 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())) { -#if NET35 || NET40 || NET45 || NET461 || NET48 - pubnubRequestState.Response.Close(); -#endif - pubnubRequestState.Response = null; - pubnubRequestState.Request = null; - } + //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}, Retrieved JSON", DateTime.Now.ToString(CultureInfo.InvariantCulture))); - return jsonString; + 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) @@ -1311,14 +1345,14 @@ protected void OnPubnubWebRequestTimeout(System.Object 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 */ } - LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, **WP7 OnPubnubWebRequestTimeout**", DateTime.Now.ToString(CultureInfo.InvariantCulture)), pubnubConfig.LogVerbosity); - if (currentState.ResponseType != PNOperationType.PNSubscribeOperation && currentState.ResponseType != PNOperationType.Presence && currentState.ResponseType != PNOperationType.PNHeartbeatOperation diff --git a/src/Api/PubnubApiPCL/PubnubApiPCL.csproj b/src/Api/PubnubApiPCL/PubnubApiPCL.csproj index b004a70df..8330aaa89 100644 --- a/src/Api/PubnubApiPCL/PubnubApiPCL.csproj +++ b/src/Api/PubnubApiPCL/PubnubApiPCL.csproj @@ -14,7 +14,7 @@ PubnubPCL - 6.14.0.0 + 6.15.0.0 PubNub C# .NET - Web Data Push API Pandu Masabathula PubNub @@ -22,7 +22,8 @@ http://pubnub.s3.amazonaws.com/2011/powered-by-pubnub/pubnub-icon-600x600.png true https://github.com/pubnub/c-sharp/ - Undeprecated GrantToken methods/properties. + Sending files as raw byte arrays. +Added TcpKeepAlive and ConnectionLimit to improve performance. Web Data Push Real-time Notifications ESB Message Broadcasting Distributed Computing PubNub is a Massively Scalable Web Push Service for Web and Mobile Games. This is a cloud-based service for broadcasting messages to thousands of web and mobile clients simultaneously diff --git a/src/Api/PubnubApiUWP/PubnubApiUWP.csproj b/src/Api/PubnubApiUWP/PubnubApiUWP.csproj index 0a104da24..545a8d30a 100644 --- a/src/Api/PubnubApiUWP/PubnubApiUWP.csproj +++ b/src/Api/PubnubApiUWP/PubnubApiUWP.csproj @@ -15,7 +15,7 @@ PubnubUWP - 6.14.0.0 + 6.15.0.0 PubNub C# .NET - Web Data Push API Pandu Masabathula PubNub @@ -23,7 +23,8 @@ http://pubnub.s3.amazonaws.com/2011/powered-by-pubnub/pubnub-icon-600x600.png true https://github.com/pubnub/c-sharp/ - Undeprecated GrantToken methods/properties. + Sending files as raw byte arrays. +Added TcpKeepAlive and ConnectionLimit to improve performance. Web Data Push Real-time Notifications ESB Message Broadcasting Distributed Computing PubNub is a Massively Scalable Web Push Service for Web and Mobile Games. This is a cloud-based service for broadcasting messages to thousands of web and mobile clients simultaneously diff --git a/src/UnitTests/AcceptanceTests/AcceptanceTests.csproj b/src/UnitTests/AcceptanceTests/AcceptanceTests.csproj index 88b19f749..b5169b946 100644 --- a/src/UnitTests/AcceptanceTests/AcceptanceTests.csproj +++ b/src/UnitTests/AcceptanceTests/AcceptanceTests.csproj @@ -18,7 +18,7 @@ - + diff --git a/src/UnitTests/PubnubApi.Tests/WhenFileIsRequested.cs b/src/UnitTests/PubnubApi.Tests/WhenFileIsRequested.cs index 27cdb6704..0e27c2d4a 100644 --- a/src/UnitTests/PubnubApi.Tests/WhenFileIsRequested.cs +++ b/src/UnitTests/PubnubApi.Tests/WhenFileIsRequested.cs @@ -53,9 +53,6 @@ public static void Init() pubnub = createPubNubInstance(config); - string expected = "{\"message\":\"Success\",\"payload\":{\"level\":\"channel-group\",\"subscribe_key\":\"demo-36\",\"ttl\":20,\"channel-groups\":{\"hello_my_group\":{\"r\":1,\"w\":0,\"m\":1}}},\"service\":\"Access Manager\",\"status\":200}"; - - pubnub.Grant().Channels(new[] { channelName }).AuthKeys(new[] { authKey }).Read(true).Write(true).Manage(true).Delete(true).Update(true).Get(true).TTL(20) .Execute(new PNAccessManagerGrantResultExt((r,s)=> { @@ -123,8 +120,6 @@ public static void ThenSendFileShouldReturnSuccess() pubnub.Subscribe().Channels(new string[] { channelName }).Execute(); mre.WaitOne(2000); - string expected = "{\"status\": 200, \"message\": \"OK\", \"service\": \"channel-registry\", \"error\": false}"; - mre = new ManualResetEvent(false); string fileId = ""; @@ -255,8 +250,6 @@ public static async Task ThenWithAsyncSendFileShouldReturnSuccess() pubnub.Subscribe().Channels(new string[] { channelName }).Execute(); mre.WaitOne(2000); - string expected = "{\"status\": 200, \"message\": \"OK\", \"service\": \"channel-registry\", \"error\": false}"; - mre = new ManualResetEvent(false); string fileId = ""; @@ -360,8 +353,6 @@ public static void ThenDownloadFileShouldReturnSuccess() } pubnub = createPubNubInstance(config); - string expected = ""; - mre = new ManualResetEvent(false); string fileId = "b0a5c0df-7523-432e-8ea9-01567c93da7d"; string fileName = "pandu_test.gif"; @@ -411,8 +402,6 @@ public static void ThenGetFileUrlShouldReturnSuccess() } pubnub = createPubNubInstance(config); - string expected = ""; - mre = new ManualResetEvent(false); string fileId = "bc03db55-6345-4a0f-aa58-beac970b2c5b"; string fileName = "whoami.txt"; @@ -462,8 +451,6 @@ public static void ThenListFilesShouldReturnSuccess() } pubnub = createPubNubInstance(config); - string expected = ""; - receivedMessage = false; mre = new ManualResetEvent(false); pubnub.ListFiles().Channel(channelName) @@ -511,8 +498,6 @@ public static void ThenDeleteFileShouldReturnSuccess() } pubnub = createPubNubInstance(config); - string expected = ""; - receivedMessage = false; PNResult listFilesResponse = pubnub.ListFiles().Channel(channelName).ExecuteAsync().Result; if (listFilesResponse.Result != null && listFilesResponse.Result.FilesList != null && listFilesResponse.Result.FilesList.Count > 0 && !listFilesResponse.Status.Error) @@ -591,8 +576,6 @@ public static async Task ThenWithAsyncDeleteFileShouldReturnSuccess() } pubnub = createPubNubInstance(config); - string expected = ""; - receivedMessage = false; #if NET40 PNResult listFilesResponse = Task.Factory.StartNew(async () => await pubnub.ListFiles().Channel(channelName).ExecuteAsync()).Result.Result;