Skip to content

Commit 0745920

Browse files
authored
Merge pull request #1 from Arlodotexe/fix/pubsub-fixups
Updated PubSub to align with 0.11.0
2 parents 6b38ef0 + eec74ba commit 0745920

File tree

4 files changed

+106
-61
lines changed

4 files changed

+106
-61
lines changed

src/CoreApi/PubSubApi.cs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Threading;
1010
using System.Threading.Tasks;
1111
using Ipfs.CoreApi;
12+
using Multiformats.Base;
1213

1314
namespace Ipfs.Http
1415
{
@@ -46,44 +47,45 @@ internal PubSubApi(IpfsClient ipfs)
4647
{
4748
var url = new StringBuilder();
4849
url.Append("/api/v0/pubsub/pub");
49-
url.Append("?arg=");
50-
url.Append(System.Net.WebUtility.UrlEncode(topic));
51-
url.Append("&arg=");
52-
var data = Encoding.ASCII.GetString(System.Net.WebUtility.UrlEncodeToBytes(message, 0, message.Length));
53-
url.Append(data);
54-
return ipfs.DoCommandAsync(new Uri(ipfs.ApiUri, url.ToString()), cancel);
50+
url.Append("?arg=u");
51+
url.Append(Multibase.Encode(MultibaseEncoding.Base64Url, Encoding.UTF8.GetBytes(topic)));
52+
53+
return ipfs.DoCommandAsync(new Uri(ipfs.ApiUri, url.ToString()), message, cancel);
5554
}
5655

5756
public Task PublishAsync(string topic, Stream message, CancellationToken cancel = default(CancellationToken))
5857
{
59-
using (MemoryStream ms = new MemoryStream())
60-
{
61-
message.CopyTo(ms);
62-
return PublishAsync(topic, ms.ToArray(), cancel);
63-
}
58+
var url = new StringBuilder();
59+
url.Append("/api/v0/pubsub/pub");
60+
url.Append("?arg=u");
61+
url.Append(Multibase.Encode(MultibaseEncoding.Base64Url, Encoding.UTF8.GetBytes(topic)));
62+
63+
return ipfs.DoCommandAsync(new Uri(ipfs.ApiUri, url.ToString()), message, cancel);
6464
}
6565

66-
public async Task PublishAsync(string topic, string message, CancellationToken cancel = default(CancellationToken))
66+
public Task PublishAsync(string topic, string message, CancellationToken cancel = default(CancellationToken))
6767
{
68-
var _ = await ipfs.DoCommandAsync("pubsub/pub", cancel, topic, "arg=" + message);
69-
return;
68+
var url = new StringBuilder();
69+
url.Append("/api/v0/pubsub/pub");
70+
url.Append("?arg=u");
71+
url.Append(Multibase.Encode(MultibaseEncoding.Base64Url, Encoding.UTF8.GetBytes(topic)));
72+
73+
return ipfs.DoCommandAsync(new Uri(ipfs.ApiUri, url.ToString()), message, cancel);
7074
}
7175

7276
public async Task SubscribeAsync(string topic, Action<IPublishedMessage> handler, CancellationToken cancellationToken)
7377
{
74-
var messageStream = await ipfs.PostDownloadAsync("pubsub/sub", cancellationToken, topic);
78+
var messageStream = await ipfs.PostDownloadAsync("pubsub/sub", cancellationToken, $"u{Multibase.Encode(MultibaseEncoding.Base64Url, Encoding.UTF8.GetBytes(topic))}");
7579
var sr = new StreamReader(messageStream);
7680

77-
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
78-
Task.Run(() => ProcessMessages(topic, handler, sr, cancellationToken));
79-
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
81+
_ = Task.Run(() => ProcessMessages(topic, handler, sr, cancellationToken));
8082

8183
return;
8284
}
8385

8486
void ProcessMessages(string topic, Action<PublishedMessage> handler, StreamReader sr, CancellationToken ct)
8587
{
86-
log.DebugFormat("Start listening for '{0}' messages", topic);
88+
log.DebugFormat($"Start listening for '{topic}' messages");
8789

8890
// .Net needs a ReadLine(CancellationToken)
8991
// As a work-around, we register a function to close the stream
@@ -95,6 +97,7 @@ void ProcessMessages(string topic, Action<PublishedMessage> handler, StreamReade
9597
var json = sr.ReadLine();
9698
if (json == null)
9799
break;
100+
98101
if (log.IsDebugEnabled)
99102
log.DebugFormat("PubSub message {0}", json);
100103

src/IpfsClient.cs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public partial class IpfsClient : ICoreApi
4545
/// The environment variable "IpfsHttpApi" overrides this value.
4646
/// </remarks>
4747
public static Uri DefaultApiUri = new Uri(
48-
Environment.GetEnvironmentVariable("IpfsHttpApi")
48+
Environment.GetEnvironmentVariable("IpfsHttpApi")
4949
?? "http://localhost:5001");
5050

5151
/// <summary>
@@ -95,7 +95,7 @@ public IpfsClient(string host)
9595
{
9696
ApiUri = new Uri(host);
9797
}
98-
98+
9999
/// <summary>
100100
/// The URL to the IPFS API server. The default is "http://localhost:5001".
101101
/// </summary>
@@ -230,7 +230,7 @@ HttpClient Api()
230230
}
231231
api = new HttpClient(handler)
232232
{
233-
Timeout = System.Threading.Timeout.InfiniteTimeSpan
233+
Timeout = Timeout.InfiniteTimeSpan
234234
};
235235
api.DefaultRequestHeaders.Add("User-Agent", UserAgent);
236236
}
@@ -276,16 +276,41 @@ public async Task<string> DoCommandAsync(string command, CancellationToken cance
276276
}
277277
}
278278

279-
internal async Task DoCommandAsync(Uri url, CancellationToken cancel)
279+
internal Task DoCommandAsync(Uri url, CancellationToken cancel)
280+
{
281+
return DoCommandAsync(url, (HttpContent)null, cancel);
282+
}
283+
284+
internal Task DoCommandAsync(Uri url, byte[] bytes, CancellationToken cancel)
285+
{
286+
return DoCommandAsync(url, new ByteArrayContent(bytes), cancel);
287+
}
288+
289+
internal Task DoCommandAsync(Uri url, Stream stream, CancellationToken cancel)
290+
{
291+
return DoCommandAsync(url, new StreamContent(stream), cancel);
292+
}
293+
294+
internal Task DoCommandAsync(Uri url, string str, CancellationToken cancel)
295+
{
296+
return DoCommandAsync(url, new StringContent(str), cancel);
297+
}
298+
299+
internal async Task DoCommandAsync(Uri url, HttpContent content, CancellationToken cancel)
280300
{
281301
if (log.IsDebugEnabled)
282302
log.Debug("POST " + url.ToString());
283-
using (var response = await Api().PostAsync(url, null, cancel))
303+
304+
using (var response = await Api().PostAsync(url, new MultipartFormDataContent
305+
{
306+
{content, "\"file\""}
307+
}, cancel))
284308
{
285309
await ThrowOnErrorAsync(response);
286310
var body = await response.Content.ReadAsStringAsync();
287311
if (log.IsDebugEnabled)
288312
log.Debug("RSP " + body);
313+
289314
return;
290315
}
291316
}
@@ -354,9 +379,10 @@ public async Task<Stream> PostDownloadAsync(string command, CancellationToken ca
354379
var url = BuildCommand(command, arg, options);
355380
if (log.IsDebugEnabled)
356381
log.Debug("POST " + url.ToString());
357-
var request = new HttpRequestMessage(HttpMethod.Post, url);
358382

383+
var request = new HttpRequestMessage(HttpMethod.Post, url);
359384
var response = await Api().SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancel);
385+
360386
await ThrowOnErrorAsync(response);
361387
return await response.Content.ReadAsStreamAsync();
362388
}
@@ -389,6 +415,7 @@ public async Task<Stream> DownloadAsync(string command, CancellationToken cancel
389415
var url = BuildCommand(command, arg, options);
390416
if (log.IsDebugEnabled)
391417
log.Debug("GET " + url.ToString());
418+
392419
var response = await Api().GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancel);
393420
await ThrowOnErrorAsync(response);
394421
return await response.Content.ReadAsStreamAsync();
@@ -422,6 +449,7 @@ public async Task<byte[]> DownloadBytesAsync(string command, CancellationToken c
422449
var url = BuildCommand(command, arg, options);
423450
if (log.IsDebugEnabled)
424451
log.Debug("GET " + url.ToString());
452+
425453
var response = await Api().GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancel);
426454
await ThrowOnErrorAsync(response);
427455
return await response.Content.ReadAsByteArrayAsync();
@@ -460,6 +488,7 @@ public async Task<String> UploadAsync(string command, CancellationToken cancel,
460488
var content = new MultipartFormDataContent();
461489
var streamContent = new StreamContent(data);
462490
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
491+
463492
if (string.IsNullOrEmpty(name))
464493
content.Add(streamContent, "file", unknownFilename);
465494
else
@@ -468,12 +497,14 @@ public async Task<String> UploadAsync(string command, CancellationToken cancel,
468497
var url = BuildCommand(command, null, options);
469498
if (log.IsDebugEnabled)
470499
log.Debug("POST " + url.ToString());
500+
471501
using (var response = await Api().PostAsync(url, content, cancel))
472502
{
473503
await ThrowOnErrorAsync(response);
474504
var json = await response.Content.ReadAsStringAsync();
475505
if (log.IsDebugEnabled)
476506
log.Debug("RSP " + json);
507+
477508
return json;
478509
}
479510
}
@@ -510,6 +541,7 @@ public async Task<Stream> Upload2Async(string command, CancellationToken cancel,
510541
var content = new MultipartFormDataContent();
511542
var streamContent = new StreamContent(data);
512543
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
544+
513545
if (string.IsNullOrEmpty(name))
514546
content.Add(streamContent, "file", unknownFilename);
515547
else
@@ -518,6 +550,7 @@ public async Task<Stream> Upload2Async(string command, CancellationToken cancel,
518550
var url = BuildCommand(command, null, options);
519551
if (log.IsDebugEnabled)
520552
log.Debug("POST " + url.ToString());
553+
521554
var response = await Api().PostAsync(url, content, cancel);
522555
await ThrowOnErrorAsync(response);
523556
return await response.Content.ReadAsStreamAsync();
@@ -536,12 +569,14 @@ public async Task<String> UploadAsync(string command, CancellationToken cancel,
536569
var url = BuildCommand(command, null, options);
537570
if (log.IsDebugEnabled)
538571
log.Debug("POST " + url.ToString());
572+
539573
using (var response = await Api().PostAsync(url, content, cancel))
540574
{
541575
await ThrowOnErrorAsync(response);
542576
var json = await response.Content.ReadAsStringAsync();
543577
if (log.IsDebugEnabled)
544578
log.Debug("RSP " + json);
579+
545580
return json;
546581
}
547582
}
@@ -561,17 +596,20 @@ async Task<bool> ThrowOnErrorAsync(HttpResponseMessage response)
561596
{
562597
if (response.IsSuccessStatusCode)
563598
return true;
599+
564600
if (response.StatusCode == HttpStatusCode.NotFound)
565601
{
566602
var error = "Invalid IPFS command: " + response.RequestMessage.RequestUri.ToString();
567603
if (log.IsDebugEnabled)
568604
log.Debug("ERR " + error);
605+
569606
throw new HttpRequestException(error);
570607
}
571608

572609
var body = await response.Content.ReadAsStringAsync();
573610
if (log.IsDebugEnabled)
574611
log.Debug("ERR " + body);
612+
575613
string message = body;
576614
try
577615
{

src/IpfsHttpClient.csproj

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3-
<PropertyGroup>
4-
<TargetFrameworks>netstandard14;netstandard2;net45</TargetFrameworks>
5-
<AssemblyName>Ipfs.Http.Client</AssemblyName>
6-
<RootNamespace>Ipfs.Http</RootNamespace>
7-
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
8-
<DebugType>full</DebugType>
9-
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
3+
<PropertyGroup>
4+
<TargetFrameworks>netstandard2;</TargetFrameworks>
5+
<AssemblyName>Ipfs.Http.Client</AssemblyName>
6+
<RootNamespace>Ipfs.Http</RootNamespace>
7+
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
8+
<DebugType>full</DebugType>
9+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
1010

11-
<!-- developer build is always 0.42 -->
12-
<AssemblyVersion>0.42</AssemblyVersion>
13-
<Version>0.42</Version>
14-
15-
<!-- Nuget specs -->
16-
<PackageId>Ipfs.Http.Client</PackageId>
17-
<Authors>Richard Schneider</Authors>
18-
<Title>IPFS HTTP Client</Title>
19-
<Description> Provides .Net client access to the InterPlanetary File System.</Description>
20-
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
21-
<PackageReleaseNotes>https://github.com/richardschneider/net-ipfs-http-client/releases</PackageReleaseNotes>
22-
<Copyright>© 2015-2019 Richard Schneider</Copyright>
23-
<PackageTags>ipfs peer-to-peer distributed file-system</PackageTags>
24-
<IncludeSymbols>True</IncludeSymbols>
25-
<PackageProjectUrl>https://github.com/richardschneider/net-ipfs-http-client</PackageProjectUrl>
26-
<PackageIconUrl>https://raw.githubusercontent.com/richardschneider/net-ipfs-core/master/doc/images/ipfs-cs-logo-64x64.png</PackageIconUrl>
27-
</PropertyGroup>
11+
<!-- developer build is always 0.42 -->
12+
<AssemblyVersion>0.42</AssemblyVersion>
13+
<Version>0.42</Version>
14+
15+
<!-- Nuget specs -->
16+
<PackageId>Ipfs.Http.Client</PackageId>
17+
<Authors>Richard Schneider</Authors>
18+
<Title>IPFS HTTP Client</Title>
19+
<Description> Provides .Net client access to the InterPlanetary File System.</Description>
20+
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
21+
<PackageReleaseNotes>https://github.com/richardschneider/net-ipfs-http-client/releases</PackageReleaseNotes>
22+
<Copyright>© 2015-2019 Richard Schneider</Copyright>
23+
<PackageTags>ipfs peer-to-peer distributed file-system</PackageTags>
24+
<IncludeSymbols>True</IncludeSymbols>
25+
<PackageProjectUrl>https://github.com/richardschneider/net-ipfs-http-client</PackageProjectUrl>
26+
<PackageIconUrl>https://raw.githubusercontent.com/richardschneider/net-ipfs-core/master/doc/images/ipfs-cs-logo-64x64.png</PackageIconUrl>
27+
</PropertyGroup>
28+
29+
<ItemGroup>
30+
<PackageReference Include="Ipfs.Core" Version="0.55.0" />
31+
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
32+
<PackageReference Include="System.Net.Http" Version="4.3.3" Condition="'$(TargetFramework)' == 'netstandard14'" />
33+
<PackageReference Include="System.Net.Http" Version="4.3.3" Condition="'$(TargetFramework)' == 'net45'" />
34+
<PackageReference Include="Multiformats.Base" Version="2.0.2"/>
35+
</ItemGroup>
2836

29-
<ItemGroup>
30-
<PackageReference Include="Ipfs.Core" Version="0.55.0" />
31-
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
32-
<PackageReference Include="System.Net.Http" Version="4.3.3" Condition="'$(TargetFramework)' == 'netstandard14'" />
33-
<PackageReference Include="System.Net.Http" Version="4.3.3" Condition="'$(TargetFramework)' == 'net45'" />
34-
</ItemGroup>
35-
3637
</Project>

src/PublishedMessage.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
using System.IO;
66
using System.Text;
77
using System.Runtime.Serialization;
8+
using Multiformats.Base;
89

910
namespace Ipfs.Http
1011
{
1112
/// <summary>
1213
/// A published message.
1314
/// </summary>
1415
/// <remarks>
15-
/// The <see cref="PubSubApi"/> is used to publish and subsribe to a message.
16+
/// The <see cref="PubSubApi"/> is used to publish and subscribe to a message.
1617
/// </remarks>
1718
[DataContract]
1819
public class PublishedMessage : IPublishedMessage
@@ -27,11 +28,13 @@ public class PublishedMessage : IPublishedMessage
2728
public PublishedMessage(string json)
2829
{
2930
var o = JObject.Parse(json);
30-
this.Sender = Convert.FromBase64String((string)o["from"]).ToBase58();
31-
this.SequenceNumber = Convert.FromBase64String((string)o["seqno"]);
32-
this.DataBytes = Convert.FromBase64String((string)o["data"]);
31+
32+
this.Sender = (string)o["from"];
33+
this.SequenceNumber = Multibase.Decode((string)o["seqno"], out MultibaseEncoding _);
34+
this.DataBytes = Multibase.Decode((string)o["data"], out MultibaseEncoding _);
35+
3336
var topics = (JArray) (o["topicIDs"]);
34-
this.Topics = topics.Select(t => (string)t);
37+
this.Topics = topics.Select(t => Encoding.UTF8.GetString(Multibase.Decode((string)t, out MultibaseEncoding _)));
3538
}
3639

3740
/// <inheritdoc />

0 commit comments

Comments
 (0)