Skip to content

Commit

Permalink
Extend SendFile to accept byte arrays (#163)
Browse files Browse the repository at this point in the history
* feat: sending files as byte arrays
* Added TcpKeepAlive and ConnectionLimit
  • Loading branch information
MikeDobrzan authored Mar 16, 2023
1 parent 58f410e commit a883481
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 67 deletions.
21 changes: 14 additions & 7 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
3 changes: 3 additions & 0 deletions src/Api/PubnubApi/ClientNetworkStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ private static async Task<bool> 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<HttpWebResponse>(myRequest.BeginGetResponse, asyncPubnubResult => (HttpWebResponse)myRequest.EndGetResponse(asyncPubnubResult), null).ConfigureAwait(false))
{
if (response != null)
Expand Down
30 changes: 27 additions & 3 deletions src/Api/PubnubApi/EndPoint/Files/SendFileOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand All @@ -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;
Expand Down Expand Up @@ -167,7 +191,7 @@ private void ProcessFileUpload(Dictionary<string, object> externalQueryParam, PN

requestState.UsePostMethod = true;

byte[] sendFileByteArray = GetByteArrayFromFilePath(sendFileFullPath);
byte[] sendFileByteArray = sendFileBytes ?? GetByteArrayFromFilePath(sendFileFullPath);


string dataBoundary = String.Format(CultureInfo.InvariantCulture, "----------{0:N}", Guid.NewGuid());
Expand Down Expand Up @@ -269,7 +293,7 @@ private async Task<PNResult<PNFileUploadResult>> ProcessFileUpload(Dictionary<st

requestState.UsePostMethod = true;

byte[] sendFileByteArray = GetByteArrayFromFilePath(sendFileFullPath);
byte[] sendFileByteArray = sendFileBytes ?? GetByteArrayFromFilePath(sendFileFullPath);

string dataBoundary = String.Format(CultureInfo.InvariantCulture, "----------{0:N}", Guid.NewGuid());
string contentType = "multipart/form-data; boundary=" + dataBoundary;
Expand Down
2 changes: 2 additions & 0 deletions src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ private void MultiChannelSubscribeRequest<T>(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 = "";
Expand Down Expand Up @@ -1417,6 +1418,7 @@ void OnPresenceHeartbeatIntervalTimeout<T>(System.Object presenceHeartbeatState)
requestState.PubnubCallback = null;
requestState.Reconnect = false;
requestState.Response = null;
requestState.TimeQueued = DateTime.Now;

UrlProcessRequest(request, requestState, false).ContinueWith(r =>
{
Expand Down
5 changes: 3 additions & 2 deletions src/Api/PubnubApi/Interface/IPubnubHttp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ public interface IPubnubHttp
HttpWebRequest SetTimeout<T>(RequestState<T> pubnubRequestState, HttpWebRequest request);

HttpWebRequest SetNoCache<T>(HttpWebRequest request);

HttpWebRequest SetServicePointSetTcpKeepAlive(HttpWebRequest request);
HttpWebRequest SetServicePointConnectionLimit<T>(RequestState<T> pubnubRequestState, HttpWebRequest request);
HttpWebRequest SetServicePointSetTcpKeepAlive<T>(RequestState<T> pubnubRequestState, HttpWebRequest request);
HttpWebRequest SetTcpKeepAlive(HttpWebRequest request);

Task<string> SendRequestAndGetJsonResponse<T>(Uri requestUri, RequestState<T> pubnubRequestState, HttpWebRequest request);

Expand Down
1 change: 1 addition & 0 deletions src/Api/PubnubApi/Model/RequestState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace PubnubApi
{
public sealed class RequestState<T>
{
public DateTime? TimeQueued { get; internal set; }
public HttpWebRequest Request { get; internal set; }
public HttpWebResponse Response { get; internal set; }
public bool GotJsonResponse { get; internal set; }
Expand Down
4 changes: 2 additions & 2 deletions src/Api/PubnubApi/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 3 additions & 2 deletions src/Api/PubnubApi/PubnubApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@

<PropertyGroup>
<PackageId>Pubnub</PackageId>
<PackageVersion>6.14.0.0</PackageVersion>
<PackageVersion>6.15.0.0</PackageVersion>
<Title>PubNub C# .NET - Web Data Push API</Title>
<Authors>Pandu Masabathula</Authors>
<Owners>PubNub</Owners>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<PackageIconUrl>http://pubnub.s3.amazonaws.com/2011/powered-by-pubnub/pubnub-icon-600x600.png</PackageIconUrl>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RepositoryUrl>https://github.com/pubnub/c-sharp/</RepositoryUrl>
<PackageReleaseNotes>Undeprecated GrantToken methods/properties.</PackageReleaseNotes>
<PackageReleaseNotes>Sending files as raw byte arrays.
Added TcpKeepAlive and ConnectionLimit to improve performance.</PackageReleaseNotes>
<PackageTags>Web Data Push Real-time Notifications ESB Message Broadcasting Distributed Computing</PackageTags>
<!--<Summary>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</Summary>-->
<Description>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</Description>
Expand Down
4 changes: 3 additions & 1 deletion src/Api/PubnubApi/PubnubCoreBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1076,10 +1076,12 @@ internal protected async Task<Tuple<string, PNStatus>> UrlProcessRequest<T>(Uri
#else
// Create Request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);

request = pubnubHttp.SetServicePointConnectionLimit(pubnubRequestState, request);
request = pubnubHttp.SetNoCache<T>(request);
request = pubnubHttp.SetProxy<T>(request);
request = pubnubHttp.SetTimeout<T>(pubnubRequestState, request);
request = pubnubHttp.SetServicePointSetTcpKeepAlive(pubnubRequestState, request);
request = pubnubHttp.SetTcpKeepAlive(request);
if (string.IsNullOrEmpty(contentType))
{
contentType = "application/json";
Expand Down
90 changes: 62 additions & 28 deletions src/Api/PubnubApi/PubnubHttp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,37 @@ HttpWebRequest IPubnubHttp.SetNoCache<T>(HttpWebRequest request)
return request;
}

HttpWebRequest IPubnubHttp.SetServicePointConnectionLimit<T>(RequestState<T> 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<T>(RequestState<T> 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;
}

Expand Down Expand Up @@ -559,40 +586,47 @@ async Task<string> SendRequestAndGetJsonResponseTaskFactory<T>(RequestState<T> p
try
{
request.Method = FindHttpGetOrDeleteMethod(pubnubRequestState);
var _ = new Timer(OnPubnubWebRequestTimeout<T>, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite);
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
var _ = new Timer(OnPubnubWebRequestTimeout<T>, pubnubRequestState, GetTimeoutInSecondsForResponseType(pubnubRequestState.ResponseType) * 1000, Timeout.Infinite);
response = await Task.Factory.FromAsync<HttpWebResponse>(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)
Expand Down Expand Up @@ -1311,14 +1345,14 @@ protected void OnPubnubWebRequestTimeout<T>(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
Expand Down
5 changes: 3 additions & 2 deletions src/Api/PubnubApiPCL/PubnubApiPCL.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@

<PropertyGroup>
<PackageId>PubnubPCL</PackageId>
<PackageVersion>6.14.0.0</PackageVersion>
<PackageVersion>6.15.0.0</PackageVersion>
<Title>PubNub C# .NET - Web Data Push API</Title>
<Authors>Pandu Masabathula</Authors>
<Owners>PubNub</Owners>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<PackageIconUrl>http://pubnub.s3.amazonaws.com/2011/powered-by-pubnub/pubnub-icon-600x600.png</PackageIconUrl>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RepositoryUrl>https://github.com/pubnub/c-sharp/</RepositoryUrl>
<PackageReleaseNotes>Undeprecated GrantToken methods/properties.</PackageReleaseNotes>
<PackageReleaseNotes>Sending files as raw byte arrays.
Added TcpKeepAlive and ConnectionLimit to improve performance.</PackageReleaseNotes>
<PackageTags>Web Data Push Real-time Notifications ESB Message Broadcasting Distributed Computing</PackageTags>
<!--<Summary>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</Summary>-->
<Description>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</Description>
Expand Down
Loading

0 comments on commit a883481

Please sign in to comment.