├── .gitignore
├── .nuget
└── packages.config
├── IpfsApi.vsmdi
├── IpfsHttpClient.sln
├── LICENSE
├── Local.testsettings
├── README.md
├── TraceAndTestImpact.testsettings
├── appveyor.yml
├── doc
├── .gitignore
├── Documentation.csproj
├── Properties
│ └── AssemblyInfo.cs
├── api
│ ├── .gitignore
│ └── .manifest
├── articles
│ ├── async.md
│ ├── client.md
│ ├── daemon.md
│ ├── envvars.md
│ ├── filesystem.md
│ ├── intro.md
│ └── toc.yml
├── docfx.json
├── images
│ ├── docs-latest-green.svg
│ ├── ipfs-cs-logo-48x48.png
│ ├── ipfs-cs-logo-64x64.png
│ ├── ipfs-cs-logo.svg
│ ├── ipfs-favicon.ico
│ └── ipfs-logo.svg
├── index.md
├── template
│ ├── fonts
│ │ ├── Lato-Bold.eot
│ │ ├── Lato-Bold.ttf
│ │ ├── Lato-Bold.woff
│ │ ├── Lato-Bold.woff2
│ │ ├── Lato-Regular.eot
│ │ ├── Lato-Regular.ttf
│ │ ├── Lato-Regular.woff
│ │ ├── Lato-Regular.woff2
│ │ ├── Lato-Semibold.eot
│ │ ├── Lato-Semibold.ttf
│ │ ├── Lato-Semibold.woff
│ │ ├── Lato-Semibold.woff2
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.svg
│ │ ├── glyphicons-halflings-regular.ttf
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2
│ ├── partials
│ │ ├── class.header.tmpl.partial
│ │ ├── class.tmpl.partial
│ │ └── classSubtitle.tmpl.partial
│ └── styles
│ │ └── main.css
└── toc.yml
├── src
├── Block.cs
├── CoreApi
│ ├── BitswapApi.cs
│ ├── BlockApi.cs
│ ├── BlockRepositoryApi.cs
│ ├── BootstrapApi.cs
│ ├── ConfigApi.cs
│ ├── DagApi.cs
│ ├── DhtApi.cs
│ ├── DnsApi.cs
│ ├── FileSystemApi.cs
│ ├── GenericApi.cs
│ ├── KeyApi.cs
│ ├── NameApi.cs
│ ├── ObjectApi.cs
│ ├── PinApi.cs
│ ├── PubSubApi.cs
│ ├── StatsApi.cs
│ └── SwarmApi.cs
├── FileSystemLink.cs
├── FileSystemNode.cs
├── IpfsClient.cs
├── IpfsHttpClient.csproj
├── MerkleNode.cs
├── PublishedMessage.cs
└── TrustedPeerCollection.cs
└── test
├── App.config
├── BlockTest.cs
├── CoreApi
├── BitswapApiTest.cs
├── BlockApiTest.cs
├── BlockRepositoryTest.cs
├── BootstrapTest.cs
├── CancellationTest.cs
├── ConfigApiTest.cs
├── DagApiTest.cs
├── DhtApiTest.cs
├── DnsApiTest.cs
├── FileSystemApiTest.cs
├── GenericApiTest.cs
├── KeyApiTest.cs
├── NameApiTest.cs
├── ObjectApiTest.cs
├── PinApiTest.cs
├── PubSubApiTest.cs
├── StatsApiTest.cs
└── SwarmApiTest.cs
├── ExceptionAssert.cs
├── FileSystemNodeTest.cs
├── IpfsClientTest.cs
├── IpfsHttpClientTests.csproj
├── MerkleNodeTest.cs
├── PublishedMessageTest.cs
├── TestFixture.cs
└── TrustedPeersTest.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # docfx
26 | api/
27 | doc/api/
28 |
29 | # Visual Studo 2015 cache/options directory
30 | .vs/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | *_i.c
46 | *_p.c
47 | *_i.h
48 | *.ilk
49 | *.meta
50 | *.obj
51 | *.pch
52 | *.pdb
53 | *.pgc
54 | *.pgd
55 | *.rsp
56 | *.sbr
57 | *.tlb
58 | *.tli
59 | *.tlh
60 | *.tmp
61 | *.tmp_proj
62 | *.log
63 | *.vspscc
64 | *.vssscc
65 | .builds
66 | *.pidb
67 | *.svclog
68 | *.scc
69 |
70 | # Chutzpah Test files
71 | _Chutzpah*
72 |
73 | # Visual C++ cache files
74 | ipch/
75 | *.aps
76 | *.ncb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 |
81 | # Visual Studio profiler
82 | *.psess
83 | *.vsp
84 | *.vspx
85 |
86 | # TFS 2012 Local Workspace
87 | $tf/
88 |
89 | # Guidance Automation Toolkit
90 | *.gpState
91 |
92 | # ReSharper is a .NET coding add-in
93 | _ReSharper*/
94 | *.[Rr]e[Ss]harper
95 | *.DotSettings.user
96 |
97 | # JustCode is a .NET coding addin-in
98 | .JustCode
99 |
100 | # TeamCity is a build add-in
101 | _TeamCity*
102 |
103 | # DotCover is a Code Coverage Tool
104 | *.dotCover
105 |
106 | # NCrunch
107 | _NCrunch_*
108 | .*crunch*.local.xml
109 |
110 | # MightyMoose
111 | *.mm.*
112 | AutoTest.Net/
113 |
114 | # Web workbench (sass)
115 | .sass-cache/
116 |
117 | # Installshield output folder
118 | [Ee]xpress/
119 |
120 | # DocProject is a documentation generator add-in
121 | DocProject/buildhelp/
122 | DocProject/Help/*.HxT
123 | DocProject/Help/*.HxC
124 | DocProject/Help/*.hhc
125 | DocProject/Help/*.hhk
126 | DocProject/Help/*.hhp
127 | DocProject/Help/Html2
128 | DocProject/Help/html
129 |
130 | # Click-Once directory
131 | publish/
132 |
133 | # Publish Web Output
134 | *.[Pp]ublish.xml
135 | *.azurePubxml
136 | # TODO: Comment the next line if you want to checkin your web deploy settings
137 | # but database connection strings (with potential passwords) will be unencrypted
138 | *.pubxml
139 | *.publishproj
140 |
141 | # NuGet Packages
142 | *.nupkg
143 | # The packages folder can be ignored because of Package Restore
144 | **/packages/*
145 | # except build/, which is used as an MSBuild target.
146 | !**/packages/build/
147 | # Uncomment if necessary however generally it will be regenerated when needed
148 | #!**/packages/repositories.config
149 |
150 | # Windows Azure Build Output
151 | csx/
152 | *.build.csdef
153 |
154 | # Windows Store app package directory
155 | AppPackages/
156 |
157 | # Others
158 | *.[Cc]ache
159 | ClientBin/
160 | [Ss]tyle[Cc]op.*
161 | ~$*
162 | *~
163 | *.dbmdl
164 | *.dbproj.schemaview
165 | *.pfx
166 | *.publishsettings
167 | node_modules/
168 | bower_components/
169 |
170 | # RIA/Silverlight projects
171 | Generated_Code/
172 |
173 | # Backup & report files from converting an old project file
174 | # to a newer Visual Studio version. Backup files are not needed,
175 | # because we have git ;-)
176 | _UpgradeReport_Files/
177 | Backup*/
178 | UpgradeLog*.XML
179 | UpgradeLog*.htm
180 |
181 | # SQL Server files
182 | *.mdf
183 | *.ldf
184 |
185 | # Business Intelligence projects
186 | *.rdl.data
187 | *.bim.layout
188 | *.bim_*.settings
189 |
190 | # Microsoft Fakes
191 | FakesAssemblies/
192 |
193 | # Node.js Tools for Visual Studio
194 | .ntvs_analysis.dat
195 |
196 | # Visual Studio 6 build log
197 | *.plg
198 |
199 | # Visual Studio 6 workspace options file
200 | *.opt
201 |
202 | # VS 2017 creates this
203 | src/Ipfs.Api.xml
204 |
205 |
--------------------------------------------------------------------------------
/.nuget/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/IpfsApi.vsmdi:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/IpfsHttpClient.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26730.16
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6B9AA9C7-5E90-4D10-9DDE-A2AA5FE3ECA6}"
7 | ProjectSection(SolutionItems) = preProject
8 | .gitignore = .gitignore
9 | appveyor.yml = appveyor.yml
10 | LICENSE = LICENSE
11 | README.md = README.md
12 | EndProjectSection
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Documentation", "doc\Documentation.csproj", "{F3A32EA9-0B2F-46A3-B47A-33B4C04BD423}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpfsHttpClient", "src\IpfsHttpClient.csproj", "{F3C81C57-C283-4E07-B765-DEABCFB22136}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpfsHttpClientTests", "test\IpfsHttpClientTests.csproj", "{B459FBC7-4A28-4170-AD83-7348A403407F}"
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {F3A32EA9-0B2F-46A3-B47A-33B4C04BD423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {F3A32EA9-0B2F-46A3-B47A-33B4C04BD423}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {F3C81C57-C283-4E07-B765-DEABCFB22136}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {F3C81C57-C283-4E07-B765-DEABCFB22136}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {F3C81C57-C283-4E07-B765-DEABCFB22136}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {F3C81C57-C283-4E07-B765-DEABCFB22136}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {B459FBC7-4A28-4170-AD83-7348A403407F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {B459FBC7-4A28-4170-AD83-7348A403407F}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {B459FBC7-4A28-4170-AD83-7348A403407F}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {B459FBC7-4A28-4170-AD83-7348A403407F}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {36ED5AA7-8F41-4F7D-A665-230635EF64A1}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Richard Schneider
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Local.testsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 | These are default test settings for a local test run.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # net-ipfs-http-client
2 |
3 | [](https://ci.appveyor.com/project/richardschneider/net-ipfs-http-client)
4 | [](https://coveralls.io/github/richardschneider/net-ipfs-http-client?branch=master)
5 | [](https://www.nuget.org/packages/Ipfs.Http.Client)
6 | [](https://richardschneider.github.io/net-ipfs-http-client/articles/client.html)
7 |
8 |
9 | A .Net client library for managing IPFS using the [HTTP API](https://docs.ipfs.io/reference/api/http/) protocol.
10 | More information, including the Class Reference, is on the [Project](https://richardschneider.github.io/net-ipfs-http-client/) web site.
11 |
12 | 
13 |
14 | ## Features
15 |
16 | - Targets .NET Framework 4.5, .NET Standard 1.4 and .NET Standard 2.0
17 | - [Asynchronous I/O](https://richardschneider.github.io/net-ipfs-http-client/articles/async.html) to an IPFS server
18 | - Supports [cancellation](https://richardschneider.github.io/net-ipfs-http-client/articles/cancellation.html) of all requests to the IPFS Server
19 | - Requests that all responses are compressed
20 | - Comprehensive [documentation](https://richardschneider.github.io/net-ipfs-http-client/articles/client.html)
21 | - C# style access to the [ipfs core interface](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.html)
22 | - [Bitswap API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IBitswapApi.html)
23 | - [Block API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IBlockApi.html)
24 | - [Config API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IConfigApi.html)
25 | - [Dag API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IDagApi.html)
26 | - [Dht API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IDhtApi.html)
27 | - [Misc API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IGenericApi.html)
28 | - [FileSystem API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IFileSystemApi.html)
29 | - [Key API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IKeyApi.html)
30 | - [Name API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.INameApi.html)
31 | - [Object API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IObjectApi.html)
32 | - [Pin API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IPinApi.html)
33 | - [PubSub API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IPubSubApi.html)
34 | - [Stats API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.IStatsApi.html)
35 | - [Swarm API](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.CoreApi.ISwarmApi.html)
36 |
37 | ## Getting started
38 |
39 | Published releases of IPFS API are available on [NuGet](https://www.nuget.org/packages/ipfs.http.client/). To install, run the following command in the [Package Manager Console](https://docs.nuget.org/docs/start-here/using-the-package-manager-console).
40 |
41 | PM> Install-Package Ipfs.Http.Client
42 |
43 | Or using [dotnet](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet?tabs=netcore21)
44 |
45 | > dotnet add package Ipfs.Http.Client
46 |
47 | ## IpfsClient
48 |
49 | Every feature of IPFS is a property of the [IpfsClient](https://richardschneider.github.io/net-ipfs-http-client/api/Ipfs.Http.IpfsClient.html). The following example
50 | uses `FileSystem` to read a text file
51 |
52 | ```csharp
53 | using Ipfs.Http;
54 |
55 | var ipfs = new IpfsClient();
56 |
57 | const string filename = "QmXarR6rgkQ2fDSHjSY5nM2kuCXKYGViky5nohtwgF65Ec/about";
58 | string text = await ipfs.FileSystem.ReadAllTextAsync(filename);
59 | ```
60 |
61 | # License
62 | Copyright © 2015-2018 Richard Schneider (makaretu@gmail.com)
63 |
64 | The IPFS API library is licensed under the [MIT](http://www.opensource.org/licenses/mit-license.php "Read more about the MIT license form") license. Refer to the [LICENSE](https://github.com/richardschneider/net-ipfs-http-client/blob/master/LICENSE) file for more information.
65 |
66 |
67 |
--------------------------------------------------------------------------------
/TraceAndTestImpact.testsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 | These are test settings for Trace and Test Impact.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # gitversion will change the version number
2 | version: x-{build}
3 |
4 | for:
5 | -
6 | branches:
7 | only:
8 | - master
9 |
10 | environment:
11 | git_token:
12 | secure: NeX5NCOUXsCLc1UjTJjqB9F02FZ8Wq0VsxqTXC8kBdyK6zjxjebrf/9Da2sY1Kql
13 | snk_secret:
14 | secure: 5QzEIgiDqTIrZruPaIQIvTlNMl5BZ7TGEps7ALyBfHE=
15 |
16 | configuration: Release
17 | os: Visual Studio 2017
18 |
19 | init:
20 | - git config --global core.autocrlf input
21 | - git config --global credential.helper store
22 | - ps: Add-Content "$env:USERPROFILE\.git-credentials" "https://$($env:git_token):x-oauth-basic@github.com`n"
23 | - git config --global user.email "noreply@emanon.org"
24 | - git config --global user.name "Appveyor CI"
25 |
26 | environment:
27 | COVERALLS_REPO_TOKEN:
28 | secure: u109t00NLIZQyREMNUyPlMd8gCi6w3o790yT8mQnzEC0LvZyevt+04u63TQfrifC
29 | DOTNET_CLI_TELEMETRY_OPTOUT: 1
30 |
31 | # tools we need for bulding/testing/deploying
32 | install:
33 | - dotnet --version
34 | - choco install gitversion.portable -y
35 | - npm install gh-pages -g
36 |
37 | # - nuget install secure-file -ExcludeVersion
38 | # - if defined snk_secret secure-file\tools\secure-file -decrypt src\ipfs.ci.snk.enc -secret %snk_secret% -out src\ipfs.dev.snk
39 | # - choco install go-ipfs
40 | - choco install go-ipfs --version 0.4.21 --force
41 | - ipfs init
42 | - ps: Start-Process -FilePath "ipfs.exe" -ArgumentList "daemon --enable-pubsub-experiment"
43 |
44 | # gitversion will change the assembly info
45 | pull_requests:
46 | do_not_increment_build_number: true
47 |
48 | before_build:
49 | - nuget restore
50 | - ps: gitversion /output buildserver /updateAssemblyInfo >gitversion.log
51 |
52 | build_script:
53 | - dotnet build -c %CONFIGURATION% -p:Version=%GitVersion_MajorMinorPatch% -p:AssemblyVersion=%GitVersion_MajorMinorPatch%
54 | - dotnet pack -c %CONFIGURATION% --no-build --no-restore -p:Version=%GitVersion_MajorMinorPatch% -p:AssemblyVersion=%GitVersion_MajorMinorPatch%
55 |
56 | after_build:
57 | - cmd: appveyor PushArtifact "src\bin\%CONFIGURATION%\Ipfs.Http.Client.%GitVersion_MajorMinorPatch%.nupkg"
58 |
59 | # Build documentation in doc\_site
60 | # v2.43 is requiring VS 2019!!!
61 | - cmd: choco install docfx -y --version 2.42 --force
62 | - docfx doc\docfx.json --logLevel Warning --warningsAsErrors
63 | - 7z a -tzip docs.zip doc\_site
64 | - appveyor PushArtifact docs.zip
65 | - if defined git_token gh-pages -d doc\_site -m "new docs %GitVersion_FullSemVer%"
66 |
67 | test_script:
68 | - dotnet test -c %CONFIGURATION% --no-build --no-restore test
69 |
70 | after_test:
71 | # Generate coverage report
72 | - packages\OpenCover.4.6.519\tools\OpenCover.Console.exe
73 | -register:user -filter:"+[Ipfs.Http*]* -[*Tests]*"
74 | -target:"c:\Program Files\dotnet\dotnet.exe"
75 | -targetargs:"test -c Release --no-build --no-restore --framework netcoreapp2.0 test"
76 | -output:coverage.xml
77 | -mergeoutput
78 | -hideskipped:File
79 | -oldStyle
80 | - if defined COVERALLS_REPO_TOKEN
81 | packages\coveralls.net.0.6.0\tools\csmacnz.coveralls.exe
82 | --opencover -i ./coverage.xml --useRelativePaths --serviceName appveyor --jobId %APPVEYOR_BUILD_NUMBER%
83 |
84 | # publish NuGet package on tag build
85 | nuget:
86 | disable_publish_on_pr: true
87 |
88 | deploy:
89 | - provider: NuGet
90 | api_key:
91 | secure: OdmGEj/l0K0ZPDmXAYx+fryCzV012eTrM29ALBuL0waxvwLvrufdDXiI+1iNhWEG
92 | on:
93 | appveyor_repo_tag: true
94 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | ###############
2 | # folder #
3 | ###############
4 | /**/DROP/
5 | /**/TEMP/
6 | /**/packages/
7 | /**/bin/
8 | /**/obj/
9 | _site
10 | log.txt
11 | msdn.4.5.2.zip
12 | namespaces.4.5.2.zip
13 |
14 |
--------------------------------------------------------------------------------
/doc/Documentation.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2
5 |
6 |
7 |
--------------------------------------------------------------------------------
/doc/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("WebApplication1")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("WebApplication1")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("f3a32ea9-0b2f-46a3-b47a-33b4c04bd423")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/doc/api/.gitignore:
--------------------------------------------------------------------------------
1 | ###############
2 | # temp file #
3 | ###############
4 | *.yml
5 |
--------------------------------------------------------------------------------
/doc/api/.manifest:
--------------------------------------------------------------------------------
1 | {
2 | "Ipfs.Http": "Ipfs.Http.yml",
3 | "Ipfs.Http.Block": "Ipfs.Http.Block.yml",
4 | "Ipfs.Http.Block.DataBytes": "Ipfs.Http.Block.yml",
5 | "Ipfs.Http.Block.DataStream": "Ipfs.Http.Block.yml",
6 | "Ipfs.Http.Block.Id": "Ipfs.Http.Block.yml",
7 | "Ipfs.Http.Block.Size": "Ipfs.Http.Block.yml",
8 | "Ipfs.Http.FileSystemLink": "Ipfs.Http.FileSystemLink.yml",
9 | "Ipfs.Http.FileSystemLink.Id": "Ipfs.Http.FileSystemLink.yml",
10 | "Ipfs.Http.FileSystemLink.IsDirectory": "Ipfs.Http.FileSystemLink.yml",
11 | "Ipfs.Http.FileSystemLink.Name": "Ipfs.Http.FileSystemLink.yml",
12 | "Ipfs.Http.FileSystemLink.Size": "Ipfs.Http.FileSystemLink.yml",
13 | "Ipfs.Http.FileSystemNode": "Ipfs.Http.FileSystemNode.yml",
14 | "Ipfs.Http.FileSystemNode.DataBytes": "Ipfs.Http.FileSystemNode.yml",
15 | "Ipfs.Http.FileSystemNode.DataStream": "Ipfs.Http.FileSystemNode.yml",
16 | "Ipfs.Http.FileSystemNode.Id": "Ipfs.Http.FileSystemNode.yml",
17 | "Ipfs.Http.FileSystemNode.IpfsClient": "Ipfs.Http.FileSystemNode.yml",
18 | "Ipfs.Http.FileSystemNode.IsDirectory": "Ipfs.Http.FileSystemNode.yml",
19 | "Ipfs.Http.FileSystemNode.Links": "Ipfs.Http.FileSystemNode.yml",
20 | "Ipfs.Http.FileSystemNode.Name": "Ipfs.Http.FileSystemNode.yml",
21 | "Ipfs.Http.FileSystemNode.Size": "Ipfs.Http.FileSystemNode.yml",
22 | "Ipfs.Http.FileSystemNode.ToLink(System.String)": "Ipfs.Http.FileSystemNode.yml",
23 | "Ipfs.Http.IpfsClient": "Ipfs.Http.IpfsClient.yml",
24 | "Ipfs.Http.IpfsClient.#ctor": "Ipfs.Http.IpfsClient.yml",
25 | "Ipfs.Http.IpfsClient.#ctor(System.String)": "Ipfs.Http.IpfsClient.yml",
26 | "Ipfs.Http.IpfsClient.ApiUri": "Ipfs.Http.IpfsClient.yml",
27 | "Ipfs.Http.IpfsClient.Bitswap": "Ipfs.Http.IpfsClient.yml",
28 | "Ipfs.Http.IpfsClient.Block": "Ipfs.Http.IpfsClient.yml",
29 | "Ipfs.Http.IpfsClient.BlockRepository": "Ipfs.Http.IpfsClient.yml",
30 | "Ipfs.Http.IpfsClient.Bootstrap": "Ipfs.Http.IpfsClient.yml",
31 | "Ipfs.Http.IpfsClient.Config": "Ipfs.Http.IpfsClient.yml",
32 | "Ipfs.Http.IpfsClient.Dag": "Ipfs.Http.IpfsClient.yml",
33 | "Ipfs.Http.IpfsClient.DefaultApiUri": "Ipfs.Http.IpfsClient.yml",
34 | "Ipfs.Http.IpfsClient.Dht": "Ipfs.Http.IpfsClient.yml",
35 | "Ipfs.Http.IpfsClient.Dns": "Ipfs.Http.IpfsClient.yml",
36 | "Ipfs.Http.IpfsClient.DoCommandAsync(System.String,System.Threading.CancellationToken,System.String,System.String[])": "Ipfs.Http.IpfsClient.yml",
37 | "Ipfs.Http.IpfsClient.DoCommandAsync``1(System.String,System.Threading.CancellationToken,System.String,System.String[])": "Ipfs.Http.IpfsClient.yml",
38 | "Ipfs.Http.IpfsClient.DownloadAsync(System.String,System.Threading.CancellationToken,System.String,System.String[])": "Ipfs.Http.IpfsClient.yml",
39 | "Ipfs.Http.IpfsClient.DownloadBytesAsync(System.String,System.Threading.CancellationToken,System.String,System.String[])": "Ipfs.Http.IpfsClient.yml",
40 | "Ipfs.Http.IpfsClient.FileSystem": "Ipfs.Http.IpfsClient.yml",
41 | "Ipfs.Http.IpfsClient.Generic": "Ipfs.Http.IpfsClient.yml",
42 | "Ipfs.Http.IpfsClient.IdAsync(Ipfs.MultiHash,System.Threading.CancellationToken)": "Ipfs.Http.IpfsClient.yml",
43 | "Ipfs.Http.IpfsClient.Key": "Ipfs.Http.IpfsClient.yml",
44 | "Ipfs.Http.IpfsClient.Name": "Ipfs.Http.IpfsClient.yml",
45 | "Ipfs.Http.IpfsClient.Object": "Ipfs.Http.IpfsClient.yml",
46 | "Ipfs.Http.IpfsClient.Pin": "Ipfs.Http.IpfsClient.yml",
47 | "Ipfs.Http.IpfsClient.PostDownloadAsync(System.String,System.Threading.CancellationToken,System.String,System.String[])": "Ipfs.Http.IpfsClient.yml",
48 | "Ipfs.Http.IpfsClient.PubSub": "Ipfs.Http.IpfsClient.yml",
49 | "Ipfs.Http.IpfsClient.ResolveAsync(System.String,System.Boolean,System.Threading.CancellationToken)": "Ipfs.Http.IpfsClient.yml",
50 | "Ipfs.Http.IpfsClient.ShutdownAsync": "Ipfs.Http.IpfsClient.yml",
51 | "Ipfs.Http.IpfsClient.Stats": "Ipfs.Http.IpfsClient.yml",
52 | "Ipfs.Http.IpfsClient.Swarm": "Ipfs.Http.IpfsClient.yml",
53 | "Ipfs.Http.IpfsClient.TrustedPeers": "Ipfs.Http.IpfsClient.yml",
54 | "Ipfs.Http.IpfsClient.Upload2Async(System.String,System.Threading.CancellationToken,System.IO.Stream,System.String,System.String[])": "Ipfs.Http.IpfsClient.yml",
55 | "Ipfs.Http.IpfsClient.UploadAsync(System.String,System.Threading.CancellationToken,System.Byte[],System.String[])": "Ipfs.Http.IpfsClient.yml",
56 | "Ipfs.Http.IpfsClient.UploadAsync(System.String,System.Threading.CancellationToken,System.IO.Stream,System.String,System.String[])": "Ipfs.Http.IpfsClient.yml",
57 | "Ipfs.Http.IpfsClient.UserAgent": "Ipfs.Http.IpfsClient.yml",
58 | "Ipfs.Http.IpfsClient.VersionAsync(System.Threading.CancellationToken)": "Ipfs.Http.IpfsClient.yml",
59 | "Ipfs.Http.MerkleNode": "Ipfs.Http.MerkleNode.yml",
60 | "Ipfs.Http.MerkleNode.#ctor(Ipfs.Cid,System.String)": "Ipfs.Http.MerkleNode.yml",
61 | "Ipfs.Http.MerkleNode.#ctor(Ipfs.IMerkleLink)": "Ipfs.Http.MerkleNode.yml",
62 | "Ipfs.Http.MerkleNode.#ctor(System.String,System.String)": "Ipfs.Http.MerkleNode.yml",
63 | "Ipfs.Http.MerkleNode.BlockSize": "Ipfs.Http.MerkleNode.yml",
64 | "Ipfs.Http.MerkleNode.DataBytes": "Ipfs.Http.MerkleNode.yml",
65 | "Ipfs.Http.MerkleNode.DataStream": "Ipfs.Http.MerkleNode.yml",
66 | "Ipfs.Http.MerkleNode.Equals(Ipfs.Http.MerkleNode)": "Ipfs.Http.MerkleNode.yml",
67 | "Ipfs.Http.MerkleNode.Equals(System.Object)": "Ipfs.Http.MerkleNode.yml",
68 | "Ipfs.Http.MerkleNode.GetHashCode": "Ipfs.Http.MerkleNode.yml",
69 | "Ipfs.Http.MerkleNode.Id": "Ipfs.Http.MerkleNode.yml",
70 | "Ipfs.Http.MerkleNode.Links": "Ipfs.Http.MerkleNode.yml",
71 | "Ipfs.Http.MerkleNode.Name": "Ipfs.Http.MerkleNode.yml",
72 | "Ipfs.Http.MerkleNode.op_Equality(Ipfs.Http.MerkleNode,Ipfs.Http.MerkleNode)": "Ipfs.Http.MerkleNode.yml",
73 | "Ipfs.Http.MerkleNode.op_Implicit(System.String)~Ipfs.Http.MerkleNode": "Ipfs.Http.MerkleNode.yml",
74 | "Ipfs.Http.MerkleNode.op_Inequality(Ipfs.Http.MerkleNode,Ipfs.Http.MerkleNode)": "Ipfs.Http.MerkleNode.yml",
75 | "Ipfs.Http.MerkleNode.Size": "Ipfs.Http.MerkleNode.yml",
76 | "Ipfs.Http.MerkleNode.ToLink(System.String)": "Ipfs.Http.MerkleNode.yml",
77 | "Ipfs.Http.MerkleNode.ToString": "Ipfs.Http.MerkleNode.yml",
78 | "Ipfs.Http.PublishedMessage": "Ipfs.Http.PublishedMessage.yml",
79 | "Ipfs.Http.PublishedMessage.#ctor(System.String)": "Ipfs.Http.PublishedMessage.yml",
80 | "Ipfs.Http.PublishedMessage.DataBytes": "Ipfs.Http.PublishedMessage.yml",
81 | "Ipfs.Http.PublishedMessage.DataStream": "Ipfs.Http.PublishedMessage.yml",
82 | "Ipfs.Http.PublishedMessage.DataString": "Ipfs.Http.PublishedMessage.yml",
83 | "Ipfs.Http.PublishedMessage.Id": "Ipfs.Http.PublishedMessage.yml",
84 | "Ipfs.Http.PublishedMessage.Sender": "Ipfs.Http.PublishedMessage.yml",
85 | "Ipfs.Http.PublishedMessage.SequenceNumber": "Ipfs.Http.PublishedMessage.yml",
86 | "Ipfs.Http.PublishedMessage.Size": "Ipfs.Http.PublishedMessage.yml",
87 | "Ipfs.Http.PublishedMessage.Topics": "Ipfs.Http.PublishedMessage.yml",
88 | "Ipfs.Http.TrustedPeerCollection": "Ipfs.Http.TrustedPeerCollection.yml",
89 | "Ipfs.Http.TrustedPeerCollection.Add(Ipfs.MultiAddress)": "Ipfs.Http.TrustedPeerCollection.yml",
90 | "Ipfs.Http.TrustedPeerCollection.AddDefaultNodes": "Ipfs.Http.TrustedPeerCollection.yml",
91 | "Ipfs.Http.TrustedPeerCollection.Clear": "Ipfs.Http.TrustedPeerCollection.yml",
92 | "Ipfs.Http.TrustedPeerCollection.Contains(Ipfs.MultiAddress)": "Ipfs.Http.TrustedPeerCollection.yml",
93 | "Ipfs.Http.TrustedPeerCollection.CopyTo(Ipfs.MultiAddress[],System.Int32)": "Ipfs.Http.TrustedPeerCollection.yml",
94 | "Ipfs.Http.TrustedPeerCollection.Count": "Ipfs.Http.TrustedPeerCollection.yml",
95 | "Ipfs.Http.TrustedPeerCollection.GetEnumerator": "Ipfs.Http.TrustedPeerCollection.yml",
96 | "Ipfs.Http.TrustedPeerCollection.IsReadOnly": "Ipfs.Http.TrustedPeerCollection.yml",
97 | "Ipfs.Http.TrustedPeerCollection.Remove(Ipfs.MultiAddress)": "Ipfs.Http.TrustedPeerCollection.yml",
98 | "Ipfs.Http.TrustedPeerCollection.System#Collections#IEnumerable#GetEnumerator": "Ipfs.Http.TrustedPeerCollection.yml"
99 | }
--------------------------------------------------------------------------------
/doc/articles/async.md:
--------------------------------------------------------------------------------
1 | # Asynchronous I/O
2 |
3 | All requests to the IPFS server are [asynchronous](https://docs.microsoft.com/en-us/dotnet/csharp/async),
4 | which does not block current thread.
5 |
6 | This means that callers should **normally** use the `async/await` paradigm
7 |
8 | ```cs
9 | var result = await ipfs.FileSystem.AddTextAsync("I am pinned");
10 | ```
11 |
12 | ## Synchronous
13 |
14 | If a synchronous operation is required, then this can work
15 |
16 | ```cs
17 | var result = ipfs.FileSystem.AddTextAsync("I am pinned").Result;
18 | ```
19 |
20 | ## Cancelling a request
21 |
22 | All requests to the IPFS server can be cancelled by supplying
23 | an optional [CancellationToken](xref:System.Threading.CancellationToken). When
24 | the token is cancelled,
25 | a [TaskCanceledException](xref:System.Threading.Tasks.TaskCanceledException)
26 | will be `thrown`.
27 |
28 | Here's a contrived example ([unit test](https://github.com/richardschneider/net-ipfs-http-client/blob/cancellation/test/CoreApi/CancellationTest.cs))
29 | that forces the getting of info on the local IPFS server to be cancelled
30 |
31 | ```csharp
32 | var cts = new CancellationTokenSource(500);
33 | try
34 | {
35 | await Task.Delay(1000);
36 | var peer = await ipfs.IdAsync(cts.Token);
37 | Assert.Fail("Did not throw TaskCanceledException");
38 | }
39 | catch (TaskCanceledException)
40 | {
41 | return;
42 | }
43 | ```
44 |
45 | See also [Task Cancellation](https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-cancellation)
46 |
--------------------------------------------------------------------------------
/doc/articles/client.md:
--------------------------------------------------------------------------------
1 | # Accessing IPFS
2 |
3 | IPFS is a distributed peer to peer system. There is no central server! Typically, each machine (peer) runs
4 | a [daemon](daemon.md) that communicates with other peers.
5 |
6 | The [IpfsClient](xref:Ipfs.Http.IpfsClient) provides a simple way for your program to access the daemon
7 | via the [IPFS HTTP API](https://docs.ipfs.io/reference/api/http/) protocol. The client
8 | should be used as a shared object in your program, much like [HttpClient](xref:System.Net.Http.HttpClient). It is
9 | thread safe (re-entrant) and conserves sockets and TCP connections when only one instance is used.
10 |
11 | ```csharp
12 | public class Program
13 | {
14 | static readonly IpfsClient ipfs = new IpfsClient();
15 | public async Task Main(string[] args)
16 | {
17 | // Get the Peer info of the daemon
18 | var peer = await ipfs.IdAsync();
19 | }
20 | }
21 | ```
22 |
23 | ## Core API
24 |
25 | The [Core API](xref:Ipfs.CoreApi.ICoreApi) is a set of interfaces to IPFS features and is implemented by the client. The
26 | [FileSystem](filesystem.md) and [PubSub]() features are most often used.
27 |
28 | ```csharp
29 | const string filename = "QmXarR6rgkQ2fDSHjSY5nM2kuCXKYGViky5nohtwgF65Ec/about";
30 | string text = await ipfs.FileSystem.ReadAllTextAsync(filename);
31 | ```
32 |
33 | ### Features
34 |
35 | | Feature | Purpose |
36 | | ------- | ------- |
37 | | [Bitswap](xref:Ipfs.CoreApi.IBitswapApi) | Data trading module for IPFS; requests blocks from and sends blocks to other peers |
38 | | [Block](xref:Ipfs.CoreApi.IBlockApi) | Manages the blocks |
39 | | [BlockRepository](xref:Ipfs.CoreApi.IBlockRepositoryApi) | Manages the repository of blocks |
40 | | [Bootstrap](xref:Ipfs.CoreApi.IBootstrapApi) | Trusted peers |
41 | | [Config](xref:Ipfs.CoreApi.IConfigApi) | Manages the configuration of the local peer |
42 | | [Dag](xref:Ipfs.CoreApi.IDagApi) | Manages the IPLD (linked data) Directed Acrylic Graph |
43 | | [Dht](xref:Ipfs.CoreApi.IDhtApi) | Manages the Distributed Hash Table |
44 | | [Dns](xref:Ipfs.CoreApi.IDhtApi) | DNS mapping to IPFS |
45 | | [Misc](xref:Ipfs.CoreApi.IGenericApi) | Some miscellaneous methods |
46 | | [FileSystem](xref:Ipfs.CoreApi.IFileSystemApi) | Manages the files/directories in IPFS |
47 | | [Key](xref:Ipfs.CoreApi.IKeyApi) | Manages the cryptographic keys |
48 | | [Name](xref:Ipfs.CoreApi.INameApi) | Manages the Interplanetary Name Space (IPNS) |
49 | | [Object](xref:Ipfs.CoreApi.IObjectApi) | Manages the IPFS Directed Acrylic Graph |
50 | | [Pin](xref:Ipfs.CoreApi.IPinApi) | Manage objects that are locally stored and permanent |
51 | | [PubSub](xref:Ipfs.CoreApi.IPubSubApi) | Publish and subscribe to topic messages |
52 | | [Swarm](xref:Ipfs.CoreApi.IStatsApi) | Get statistics on IPFS components |
53 | | [Swarm](xref:Ipfs.CoreApi.ISwarmApi) | Manages the swarm of peers |
54 |
55 |
--------------------------------------------------------------------------------
/doc/articles/daemon.md:
--------------------------------------------------------------------------------
1 | # IPFS Daemon
2 |
3 | The IPFS daemon is a service that runs on a machine and allows access to other peers on the network. This
4 | is what the [IPFS client](client.md) manages.
5 |
6 | ## Installing
7 |
8 | The authoritive documentmenation is at [https://docs.ipfs.io/introduction/install/](https://docs.ipfs.io/introduction/install/) which
9 | describes the `go-ipfs` implementation.
10 | There is also [js-ipfs](https://docs.ipfs.io/reference/js/overview/) for NodeJS fans.
11 |
12 | ### Windows
13 |
14 | For Windows using [chocolatey](https://chocolatey.org/)
15 |
16 | ```
17 | > choco install go-ipfs
18 | > ipfs init
19 | > ipfs daemon
20 | ```
21 |
22 | ## Locating the daemon
23 |
24 | By default the client looks for a deamon at `http://localhost:5001`. This can be overriden by either
25 | setting the environment variable [IpfsHttpUrl](envvars.md) or initialising the client with an URL.
26 |
27 | ```csharp
28 | // js-ipfs likes this address
29 | static readonly IpfsClient ipfs = new IpfsClient("http://127.0.0.1:5002");
30 | ```
31 |
32 |
33 |
--------------------------------------------------------------------------------
/doc/articles/envvars.md:
--------------------------------------------------------------------------------
1 | # Environment variables
2 |
3 | The following [environment variables](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682653.aspx)
4 | are used to control the behaviour of the library. They override the default value.
5 |
6 | | Name | Description |
7 | | --- | --- |
8 | | IpfsHttpUrl | The [default URL](xref:Ipfs.Http.IpfsClient.DefaultApiUri) to the IPFS HTTP API [daemon](daemon.md).
9 |
--------------------------------------------------------------------------------
/doc/articles/filesystem.md:
--------------------------------------------------------------------------------
1 | # IPFS file system
2 |
3 | The official name is [UnixFS](https://docs.ipfs.io/guides/concepts/unixfs/). It allows files and directories of any size
4 | to be added and retrieved from IPFS via the [FileSystem](xref:Ipfs.CoreApi.IFileSystemApi)
5 | and [Object](xref:Ipfs.CoreApi.IObjectApi) API.
6 |
7 | ## Files
8 |
9 | A file has a unique [content id (CID)](xref:Ipfs.Cid) which is the cryptographic hash of the content; see
10 | [CID concept](https://docs.ipfs.io/guides/concepts/cid/) for background information. The file's content is not just the file's
11 | data but is encapsulated with a [protocol buffer](https://en.wikipedia.org/wiki/Protocol_Buffers) encoding of the
12 | [PBNode](https://github.com/ipfs/go-ipfs/blob/0cb22ccf359e05fb5b55a9bf2f9c515bf7d4dba7/merkledag/pb/merkledag.proto#L31-L39)
13 | and [UnixFS Data](https://github.com/ipfs/go-ipfs/blob/0cb22ccf359e05fb5b55a9bf2f9c515bf7d4dba7/unixfs/pb/unixfs.proto#L3-L20).
14 |
15 | Where
16 | - `PBNode.Data` contains unixfs message Data
17 | - unixfs `Data.Data` contans file's data
18 |
19 | When the file's data exceeds the [chunking size](xref:Ipfs.CoreApi.AddFileOptions.ChunkSize), multiple [blocks](xref:Ipfs.CoreApi.IBlockApi)
20 | are generated. The returned CID points to a block that has `PBNode.Links` and no `PBNode.Data`.
21 |
22 | ### Adding a file
23 |
24 | [AddAsync](xref:Ipfs.CoreApi.IFileSystemApi.AddAsync*) is used to add a stream of data to IPFS. It returns a
25 | [FileSystemNode](xref:Ipfs.IFileSystemNode) which
26 | describes the added the data. Of particular import is its [CID](xref:Ipfs.IDataBlock.Id). The helper methods
27 | [AddTextAsync](xref:Ipfs.CoreApi.IFileSystemApi.AddTextAsync*) and [AddFileAsync](xref:Ipfs.CoreApi.IFileSystemApi.AddFileAsync*) are also available.
28 |
29 | All the Add methods accept [options](xref:Ipfs.CoreApi.AddFileOptions) to control how the data is added to IPFS.
30 |
31 | ```csharp
32 | var fsn = await ipfs.FileSystem.AddTextAsync("hello world");
33 | Console.WriteLine((string)fsn.Id)
34 |
35 | // Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD
36 | ```
37 |
38 | ### Reading a file
39 |
40 | [ReaFileAsync](xref:Ipfs.CoreApi.IFileSystemApi.ReadFileAsync*) is used to read a stream of data from IPFS. It returns a
41 | [Stream](xref:System.IO.Stream) containing just the file's data NOT the protocol buffer encoded data.
42 |
43 | ```csharp
44 | string path = "Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD";
45 | using (var stream = await ipfs.FileSystem.ReadFileAsyc(path))
46 | {
47 | // Do something with the data
48 | }
49 | ```
50 |
51 | ### Getting a CID
52 |
53 | Normally, you get the CID by [adding](xref:Ipfs.CoreApi.IFileSystemApi.AddAsync*) the file to IPFS. You can avoid adding it
54 | to IPFS by using the [OnlyHash option](xref:Ipfs.CoreApi.AddFileOptions.OnlyHash).
55 |
56 | ```csharp
57 | var options = new AddFileOptions { OnlyHash = true };
58 | var fsn = await ipfs.FileSystem.AddTextAsync("hello world", options);
59 | Console.WriteLine((string)fsn.Id)
60 |
61 | // Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD
62 | ```
63 |
64 |
--------------------------------------------------------------------------------
/doc/articles/intro.md:
--------------------------------------------------------------------------------
1 | # IPFS HTTP Client
2 |
3 | A .Net client library for the IPFS HTTP API, implemented in C#. It allows you to access the features of [IPFS](https://ipfs.io/).
4 |
5 | The source code is on [GitHub](https://github.com/richardschneider/net-ipfs-http-client) and the
6 | package is published on [NuGet](https://www.nuget.org/packages/ipfs.http.client).
7 |
8 | 
9 |
--------------------------------------------------------------------------------
/doc/articles/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Introduction
2 | href: intro.md
3 | - name: Accessing IPFS
4 | href: client.md
5 | - name: File system
6 | href: filesystem.md
7 | - name: Asynchronous I/O
8 | href: async.md
9 | - name: Environment variables
10 | href: envvars.md
11 | - name: IPFS daemon
12 | href: daemon.md
13 | - name: Class Reference
14 | href: ../api/Ipfs.Http.yml
15 |
--------------------------------------------------------------------------------
/doc/docfx.json:
--------------------------------------------------------------------------------
1 | {
2 | "metadata": [
3 | {
4 | "src": [
5 | {
6 | "files": [
7 | "src/**.csproj"
8 | ],
9 | "exclude": [
10 | "**/obj/**",
11 | "**/bin/**",
12 | "_site/**"
13 | ],
14 | "src": ".."
15 | }
16 | ],
17 | "properties": {
18 | "TargetFramework": "net45"
19 | },
20 |
21 | "dest": "api"
22 | }
23 | ],
24 | "build": {
25 | "content": [
26 | {
27 | "files": [
28 | "api/**.yml",
29 | "api/index.md"
30 | ]
31 | },
32 | {
33 | "files": [
34 | "articles/**.md",
35 | "articles/**/toc.yml",
36 | "toc.yml",
37 | "*.md"
38 | ],
39 | "exclude": [
40 | "obj/**",
41 | "_site/**"
42 | ]
43 | }
44 | ],
45 | "resource": [
46 | {
47 | "files": [
48 | "images/**"
49 | ],
50 | "exclude": [
51 | "obj/**",
52 | "_site/**"
53 | ]
54 | }
55 | ],
56 | "overwrite": [
57 | {
58 | "files": [
59 | "apidoc/**.md"
60 | ],
61 | "exclude": [
62 | "obj/**",
63 | "_site/**"
64 | ]
65 | }
66 | ],
67 | "xrefService": [
68 | "https://xref.docs.microsoft.com/query?uid={uid}"
69 | ],
70 | "xref": [
71 | "https://richardschneider.github.io/net-ipfs-core/xrefmap.yml"
72 | ],
73 | "globalMetadata": {
74 | "_appTitle": "IPFS HTP Client documentation",
75 | "_appFooter": "Generated by DocFX",
76 | "_appFaviconPath": "images/ipfs-favicon.ico",
77 | "_appLogoPath": "images/ipfs-cs-logo-48x48.png"
78 | },
79 | "dest": "_site",
80 | "globalMetadataFiles": [],
81 | "fileMetadataFiles": [],
82 | "template": [
83 | "default"
84 | ],
85 | "postProcessors": [],
86 | "noLangKeyword": false
87 | }
88 | }
--------------------------------------------------------------------------------
/doc/images/docs-latest-green.svg:
--------------------------------------------------------------------------------
1 | docs docs latest latest
--------------------------------------------------------------------------------
/doc/images/ipfs-cs-logo-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/images/ipfs-cs-logo-48x48.png
--------------------------------------------------------------------------------
/doc/images/ipfs-cs-logo-64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/images/ipfs-cs-logo-64x64.png
--------------------------------------------------------------------------------
/doc/images/ipfs-cs-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
21 |
23 |
24 |
26 | image/svg+xml
27 |
29 |
30 |
31 |
32 |
33 |
53 |
55 |
62 |
66 |
67 |
74 |
78 |
79 |
87 |
91 |
92 |
100 |
104 |
105 |
106 |
110 |
115 |
120 |
121 |
125 |
130 |
135 |
140 |
141 | C #
168 |
--------------------------------------------------------------------------------
/doc/images/ipfs-favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/images/ipfs-favicon.ico
--------------------------------------------------------------------------------
/doc/images/ipfs-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/doc/index.md:
--------------------------------------------------------------------------------
1 | # IPFS HTTP Client
2 |
3 | A .Net client library to access the IPFS, it implements the [IPFS Core API](https://github.com/ipfs/interface-ipfs-core).
4 | The source code is on [GitHub](https://github.com/richardschneider/net-ipfs-http-client) and the
5 | package is published on [NuGet](https://www.nuget.org/packages/Ipfs.Http.Client).
6 |
7 | The interplanetary file system is the permanent web. It is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.
8 |
9 | - [Articles](articles/intro.md) on using the API
10 | - [API Documentation](api/Ipfs.Http.yml) describes the core objects in detail
11 |
12 | [](https://github.com/ipfs/interface-ipfs-core)
13 |
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Bold.eot
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Bold.ttf
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Bold.woff
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Bold.woff2
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Regular.eot
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Regular.ttf
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Regular.woff
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Regular.woff2
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Semibold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Semibold.eot
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Semibold.ttf
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Semibold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Semibold.woff
--------------------------------------------------------------------------------
/doc/template/fonts/Lato-Semibold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/Lato-Semibold.woff2
--------------------------------------------------------------------------------
/doc/template/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/doc/template/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/doc/template/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/doc/template/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-http-client/6b38ef00fb4d6b75cda232234189f274dcdda67c/doc/template/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/doc/template/partials/class.header.tmpl.partial:
--------------------------------------------------------------------------------
1 | {{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
2 |
3 |
{{>partials/title}}
4 | {{{summary}}}
5 | {{{conceptual}}}
6 |
7 | {{#remarks}}
8 |
9 | {{/remarks}}
10 |
11 |
12 |
{{syntax.content.0.value}}
13 |
14 |
15 | {{#inheritance.0}}
16 |
17 |
{{__global.inheritance}}
18 | {{#inheritance}}
19 |
{{{specName.0.value}}}
20 | {{/inheritance}}
21 |
{{item.name.0.value}}
22 | {{#derivedClasses}}
23 |
{{{specName.0.value}}}
24 | {{/derivedClasses}}
25 |
26 | {{/inheritance.0}}
27 |
28 | {{__global.namespace}} : {{namespace}}
29 | {{__global.assembly}} : {{assemblies.0}}.dll
30 |
31 |
32 | {{#syntax.parameters.0}}
33 | {{__global.parameters}} X
34 | {{/syntax.parameters.0}}
35 | {{#syntax.parameters}}
36 | {{{type.specName.0.value}}}
37 | {{{id}}}
38 | {{{description}}}
39 | {{/syntax.parameters}}
40 |
41 | {{#syntax.return}}
42 | {{__global.returns}}
43 |
44 |
45 |
46 | {{__global.type}}
47 | {{__global.description}}
48 |
49 |
50 |
51 |
52 | {{{type.specName.0.value}}}
53 | {{{description}}}
54 |
55 |
56 |
57 | {{/syntax.return}}
58 | {{#syntax.typeParameters.0}}
59 | {{__global.typeParameters}}
60 |
61 |
62 |
63 | {{__global.name}}
64 | {{__global.description}}
65 |
66 |
67 |
68 | {{/syntax.typeParameters.0}}
69 | {{#syntax.typeParameters}}
70 |
71 | {{{id}}}
72 | {{{description}}}
73 |
74 | {{/syntax.typeParameters}}
75 | {{#syntax.typeParameters.0}}
76 |
77 |
78 | {{/syntax.typeParameters.0}}
79 | {{#example.0}}
80 | {{__global.examples}}
81 | {{/example.0}}
82 | {{#example}}
83 | {{{.}}}
84 | {{/example}}
--------------------------------------------------------------------------------
/doc/template/partials/class.tmpl.partial:
--------------------------------------------------------------------------------
1 | {{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
2 |
3 | {{>partials/class.header}}
4 | {{#children}}
5 | {{>partials/classSubtitle}}
6 | {{#children}}
7 | {{^_disableContribution}}
8 | {{#docurl}}
9 |
10 | |
11 | {{__global.improveThisDoc}}
12 | {{/docurl}}
13 | {{#sourceurl}}
14 |
15 | {{__global.viewSource}}
16 | {{/sourceurl}}
17 | {{/_disableContribution}}
18 | {{#overload}}
19 |
20 | {{/overload}}
21 | {{name.0.value}}
22 |
23 | {{{summary}}}
24 | {{{conceptual}}}
25 |
26 |
27 | {{#syntax}}
28 |
29 |
{{syntax.content.0.value}}
30 |
31 |
32 | {{#parameters.0}}
33 | {{__global.parameters}}
34 | {{/parameters.0}}
35 | {{#parameters}}
36 |
37 | {{{type.specName.0.value}}}
38 | {{{id}}}
39 | {{{description}}}
40 |
41 | {{/parameters}}
42 |
43 | {{#return}}
44 | {{__global.returns}}
45 |
46 | {{{type.specName.0.value}}}
47 | {{{description}}}
48 |
49 | {{/return}}
50 |
51 | {{#typeParameters.0}}
52 | {{__global.typeParameters}}
53 |
54 |
55 |
56 | {{__global.name}}
57 | {{__global.description}}
58 |
59 |
60 |
61 | {{/typeParameters.0}}
62 | {{#typeParameters}}
63 |
64 | {{{id}}}
65 | {{{description}}}
66 |
67 | {{/typeParameters}}
68 | {{#typeParameters.0}}
69 |
70 |
71 | {{/typeParameters.0}}
72 | {{#fieldValue}}
73 | {{__global.fieldValue}}
74 |
75 |
76 |
77 | {{__global.type}}
78 | {{__global.description}}
79 |
80 |
81 |
82 |
83 | {{{type.specName.0.value}}}
84 | {{{description}}}
85 |
86 |
87 |
88 | {{/fieldValue}}
89 |
90 | {{#propertyValue}}
91 | {{__global.propertyValue}}
92 |
93 | {{{type.specName.0.value}}}
94 | {{{description}}}
95 |
96 | {{/propertyValue}}
97 |
98 | {{#eventType}}
99 | {{__global.eventType}}
100 |
101 |
102 |
103 | {{__global.type}}
104 | {{__global.description}}
105 |
106 |
107 |
108 |
109 | {{{type.specName.0.value}}}
110 | {{{description}}}
111 |
112 |
113 |
114 | {{/eventType}}
115 | {{/syntax}}
116 | {{#overridden}}
117 | {{__global.overrides}}
118 |
119 | {{/overridden}}
120 | {{#implements.0}}
121 | {{__global.implements}}
122 | {{/implements.0}}
123 | {{#implements}}
124 | {{#definition}}
125 |
126 | {{/definition}}
127 | {{^definition}}
128 |
129 | {{/definition}}
130 | {{/implements}}
131 |
132 | {{#example.0}}
133 | {{__global.examples}}
134 | {{/example.0}}
135 | {{#example}}
136 | {{{.}}}
137 | {{/example}}
138 |
139 | {{#exceptions.0}}
140 | {{__global.exceptions}}
141 | {{/exceptions.0}}
142 | {{#exceptions}}
143 |
144 | {{{type.specName.0.value}}}
145 | {{{description}}}
146 |
147 | {{/exceptions}}
148 |
149 | {{#seealso.0}}
150 | {{__global.seealso}}
151 |
152 | {{/seealso.0}}
153 | {{#seealso}}
154 | {{#isCref}}
155 |
{{{type.specName.0.value}}}
156 | {{/isCref}}
157 | {{^isCref}}
158 |
{{{url}}}
159 | {{/isCref}}
160 | {{/seealso}}
161 | {{#seealso.0}}
162 |
163 | {{/seealso.0}}
164 | {{/children}}
165 | {{/children}}
166 | {{#extensionMethods.0}}
167 | {{__global.extensionMethods}}
168 | {{/extensionMethods.0}}
169 | {{#extensionMethods}}
170 |
171 | {{#definition}}
172 |
173 | {{/definition}}
174 | {{^definition}}
175 |
176 | {{/definition}}
177 |
178 | {{/extensionMethods}}
179 | {{#seealso.0}}
180 | {{__global.seealso}}
181 |
182 | {{/seealso.0}}
183 | {{#seealso}}
184 | {{#isCref}}
185 |
{{{type.specName.0.value}}}
186 | {{/isCref}}
187 | {{^isCref}}
188 |
{{{url}}}
189 | {{/isCref}}
190 | {{/seealso}}
191 | {{#seealso.0}}
192 |
193 | {{/seealso.0}}
194 |
--------------------------------------------------------------------------------
/doc/template/partials/classSubtitle.tmpl.partial:
--------------------------------------------------------------------------------
1 | {{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
2 | {{#inConstructor}}
3 | {{__global.constructorsInSubtitle}}
4 | {{/inConstructor}}
5 | {{#inField}}
6 | {{__global.fieldsInSubtitle}}
7 | {{/inField}}
8 | {{#inProperty}}
9 | {{__global.propertiesInSubtitle}}
10 | {{/inProperty}}
11 | {{#inMethod}}
12 | {{__global.methodsInSubtitle}}
13 | {{/inMethod}}
14 | {{#inEvent}}
15 | {{__global.eventsInSubtitle}}
16 | {{/inEvent}}
17 | {{#inOperator}}
18 | {{__global.operatorsInSubtitle}}
19 | {{/inOperator}}
20 | {{#inEii}}
21 | {{__global.eiisInSubtitle}}
22 | {{/inEii}}
--------------------------------------------------------------------------------
/doc/template/styles/main.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;
4 | height: 100%;
5 | }
6 |
7 | /* http://www.latofonts.com/lato-free-fonts/ */
8 | @font-face {
9 | font-family: 'Lato';
10 | src: url(../fonts/Lato-Regular.eot);
11 | src: url(../fonts/Lato-Regular.eot?#iefix) format('embedded-opentype'),
12 | url(../fonts/Lato-Regular.woff2) format('woff2'),
13 | url(../fonts/Lato-Regular.woff) format('woff'),
14 | url(../fonts/Lato-Regular.ttf) format('truetype');
15 | font-weight: normal;
16 | font-style: normal;
17 | }
18 | @font-face {
19 | font-family: 'Lato';
20 | src: url(../fonts/Lato-Semibold.eot);
21 | src: url(../fonts/Lato-Semibold.eot?#iefix) format('embedded-opentype'),
22 | url(../fonts/Lato-Semibold.woff2) format('woff2'),
23 | url(../fonts/Lato-Semibold.woff) format('woff'),
24 | url(../fonts/Lato-Semibold.ttf) format('truetype');
25 | font-weight: 500;
26 | font-style: normal;
27 | }
28 | @font-face {
29 | font-family: 'Lato';
30 | src: url(../fonts/Lato-Bold.eot);
31 | src: url(../fonts/Lato-Bold.eot?#iefix) format('embedded-opentype'),
32 | url(../fonts/Lato-Bold.woff2) format('woff2'),
33 | url(../fonts/Lato-Bold.woff) format('woff'),
34 | url(../fonts/Lato-Bold.ttf) format('truetype');
35 | font-weight: bold;
36 | font-style: normal;
37 | }
38 |
39 | p {
40 | line-height: 24px;
41 | font-size: 16px;
42 | }
43 |
44 | .h1,h1{font-size:36px}
45 | .h2,h2{font-size:30px}
46 | .h3,h3{font-size:24px}
47 | .h4,h4{font-size:20px}
48 | .h5,h5{font-size:14px}
49 | .h6,h6{font-size:12px}
50 |
51 | #logo {
52 | padding-top: 5px;
53 | }
54 |
--------------------------------------------------------------------------------
/doc/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Articles
2 | href: articles/
3 | - name: Classes
4 | href: api/
5 | - name: Github
6 | href: https://github.com/richardschneider/net-ipfs-http-client
7 |
--------------------------------------------------------------------------------
/src/Block.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.Serialization;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs.Http
10 | {
11 | ///
12 | [DataContract]
13 | public class Block : IDataBlock
14 | {
15 | long? size;
16 |
17 | ///
18 | [DataMember]
19 | public Cid Id { get; set; }
20 |
21 | ///
22 | [DataMember]
23 | public byte[] DataBytes { get; set; }
24 |
25 | ///
26 | public Stream DataStream
27 | {
28 | get
29 | {
30 | return new MemoryStream(DataBytes, false);
31 | }
32 | }
33 |
34 | ///
35 | [DataMember]
36 | public long Size
37 | {
38 | get
39 | {
40 | if (size.HasValue)
41 | {
42 | return size.Value;
43 | }
44 | return DataBytes.Length;
45 | }
46 | set
47 | {
48 | size = value;
49 | }
50 | }
51 |
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/CoreApi/BitswapApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Ipfs.CoreApi;
11 | using System.IO;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class BitswapApi : IBitswapApi
17 | {
18 | IpfsClient ipfs;
19 |
20 | internal BitswapApi(IpfsClient ipfs)
21 | {
22 | this.ipfs = ipfs;
23 | }
24 |
25 | public Task GetAsync(Cid id, CancellationToken cancel = default(CancellationToken))
26 | {
27 | return ipfs.Block.GetAsync(id, cancel);
28 | }
29 |
30 | public async Task> WantsAsync(MultiHash peer = null, CancellationToken cancel = default(CancellationToken))
31 | {
32 | var json = await ipfs.DoCommandAsync("bitswap/wantlist", cancel, peer?.ToString());
33 | var keys = (JArray)(JObject.Parse(json)["Keys"]);
34 | // https://github.com/ipfs/go-ipfs/issues/5077
35 | return keys
36 | .Select(k =>
37 | {
38 | if (k.Type == JTokenType.String)
39 | return Cid.Decode(k.ToString());
40 | var obj = (JObject)k;
41 | return Cid.Decode(obj["/"].ToString());
42 | });
43 | }
44 |
45 | public async Task UnwantAsync(Cid id, CancellationToken cancel = default(CancellationToken))
46 | {
47 | await ipfs.DoCommandAsync("bitswap/unwant", cancel, id);
48 | }
49 |
50 | public async Task LedgerAsync(Peer peer, CancellationToken cancel = default(CancellationToken))
51 | {
52 | var json = await ipfs.DoCommandAsync("bitswap/ledger", cancel, peer.Id.ToString());
53 | var o = JObject.Parse(json);
54 | return new BitswapLedger
55 | {
56 | Peer = (string)o["Peer"],
57 | DataReceived = (ulong)o["Sent"],
58 | DataSent = (ulong)o["Recv"],
59 | BlocksExchanged = (ulong)o["Exchanged"]
60 | };
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/CoreApi/BlockApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Ipfs.CoreApi;
11 | using System.IO;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class BlockApi : IBlockApi
17 | {
18 | IpfsClient ipfs;
19 |
20 | internal BlockApi(IpfsClient ipfs)
21 | {
22 | this.ipfs = ipfs;
23 | }
24 |
25 | public async Task GetAsync(Cid id, CancellationToken cancel = default(CancellationToken))
26 | {
27 | var data = await ipfs.DownloadBytesAsync("block/get", cancel, id);
28 | return new Block
29 | {
30 | DataBytes = data,
31 | Id = id
32 | };
33 | }
34 |
35 | public async Task PutAsync(
36 | byte[] data,
37 | string contentType = Cid.DefaultContentType,
38 | string multiHash = MultiHash.DefaultAlgorithmName,
39 | string encoding = MultiBase.DefaultAlgorithmName,
40 | bool pin = false,
41 | CancellationToken cancel = default(CancellationToken))
42 | {
43 | var options = new List();
44 | if (multiHash != MultiHash.DefaultAlgorithmName ||
45 | contentType != Cid.DefaultContentType ||
46 | encoding != MultiBase.DefaultAlgorithmName)
47 | {
48 | options.Add($"mhtype={multiHash}");
49 | options.Add($"format={contentType}");
50 | options.Add($"cid-base={encoding}");
51 | }
52 | var json = await ipfs.UploadAsync("block/put", cancel, data, options.ToArray());
53 | var info = JObject.Parse(json);
54 | Cid cid = (string)info["Key"];
55 |
56 | if (pin)
57 | {
58 | await ipfs.Pin.AddAsync(cid, recursive: false, cancel: cancel);
59 | }
60 |
61 | return cid;
62 | }
63 |
64 | public async Task PutAsync(
65 | Stream data,
66 | string contentType = Cid.DefaultContentType,
67 | string multiHash = MultiHash.DefaultAlgorithmName,
68 | string encoding = MultiBase.DefaultAlgorithmName,
69 | bool pin = false,
70 | CancellationToken cancel = default(CancellationToken))
71 | {
72 | var options = new List();
73 | if (multiHash != MultiHash.DefaultAlgorithmName ||
74 | contentType != Cid.DefaultContentType ||
75 | encoding != MultiBase.DefaultAlgorithmName)
76 | {
77 | options.Add($"mhtype={multiHash}");
78 | options.Add($"format={contentType}");
79 | options.Add($"cid-base={encoding}");
80 | }
81 | var json = await ipfs.UploadAsync("block/put", cancel, data, null, options.ToArray());
82 | var info = JObject.Parse(json);
83 | Cid cid = (string)info["Key"];
84 |
85 | if (pin)
86 | {
87 | await ipfs.Pin.AddAsync(cid, recursive: false, cancel: cancel);
88 | }
89 |
90 | return cid;
91 | }
92 |
93 | public async Task StatAsync(Cid id, CancellationToken cancel = default(CancellationToken))
94 | {
95 | var json = await ipfs.DoCommandAsync("block/stat", cancel, id);
96 | var info = JObject.Parse(json);
97 | return new Block
98 | {
99 | Size = (long)info["Size"],
100 | Id = (string)info["Key"]
101 | };
102 | }
103 |
104 | public async Task RemoveAsync(Cid id, bool ignoreNonexistent = false, CancellationToken cancel = default(CancellationToken))
105 | {
106 | var json = await ipfs.DoCommandAsync("block/rm", cancel, id, "force=" + ignoreNonexistent.ToString().ToLowerInvariant());
107 | if (json.Length == 0)
108 | return null;
109 | var result = JObject.Parse(json);
110 | var error = (string)result["Error"];
111 | if (error != null)
112 | throw new HttpRequestException(error);
113 | return (Cid)(string)result["Hash"];
114 | }
115 |
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/src/CoreApi/BlockRepositoryApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Ipfs.CoreApi;
11 | using System.IO;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class BlockRepositoryApi : IBlockRepositoryApi
17 | {
18 | IpfsClient ipfs;
19 |
20 | internal BlockRepositoryApi(IpfsClient ipfs)
21 | {
22 | this.ipfs = ipfs;
23 | }
24 |
25 | public async Task RemoveGarbageAsync(CancellationToken cancel = default(CancellationToken))
26 | {
27 | await ipfs.DoCommandAsync("repo/gc", cancel);
28 | }
29 |
30 | public Task StatisticsAsync(CancellationToken cancel = default(CancellationToken))
31 | {
32 | return ipfs.DoCommandAsync("repo/stat", cancel);
33 | }
34 |
35 | public async Task VerifyAsync(CancellationToken cancel = default(CancellationToken))
36 | {
37 | await ipfs.DoCommandAsync("repo/verify", cancel);
38 | }
39 |
40 | public async Task VersionAsync(CancellationToken cancel = default(CancellationToken))
41 | {
42 | var json = await ipfs.DoCommandAsync("repo/version", cancel);
43 | var info = JObject.Parse(json);
44 | return (string)info["Version"];
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/CoreApi/BootstrapApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Ipfs.CoreApi;
11 | using System.IO;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class BootstrapApi : IBootstrapApi
17 | {
18 | IpfsClient ipfs;
19 |
20 | internal BootstrapApi(IpfsClient ipfs)
21 | {
22 | this.ipfs = ipfs;
23 | }
24 |
25 | public async Task AddAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken))
26 | {
27 | var json = await ipfs.DoCommandAsync("bootstrap/add", cancel, address.ToString());
28 | var addrs = (JArray)(JObject.Parse(json)["Peers"]);
29 | var a = addrs.FirstOrDefault();
30 | if (a == null)
31 | return null;
32 | return new MultiAddress((string)a);
33 | }
34 |
35 | public async Task> AddDefaultsAsync(CancellationToken cancel = default(CancellationToken))
36 | {
37 | var json = await ipfs.DoCommandAsync("bootstrap/add/default", cancel);
38 | var addrs = (JArray)(JObject.Parse(json)["Peers"]);
39 | return addrs
40 | .Select(a => MultiAddress.TryCreate((string)a))
41 | .Where(ma => ma != null);
42 | }
43 |
44 | public async Task> ListAsync(CancellationToken cancel = default(CancellationToken))
45 | {
46 | var json = await ipfs.DoCommandAsync("bootstrap/list", cancel);
47 | var addrs = (JArray)(JObject.Parse(json)["Peers"]);
48 | return addrs
49 | .Select(a => MultiAddress.TryCreate((string)a))
50 | .Where(ma => ma != null);
51 | }
52 |
53 | public Task RemoveAllAsync(CancellationToken cancel = default(CancellationToken))
54 | {
55 | return ipfs.DoCommandAsync("bootstrap/rm/all", cancel);
56 | }
57 |
58 | public async Task RemoveAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken))
59 | {
60 | var json = await ipfs.DoCommandAsync("bootstrap/rm", cancel, address.ToString());
61 | var addrs = (JArray)(JObject.Parse(json)["Peers"]);
62 | var a = addrs.FirstOrDefault();
63 | if (a == null)
64 | return null;
65 | return new MultiAddress((string)a);
66 | }
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/CoreApi/ConfigApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using Ipfs.CoreApi;
10 |
11 | namespace Ipfs.Http
12 | {
13 |
14 | class ConfigApi : IConfigApi
15 | {
16 | IpfsClient ipfs;
17 |
18 | internal ConfigApi(IpfsClient ipfs)
19 | {
20 | this.ipfs = ipfs;
21 | }
22 |
23 | public async Task GetAsync(CancellationToken cancel = default(CancellationToken))
24 | {
25 | var json = await ipfs.DoCommandAsync("config/show", cancel);
26 | return JObject.Parse(json);
27 | }
28 |
29 | public async Task GetAsync(string key, CancellationToken cancel = default(CancellationToken))
30 | {
31 | var json = await ipfs.DoCommandAsync("config", cancel, key);
32 | var r = JObject.Parse(json);
33 | return r["Value"];
34 | }
35 |
36 | public async Task SetAsync(string key, string value, CancellationToken cancel = default(CancellationToken))
37 | {
38 | var _ = await ipfs.DoCommandAsync("config", cancel, key, "arg=" + value);
39 | return;
40 | }
41 |
42 | public async Task SetAsync(string key, JToken value, CancellationToken cancel = default(CancellationToken))
43 | {
44 | var _ = await ipfs.DoCommandAsync("config", cancel,
45 | key,
46 | "arg=" + value.ToString(Formatting.None),
47 | "json=true");
48 | return;
49 | }
50 |
51 | public async Task ReplaceAsync(JObject config)
52 | {
53 | var data = Encoding.UTF8.GetBytes(config.ToString(Formatting.None));
54 | await ipfs.UploadAsync("config/replace", CancellationToken.None, data);
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/CoreApi/DagApi.cs:
--------------------------------------------------------------------------------
1 | using Common.Logging;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using Ipfs.CoreApi;
12 | using System.Globalization;
13 |
14 | namespace Ipfs.Http
15 | {
16 |
17 | class DagApi : IDagApi
18 | {
19 | IpfsClient ipfs;
20 |
21 | internal DagApi(IpfsClient ipfs)
22 | {
23 | this.ipfs = ipfs;
24 | }
25 |
26 |
27 | public async Task PutAsync(
28 | JObject data,
29 | string contentType = "dag-cbor",
30 | string multiHash = MultiHash.DefaultAlgorithmName,
31 | string encoding = MultiBase.DefaultAlgorithmName,
32 | bool pin = true,
33 | CancellationToken cancel = default(CancellationToken))
34 | {
35 | using (var ms = new MemoryStream())
36 | {
37 | using (var sw = new StreamWriter(ms, new UTF8Encoding(false), 4096, true) { AutoFlush = true })
38 | using (var jw = new JsonTextWriter(sw))
39 | {
40 | var serializer = new JsonSerializer
41 | {
42 | Culture = CultureInfo.InvariantCulture
43 | };
44 | serializer.Serialize(jw, data);
45 | }
46 | ms.Position = 0;
47 | return await PutAsync(ms, contentType, multiHash, encoding, pin, cancel);
48 | }
49 | }
50 |
51 | public async Task PutAsync(
52 | object data,
53 | string contentType = "dag-cbor",
54 | string multiHash = MultiHash.DefaultAlgorithmName,
55 | string encoding = MultiBase.DefaultAlgorithmName,
56 | bool pin = true,
57 | CancellationToken cancel = default(CancellationToken))
58 | {
59 | using (var ms = new MemoryStream(
60 | Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data)),
61 | false))
62 | {
63 | return await PutAsync(ms, contentType, multiHash, encoding, pin, cancel);
64 | }
65 | }
66 |
67 | public async Task PutAsync(
68 | Stream data,
69 | string contentType = "dag-cbor",
70 | string multiHash = MultiHash.DefaultAlgorithmName,
71 | string encoding = MultiBase.DefaultAlgorithmName,
72 | bool pin = true,
73 | CancellationToken cancel = default(CancellationToken))
74 | {
75 | var json = await ipfs.UploadAsync("dag/put", cancel,
76 | data, null,
77 | $"format={contentType}",
78 | $"pin={pin.ToString().ToLowerInvariant()}",
79 | $"hash={multiHash}",
80 | $"cid-base={encoding}");
81 | var result = JObject.Parse(json);
82 | return (Cid)(string)result["Cid"]["/"];
83 | }
84 |
85 | public async Task GetAsync(
86 | Cid id,
87 | CancellationToken cancel = default(CancellationToken))
88 | {
89 | var json = await ipfs.DoCommandAsync("dag/get", cancel, id);
90 | return JObject.Parse(json);
91 | }
92 |
93 |
94 | public async Task GetAsync(
95 | string path,
96 | CancellationToken cancel = default(CancellationToken))
97 | {
98 | var json = await ipfs.DoCommandAsync("dag/get", cancel, path);
99 | return JToken.Parse(json);
100 | }
101 |
102 | public async Task GetAsync(Cid id, CancellationToken cancel = default(CancellationToken))
103 | {
104 | var json = await ipfs.DoCommandAsync("dag/get", cancel, id);
105 | return JsonConvert.DeserializeObject(json);
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/CoreApi/DhtApi.cs:
--------------------------------------------------------------------------------
1 | using Common.Logging;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using Ipfs.CoreApi;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class DhtApi : IDhtApi
17 | {
18 | static ILog log = LogManager.GetLogger();
19 |
20 | IpfsClient ipfs;
21 |
22 | internal DhtApi(IpfsClient ipfs)
23 | {
24 | this.ipfs = ipfs;
25 | }
26 |
27 | public Task FindPeerAsync(MultiHash id, CancellationToken cancel = default(CancellationToken))
28 | {
29 | return ipfs.IdAsync(id, cancel);
30 | }
31 |
32 | public async Task> FindProvidersAsync(Cid id, int limit = 20, Action providerFound = null, CancellationToken cancel = default(CancellationToken))
33 | {
34 | // TODO: providerFound action
35 | var stream = await ipfs.PostDownloadAsync("dht/findprovs", cancel, id, $"num-providers={limit}");
36 | return ProviderFromStream(stream, limit);
37 | }
38 |
39 | public Task GetAsync(byte[] key, CancellationToken cancel = default(CancellationToken))
40 | {
41 | throw new NotImplementedException();
42 | }
43 |
44 | public Task ProvideAsync(Cid cid, bool advertise = true, CancellationToken cancel = default(CancellationToken))
45 | {
46 | throw new NotImplementedException();
47 | }
48 |
49 | public Task PutAsync(byte[] key, out byte[] value, CancellationToken cancel = default(CancellationToken))
50 | {
51 | throw new NotImplementedException();
52 | }
53 |
54 | public Task TryGetAsync(byte[] key, out byte[] value, CancellationToken cancel = default(CancellationToken))
55 | {
56 | throw new NotImplementedException();
57 | }
58 |
59 | IEnumerable ProviderFromStream(Stream stream, int limit = int.MaxValue)
60 | {
61 | using (var sr = new StreamReader(stream))
62 | {
63 | var n = 0;
64 | while (!sr.EndOfStream && n < limit)
65 | {
66 | var json = sr.ReadLine();
67 | if (log.IsDebugEnabled)
68 | log.DebugFormat("Provider {0}", json);
69 |
70 | var r = JObject.Parse(json);
71 | var id = (string)r["ID"];
72 | if (id != String.Empty)
73 | {
74 | ++n;
75 | yield return new Peer { Id = new MultiHash(id) };
76 | }
77 | else
78 | {
79 | var responses = (JArray)r["Responses"];
80 | if (responses != null)
81 | {
82 | foreach (var response in responses)
83 | {
84 | var rid = (string)response["ID"];
85 | if (rid != String.Empty)
86 | {
87 | ++n;
88 | yield return new Peer { Id = new MultiHash(rid) };
89 | }
90 | }
91 | }
92 | }
93 | }
94 | }
95 | }
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/src/CoreApi/DnsApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Ipfs.CoreApi;
11 | using System.IO;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class DnsApi : IDnsApi
17 | {
18 | IpfsClient ipfs;
19 |
20 | internal DnsApi(IpfsClient ipfs)
21 | {
22 | this.ipfs = ipfs;
23 | }
24 |
25 | public async Task ResolveAsync(string name, bool recursive = false, CancellationToken cancel = default(CancellationToken))
26 | {
27 | var json = await ipfs.DoCommandAsync("dns", cancel,
28 | name,
29 | $"recursive={recursive.ToString().ToLowerInvariant()}");
30 | var path = (string)(JObject.Parse(json)["Path"]);
31 | return path;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/CoreApi/FileSystemApi.cs:
--------------------------------------------------------------------------------
1 | using Common.Logging;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using Ipfs.CoreApi;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class FileSystemApi : IFileSystemApi
17 | {
18 | static ILog log = LogManager.GetLogger();
19 |
20 | IpfsClient ipfs;
21 | Lazy emptyFolder;
22 |
23 | internal FileSystemApi(IpfsClient ipfs)
24 | {
25 | this.ipfs = ipfs;
26 | this.emptyFolder = new Lazy(() => ipfs.Object.NewDirectoryAsync().Result);
27 | }
28 |
29 | public async Task AddFileAsync(string path, AddFileOptions options = null, CancellationToken cancel = default(CancellationToken))
30 | {
31 | using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
32 | {
33 | var node = await AddAsync(stream, Path.GetFileName(path), options, cancel);
34 | return node;
35 | }
36 | }
37 |
38 | public Task AddTextAsync(string text, AddFileOptions options = null, CancellationToken cancel = default(CancellationToken))
39 | {
40 | return AddAsync(new MemoryStream(Encoding.UTF8.GetBytes(text), false), "", options, cancel);
41 | }
42 |
43 | public async Task AddAsync(Stream stream, string name = "", AddFileOptions options = null, CancellationToken cancel = default(CancellationToken))
44 | {
45 | if (options == null)
46 | options = new AddFileOptions();
47 | var opts = new List();
48 | if (!options.Pin)
49 | opts.Add("pin=false");
50 | if (options.Wrap)
51 | opts.Add("wrap-with-directory=true");
52 | if (options.RawLeaves)
53 | opts.Add("raw-leaves=true");
54 | if (options.OnlyHash)
55 | opts.Add("only-hash=true");
56 | if (options.Trickle)
57 | opts.Add("trickle=true");
58 | if (options.Progress != null)
59 | opts.Add("progress=true");
60 | if (options.Hash != MultiHash.DefaultAlgorithmName)
61 | opts.Add($"hash=${options.Hash}");
62 | if (options.Encoding != MultiBase.DefaultAlgorithmName)
63 | opts.Add($"cid-base=${options.Encoding}");
64 | if (!string.IsNullOrWhiteSpace(options.ProtectionKey))
65 | opts.Add($"protect={options.ProtectionKey}");
66 | opts.Add($"chunker=size-{options.ChunkSize}");
67 |
68 | var response = await ipfs.Upload2Async("add", cancel, stream, name, opts.ToArray());
69 |
70 | // The result is a stream of LDJSON objects.
71 | // See https://github.com/ipfs/go-ipfs/issues/4852
72 | FileSystemNode fsn = null;
73 | using (var sr = new StreamReader(response))
74 | using (var jr = new JsonTextReader(sr) { SupportMultipleContent = true })
75 | {
76 | while (jr.Read())
77 | {
78 | var r = await JObject.LoadAsync(jr, cancel);
79 |
80 | // If a progress report.
81 | if (r.ContainsKey("Bytes"))
82 | {
83 | options.Progress?.Report(new TransferProgress
84 | {
85 | Name = (string)r["Name"],
86 | Bytes = (ulong)r["Bytes"]
87 | });
88 | }
89 |
90 | // Else must be an added file.
91 | else
92 | {
93 | fsn = new FileSystemNode
94 | {
95 | Id = (string)r["Hash"],
96 | Size = long.Parse((string)r["Size"]),
97 | IsDirectory = false,
98 | Name = name,
99 | IpfsClient = ipfs
100 | };
101 | if (log.IsDebugEnabled)
102 | log.Debug("added " + fsn.Id + " " + fsn.Name);
103 | }
104 | }
105 | }
106 |
107 | fsn.IsDirectory = options.Wrap;
108 | return fsn;
109 | }
110 |
111 | public async Task AddDirectoryAsync(string path, bool recursive = true, AddFileOptions options = null, CancellationToken cancel = default(CancellationToken))
112 | {
113 | if (options == null)
114 | options = new AddFileOptions();
115 | options.Wrap = false;
116 |
117 | // Add the files and sub-directories.
118 | path = Path.GetFullPath(path);
119 | var files = Directory
120 | .EnumerateFiles(path)
121 | .Select(p => AddFileAsync(p, options, cancel));
122 | if (recursive)
123 | {
124 | var folders = Directory
125 | .EnumerateDirectories(path)
126 | .Select(dir => AddDirectoryAsync(dir, recursive, options, cancel));
127 | files = files.Union(folders);
128 | }
129 |
130 | // go-ipfs v0.4.14 sometimes fails when sending lots of 'add file'
131 | // requests. It's happy with adding one file at a time.
132 | #if true
133 | var links = new List();
134 | foreach (var file in files)
135 | {
136 | var node = await file;
137 | links.Add(node.ToLink());
138 | }
139 | #else
140 | var nodes = await Task.WhenAll(files);
141 | var links = nodes.Select(node => node.ToLink());
142 | #endif
143 | // Create the directory with links to the created files and sub-directories
144 | var folder = emptyFolder.Value.AddLinks(links);
145 | var directory = await ipfs.Object.PutAsync(folder, cancel);
146 |
147 | if (log.IsDebugEnabled)
148 | log.Debug("added " + directory.Id + " " + Path.GetFileName(path));
149 | return new FileSystemNode
150 | {
151 | Id = directory.Id,
152 | Name = Path.GetFileName(path),
153 | Links = links,
154 | IsDirectory = true,
155 | Size = directory.Size,
156 | IpfsClient = ipfs
157 | };
158 |
159 | }
160 |
161 | ///
162 | /// Reads the content of an existing IPFS file as text.
163 | ///
164 | ///
165 | /// A path to an existing file, such as "QmXarR6rgkQ2fDSHjSY5nM2kuCXKYGViky5nohtwgF65Ec/about"
166 | /// or "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V"
167 | ///
168 | ///
169 | /// Is used to stop the task. When cancelled, the is raised.
170 | ///
171 | ///
172 | /// The contents of the as a .
173 | ///
174 | public async Task ReadAllTextAsync(string path, CancellationToken cancel = default(CancellationToken))
175 | {
176 | using (var data = await ReadFileAsync(path, cancel))
177 | using (var text = new StreamReader(data))
178 | {
179 | return await text.ReadToEndAsync();
180 | }
181 | }
182 |
183 |
184 | ///
185 | /// Opens an existing IPFS file for reading.
186 | ///
187 | ///
188 | /// A path to an existing file, such as "QmXarR6rgkQ2fDSHjSY5nM2kuCXKYGViky5nohtwgF65Ec/about"
189 | /// or "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V"
190 | ///
191 | ///
192 | /// Is used to stop the task. When cancelled, the is raised.
193 | ///
194 | ///
195 | /// A to the file contents.
196 | ///
197 | public Task ReadFileAsync(string path, CancellationToken cancel = default(CancellationToken))
198 | {
199 | return ipfs.DownloadAsync("cat", cancel, path);
200 | }
201 |
202 | public Task ReadFileAsync(string path, long offset, long length = 0, CancellationToken cancel = default(CancellationToken))
203 | {
204 | // https://github.com/ipfs/go-ipfs/issues/5380
205 | if (offset > int.MaxValue)
206 | throw new NotSupportedException("Only int offsets are currently supported.");
207 | if (length > int.MaxValue)
208 | throw new NotSupportedException("Only int lengths are currently supported.");
209 |
210 | if (length == 0)
211 | length = int.MaxValue; // go-ipfs only accepts int lengths
212 | return ipfs.DownloadAsync("cat", cancel, path,
213 | $"offset={offset}",
214 | $"length={length}");
215 | }
216 |
217 | ///
218 | /// Get information about the file or directory.
219 | ///
220 | ///
221 | /// A path to an existing file or directory, such as "QmXarR6rgkQ2fDSHjSY5nM2kuCXKYGViky5nohtwgF65Ec/about"
222 | /// or "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V"
223 | ///
224 | ///
225 | /// Is used to stop the task. When cancelled, the is raised.
226 | ///
227 | ///
228 | public async Task ListFileAsync(string path, CancellationToken cancel = default(CancellationToken))
229 | {
230 | var json = await ipfs.DoCommandAsync("file/ls", cancel, path);
231 | var r = JObject.Parse(json);
232 | var hash = (string)r["Arguments"][path];
233 | var o = (JObject)r["Objects"][hash];
234 | var node = new FileSystemNode()
235 | {
236 | Id = (string)o["Hash"],
237 | Size = (long)o["Size"],
238 | IsDirectory = (string)o["Type"] == "Directory",
239 | Links = new FileSystemLink[0],
240 | IpfsClient = ipfs
241 | };
242 | var links = o["Links"] as JArray;
243 | if (links != null)
244 | {
245 | node.Links = links
246 | .Select(l => new FileSystemLink()
247 | {
248 | Name = (string)l["Name"],
249 | Id = (string)l["Hash"],
250 | Size = (long)l["Size"],
251 | })
252 | .ToArray();
253 | }
254 |
255 | return node;
256 | }
257 |
258 | public Task GetAsync(string path, bool compress = false, CancellationToken cancel = default(CancellationToken))
259 | {
260 | return ipfs.DownloadAsync("get", cancel, path, $"compress={compress}");
261 | }
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/src/CoreApi/GenericApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Globalization;
5 | using System.Linq;
6 | using System.Text;
7 | using System.IO;
8 | using System.Net;
9 | using System.Threading.Tasks;
10 | using System.Threading;
11 | using Ipfs.CoreApi;
12 | using Newtonsoft.Json.Linq;
13 |
14 | namespace Ipfs.Http
15 | {
16 | public partial class IpfsClient : IGenericApi
17 | {
18 | const double TicksPerNanosecond = (double)TimeSpan.TicksPerMillisecond * 0.000001;
19 |
20 | ///
21 | public Task IdAsync(MultiHash peer = null, CancellationToken cancel = default(CancellationToken))
22 | {
23 | return DoCommandAsync("id", cancel, peer?.ToString());
24 | }
25 |
26 | ///
27 | public async Task> PingAsync(MultiHash peer, int count = 10, CancellationToken cancel = default(CancellationToken))
28 | {
29 | var stream = await PostDownloadAsync("ping", cancel,
30 | peer.ToString(),
31 | $"count={count.ToString(CultureInfo.InvariantCulture)}");
32 | return PingResultFromStream(stream);
33 | }
34 |
35 | ///
36 | public async Task> PingAsync(MultiAddress address, int count = 10, CancellationToken cancel = default(CancellationToken))
37 | {
38 | var stream = await PostDownloadAsync("ping", cancel,
39 | address.ToString(),
40 | $"count={count.ToString(CultureInfo.InvariantCulture)}");
41 | return PingResultFromStream(stream);
42 | }
43 |
44 | IEnumerable PingResultFromStream(Stream stream)
45 | {
46 | using (var sr = new StreamReader(stream))
47 | {
48 | while (!sr.EndOfStream)
49 | {
50 | var json = sr.ReadLine();
51 | if (log.IsDebugEnabled)
52 | log.DebugFormat("RSP {0}", json);
53 |
54 | var r = JObject.Parse(json);
55 | yield return new PingResult
56 | {
57 | Success = (bool)r["Success"],
58 | Text = (string)r["Text"],
59 | Time = TimeSpan.FromTicks((long)((long)r["Time"] * TicksPerNanosecond))
60 | };
61 | }
62 | }
63 | }
64 |
65 | ///
66 | public async Task ResolveAsync(string name, bool recursive = true, CancellationToken cancel = default(CancellationToken))
67 | {
68 | var json = await DoCommandAsync("resolve", cancel,
69 | name,
70 | $"recursive={recursive.ToString().ToLowerInvariant()}");
71 | var path = (string)(JObject.Parse(json)["Path"]);
72 | return path;
73 | }
74 |
75 | ///
76 | public async Task ShutdownAsync()
77 | {
78 | await DoCommandAsync("shutdown", default(CancellationToken));
79 | }
80 |
81 | ///
82 | public Task> VersionAsync(CancellationToken cancel = default(CancellationToken))
83 | {
84 | return DoCommandAsync>("version", cancel);
85 | }
86 |
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/CoreApi/KeyApi.cs:
--------------------------------------------------------------------------------
1 | using Common.Logging;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using Ipfs.CoreApi;
12 |
13 | namespace Ipfs.Http
14 | {
15 | class KeyApi : IKeyApi
16 | {
17 | ///
18 | /// Information about a local key.
19 | ///
20 | public class KeyInfo : IKey
21 | {
22 | ///
23 | public MultiHash Id { get; set; }
24 |
25 | ///
26 | public string Name { get; set; }
27 |
28 | ///
29 | public override string ToString()
30 | {
31 | return Name;
32 | }
33 |
34 | }
35 | IpfsClient ipfs;
36 |
37 | internal KeyApi(IpfsClient ipfs)
38 | {
39 | this.ipfs = ipfs;
40 | }
41 |
42 | public async Task CreateAsync(string name, string keyType, int size, CancellationToken cancel = default(CancellationToken))
43 | {
44 | return await ipfs.DoCommandAsync("key/gen", cancel,
45 | name,
46 | $"type={keyType}",
47 | $"size={size}");
48 | }
49 |
50 | public async Task> ListAsync(CancellationToken cancel = default(CancellationToken))
51 | {
52 | var json = await ipfs.DoCommandAsync("key/list", cancel, null, "l=true");
53 | var keys = (JArray)(JObject.Parse(json)["Keys"]);
54 | return keys
55 | .Select(k => new KeyInfo
56 | {
57 | Id = (string)k["Id"],
58 | Name = (string)k["Name"]
59 | });
60 | }
61 |
62 | public async Task RemoveAsync(string name, CancellationToken cancel = default(CancellationToken))
63 | {
64 | var json = await ipfs.DoCommandAsync("key/rm", cancel, name);
65 | var keys = JObject.Parse(json)["Keys"] as JArray;
66 |
67 | return keys?
68 | .Select(k => new KeyInfo
69 | {
70 | Id = (string)k["Id"],
71 | Name = (string)k["Name"]
72 | })
73 | .First();
74 | }
75 |
76 | public async Task RenameAsync(string oldName, string newName, CancellationToken cancel = default(CancellationToken))
77 | {
78 | var json = await ipfs.DoCommandAsync("key/rename", cancel, oldName, $"arg={newName}");
79 | var key = JObject.Parse(json);
80 | return new KeyInfo
81 | {
82 | Id = (string)key["Id"],
83 | Name = (string)key["Now"]
84 | };
85 | }
86 |
87 | public Task ExportAsync(string name, char[] password, CancellationToken cancel = default(CancellationToken))
88 | {
89 | throw new NotImplementedException();
90 | }
91 |
92 | public Task ImportAsync(string name, string pem, char[] password = null, CancellationToken cancel = default(CancellationToken))
93 | {
94 | throw new NotImplementedException();
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/CoreApi/NameApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Ipfs.CoreApi;
11 | using System.IO;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class NameApi : INameApi
17 | {
18 | IpfsClient ipfs;
19 |
20 | internal NameApi(IpfsClient ipfs)
21 | {
22 | this.ipfs = ipfs;
23 | }
24 |
25 | public async Task PublishAsync(string path, bool resolve = true, string key = "self", TimeSpan? lifetime = null, CancellationToken cancel = default(CancellationToken))
26 | {
27 | var json = await ipfs.DoCommandAsync("name/publish", cancel,
28 | path,
29 | "lifetime=24h", // TODO
30 | $"resolve={resolve.ToString().ToLowerInvariant()}",
31 | $"key={key}");
32 | // TODO: lifetime
33 | var info = JObject.Parse(json);
34 | return new NamedContent
35 | {
36 | NamePath = (string)info["Name"],
37 | ContentPath = (string)info["Value"]
38 | };
39 | }
40 |
41 | public Task PublishAsync(Cid id, string key = "self", TimeSpan? lifetime = null, CancellationToken cancel = default(CancellationToken))
42 | {
43 | return PublishAsync("/ipfs/" + id.Encode(), false, key, lifetime, cancel);
44 | }
45 |
46 | public async Task ResolveAsync(string name, bool recursive = false, bool nocache = false, CancellationToken cancel = default(CancellationToken))
47 | {
48 | var json = await ipfs.DoCommandAsync("name/resolve", cancel,
49 | name,
50 | $"recursive={recursive.ToString().ToLowerInvariant()}",
51 | $"nocache={nocache.ToString().ToLowerInvariant()}");
52 | var path = (string)(JObject.Parse(json)["Path"]);
53 | return path;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/CoreApi/ObjectApi.cs:
--------------------------------------------------------------------------------
1 | using Common.Logging;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using Ipfs.CoreApi;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class ObjectApi : IObjectApi
17 | {
18 | static ILog log = LogManager.GetLogger();
19 |
20 | IpfsClient ipfs;
21 |
22 | internal ObjectApi(IpfsClient ipfs)
23 | {
24 | this.ipfs = ipfs;
25 | }
26 |
27 | public Task NewDirectoryAsync(CancellationToken cancel = default(CancellationToken))
28 | {
29 | return NewAsync("unixfs-dir", cancel);
30 | }
31 |
32 | public async Task NewAsync(string template = null, CancellationToken cancel = default(CancellationToken))
33 | {
34 | var json = await ipfs.DoCommandAsync("object/new", cancel, template);
35 | var hash = (string) (JObject.Parse(json)["Hash"]);
36 | return await GetAsync(hash);
37 | }
38 |
39 | public async Task GetAsync(Cid id, CancellationToken cancel = default(CancellationToken))
40 | {
41 | var json = await ipfs.DoCommandAsync("object/get", cancel, id);
42 | return GetDagFromJson(json);
43 | }
44 |
45 | public Task PutAsync(byte[] data, IEnumerable links = null, CancellationToken cancel = default(CancellationToken))
46 | {
47 | return PutAsync(new DagNode(data, links), cancel);
48 | }
49 |
50 | public async Task PutAsync(DagNode node, CancellationToken cancel = default(CancellationToken))
51 | {
52 | var json = await ipfs.UploadAsync("object/put", cancel, node.ToArray(), "inputenc=protobuf");
53 | return node;
54 | }
55 |
56 | public Task DataAsync(Cid id, CancellationToken cancel = default(CancellationToken))
57 | {
58 | return ipfs.DownloadAsync("object/data", cancel, id);
59 | }
60 |
61 | public async Task> LinksAsync(Cid id, CancellationToken cancel = default(CancellationToken))
62 | {
63 | var json = await ipfs.DoCommandAsync("object/links", cancel, id);
64 | return GetDagFromJson(json).Links;
65 | }
66 |
67 | // TOOD: patch sub API
68 |
69 | DagNode GetDagFromJson(string json)
70 | {
71 | var result = JObject.Parse(json);
72 | byte[] data = null;
73 | var stringData = (string)result["Data"];
74 | if (stringData != null)
75 | data = Encoding.UTF8.GetBytes(stringData);
76 | var links = ((JArray)result["Links"])
77 | .Select(link => new DagLink(
78 | (string)link["Name"],
79 | (string)link["Hash"],
80 | (long)link["Size"]));
81 | return new DagNode(data, links);
82 | }
83 |
84 | public async Task StatAsync(Cid id, CancellationToken cancel = default(CancellationToken))
85 | {
86 | var json = await ipfs.DoCommandAsync("object/stat", cancel, id);
87 | var r = JObject.Parse(json);
88 |
89 | return new ObjectStat
90 | {
91 | LinkCount = (int)r["NumLinks"],
92 | LinkSize = (long)r["LinksSize"],
93 | BlockSize = (long)r["BlockSize"],
94 | DataSize = (long)r["DataSize"],
95 | CumulativeSize = (long)r["CumulativeSize"]
96 | };
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/CoreApi/PinApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using Ipfs.CoreApi;
10 |
11 | namespace Ipfs.Http
12 | {
13 |
14 | class PinApi : IPinApi
15 | {
16 | IpfsClient ipfs;
17 |
18 | internal PinApi(IpfsClient ipfs)
19 | {
20 | this.ipfs = ipfs;
21 | }
22 |
23 | public async Task> AddAsync(string path, bool recursive = true, CancellationToken cancel = default(CancellationToken))
24 | {
25 | var opts = "recursive=" + recursive.ToString().ToLowerInvariant();
26 | var json = await ipfs.DoCommandAsync("pin/add", cancel, path, opts);
27 | return ((JArray)JObject.Parse(json)["Pins"])
28 | .Select(p => (Cid)(string)p);
29 | }
30 |
31 | public async Task> ListAsync(CancellationToken cancel = default(CancellationToken))
32 | {
33 | var json = await ipfs.DoCommandAsync("pin/ls", cancel);
34 | var keys = (JObject)(JObject.Parse(json)["Keys"]);
35 | return keys
36 | .Properties()
37 | .Select(p => (Cid)p.Name);
38 | }
39 |
40 | public async Task> RemoveAsync(Cid id, bool recursive = true, CancellationToken cancel = default(CancellationToken))
41 | {
42 | var opts = "recursive=" + recursive.ToString().ToLowerInvariant();
43 | var json = await ipfs.DoCommandAsync("pin/rm", cancel, id, opts);
44 | return ((JArray)JObject.Parse(json)["Pins"])
45 | .Select(p => (Cid)(string)p);
46 | }
47 |
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/CoreApi/PubSubApi.cs:
--------------------------------------------------------------------------------
1 | using Common.Logging;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using Ipfs.CoreApi;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class PubSubApi : IPubSubApi
17 | {
18 | static ILog log = LogManager.GetLogger();
19 |
20 | IpfsClient ipfs;
21 |
22 | internal PubSubApi(IpfsClient ipfs)
23 | {
24 | this.ipfs = ipfs;
25 | }
26 |
27 | public async Task> SubscribedTopicsAsync(CancellationToken cancel = default(CancellationToken))
28 | {
29 | var json = await ipfs.DoCommandAsync("pubsub/ls", cancel);
30 | var result = JObject.Parse(json);
31 | var strings = result["Strings"] as JArray;
32 | if (strings == null) return new string[0];
33 | return strings.Select(s => (string)s);
34 | }
35 |
36 | public async Task> PeersAsync(string topic = null, CancellationToken cancel = default(CancellationToken))
37 | {
38 | var json = await ipfs.DoCommandAsync("pubsub/peers", cancel, topic);
39 | var result = JObject.Parse(json);
40 | var strings = result["Strings"] as JArray;
41 | if (strings == null) return new Peer[0];
42 | return strings.Select(s => new Peer { Id = (string)s } );
43 | }
44 |
45 | public Task PublishAsync(string topic, byte[] message, CancellationToken cancel = default(CancellationToken))
46 | {
47 | var url = new StringBuilder();
48 | 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);
55 | }
56 |
57 | public Task PublishAsync(string topic, Stream message, CancellationToken cancel = default(CancellationToken))
58 | {
59 | using (MemoryStream ms = new MemoryStream())
60 | {
61 | message.CopyTo(ms);
62 | return PublishAsync(topic, ms.ToArray(), cancel);
63 | }
64 | }
65 |
66 | public async Task PublishAsync(string topic, string message, CancellationToken cancel = default(CancellationToken))
67 | {
68 | var _ = await ipfs.DoCommandAsync("pubsub/pub", cancel, topic, "arg=" + message);
69 | return;
70 | }
71 |
72 | public async Task SubscribeAsync(string topic, Action handler, CancellationToken cancellationToken)
73 | {
74 | var messageStream = await ipfs.PostDownloadAsync("pubsub/sub", cancellationToken, topic);
75 | var sr = new StreamReader(messageStream);
76 |
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
80 |
81 | return;
82 | }
83 |
84 | void ProcessMessages(string topic, Action handler, StreamReader sr, CancellationToken ct)
85 | {
86 | log.DebugFormat("Start listening for '{0}' messages", topic);
87 |
88 | // .Net needs a ReadLine(CancellationToken)
89 | // As a work-around, we register a function to close the stream
90 | ct.Register(() => sr.Dispose());
91 | try
92 | {
93 | while (!sr.EndOfStream && !ct.IsCancellationRequested)
94 | {
95 | var json = sr.ReadLine();
96 | if (json == null)
97 | break;
98 | if (log.IsDebugEnabled)
99 | log.DebugFormat("PubSub message {0}", json);
100 |
101 | // go-ipfs 0.4.13 and earlier always send empty JSON
102 | // as the first response.
103 | if (json == "{}")
104 | continue;
105 |
106 | if (!ct.IsCancellationRequested)
107 | {
108 | handler(new PublishedMessage(json));
109 | }
110 | }
111 | }
112 | catch (Exception e)
113 | {
114 | // Do not report errors when cancelled.
115 | if (!ct.IsCancellationRequested)
116 | log.Error(e);
117 | }
118 | finally
119 | {
120 | sr.Dispose();
121 | }
122 |
123 | log.DebugFormat("Stop listening for '{0}' messages", topic);
124 | }
125 |
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/src/CoreApi/StatsApi.cs:
--------------------------------------------------------------------------------
1 | using Common.Logging;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using Ipfs.CoreApi;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class StatApi : IStatsApi
17 | {
18 | IpfsClient ipfs;
19 |
20 | internal StatApi(IpfsClient ipfs)
21 | {
22 | this.ipfs = ipfs;
23 | }
24 |
25 | public Task BandwidthAsync(CancellationToken cancel = default(CancellationToken))
26 | {
27 | return ipfs.DoCommandAsync("stats/bw", cancel);
28 | }
29 |
30 | public async Task BitswapAsync(CancellationToken cancel = default(CancellationToken))
31 | {
32 | var json = await ipfs.DoCommandAsync("stats/bitswap", cancel);
33 | var stat = JObject.Parse(json);
34 | return new BitswapData
35 | {
36 | BlocksReceived = (ulong)stat["BlocksReceived"],
37 | DataReceived = (ulong)stat["DataReceived"],
38 | BlocksSent = (ulong)stat["BlocksSent"],
39 | DataSent = (ulong)stat["DataSent"],
40 | DupBlksReceived = (ulong)stat["DupBlksReceived"],
41 | DupDataReceived = (ulong)stat["DupDataReceived"],
42 | ProvideBufLen = (int)stat["ProvideBufLen"],
43 | Peers = ((JArray)stat["Peers"]).Select(s => new MultiHash((string)s)),
44 | Wantlist = ((JArray)stat["Wantlist"]).Select(o => Cid.Decode(o["/"].ToString()))
45 | };
46 | }
47 |
48 | public Task RepositoryAsync(CancellationToken cancel = default(CancellationToken))
49 | {
50 | return ipfs.DoCommandAsync("stats/repo", cancel);
51 | }
52 |
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/CoreApi/SwarmApi.cs:
--------------------------------------------------------------------------------
1 | using Common.Logging;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using Ipfs.CoreApi;
12 |
13 | namespace Ipfs.Http
14 | {
15 |
16 | class SwarmApi : ISwarmApi
17 | {
18 | IpfsClient ipfs;
19 |
20 | internal SwarmApi(IpfsClient ipfs)
21 | {
22 | this.ipfs = ipfs;
23 | }
24 |
25 | public async Task> AddressesAsync(CancellationToken cancel = default(CancellationToken))
26 | {
27 | var json = await ipfs.DoCommandAsync("swarm/addrs", cancel);
28 | return ((JObject)JObject.Parse(json)["Addrs"])
29 | .Properties()
30 | .Select(p => new Peer {
31 | Id = p.Name,
32 | Addresses = ((JArray)p.Value)
33 | .Select(a => MultiAddress.TryCreate((string)a))
34 | .Where(ma => ma != null)
35 | });
36 | }
37 |
38 | public async Task> PeersAsync(CancellationToken cancel = default(CancellationToken))
39 | {
40 | var json = await ipfs.DoCommandAsync("swarm/peers", cancel, null, "verbose=true");
41 | var result = JObject.Parse(json);
42 |
43 | // Older servers return an array of strings
44 | var strings = (JArray)result["Strings"];
45 | if (strings != null)
46 | {
47 | return strings
48 | .Select(s =>
49 | {
50 | var parts = ((string)s).Split(' ');
51 | var address = new MultiAddress(parts[0]);
52 | return new Peer
53 | {
54 | Id = address.PeerId,
55 | ConnectedAddress = parts[0],
56 | Latency = Duration.Parse(parts[1])
57 | };
58 | });
59 | }
60 |
61 | // Current servers return JSON
62 | var peers = (JArray)result["Peers"];
63 | if (peers != null)
64 | {
65 | return peers.Select(p => new Peer
66 | {
67 | Id = (string)p["Peer"],
68 | ConnectedAddress = new MultiAddress((string)p["Addr"] + "/ipfs/" + (string)p["Peer"]),
69 | Latency = Duration.Parse((string)p["Latency"])
70 | });
71 | }
72 |
73 | // Hmmm. Another change we can handle
74 | throw new FormatException("Unknown response from 'swarm/peers");
75 | }
76 |
77 | public async Task ConnectAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken))
78 | {
79 | await ipfs.DoCommandAsync("swarm/connect", cancel, address.ToString());
80 | }
81 |
82 | public async Task DisconnectAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken))
83 | {
84 | await ipfs.DoCommandAsync("swarm/disconnect", cancel, address.ToString());
85 | }
86 |
87 | public async Task AddAddressFilterAsync(MultiAddress address, bool persist = false, CancellationToken cancel = default(CancellationToken))
88 | {
89 | // go-ipfs always does persist, https://github.com/ipfs/go-ipfs/issues/4605
90 | var json = await ipfs.DoCommandAsync("swarm/filters/add", cancel, address.ToString());
91 | var addrs = (JArray)(JObject.Parse(json)["Strings"]);
92 | var a = addrs.FirstOrDefault();
93 | if (a == null)
94 | return null;
95 | return new MultiAddress((string)a);
96 | }
97 |
98 | public async Task> ListAddressFiltersAsync(bool persist = false, CancellationToken cancel = default(CancellationToken))
99 | {
100 | JArray addrs;
101 | if (persist)
102 | {
103 | addrs = await ipfs.Config.GetAsync("Swarm.AddrFilters", cancel) as JArray;
104 | }
105 | else
106 | {
107 | var json = await ipfs.DoCommandAsync("swarm/filters", cancel);
108 | addrs = (JObject.Parse(json)["Strings"]) as JArray;
109 | }
110 |
111 | if (addrs == null)
112 | return new MultiAddress[0];
113 | return addrs
114 | .Select(a => MultiAddress.TryCreate((string)a))
115 | .Where(ma => ma != null);
116 | }
117 |
118 | public async Task RemoveAddressFilterAsync(MultiAddress address, bool persist = false, CancellationToken cancel = default(CancellationToken))
119 | {
120 | // go-ipfs always does persist, https://github.com/ipfs/go-ipfs/issues/4605
121 | var json = await ipfs.DoCommandAsync("swarm/filters/rm", cancel, address.ToString());
122 | var addrs = (JArray)(JObject.Parse(json)["Strings"]);
123 | var a = addrs.FirstOrDefault();
124 | if (a == null)
125 | return null;
126 | return new MultiAddress((string)a);
127 | }
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/src/FileSystemLink.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Ipfs.Http
3 | {
4 | ///
5 | /// A link to another file system node in IPFS.
6 | ///
7 | public class FileSystemLink : IFileSystemLink
8 | {
9 | ///
10 | public string Name { get; set; }
11 |
12 | ///
13 | public Cid Id { get; set; }
14 |
15 | ///
16 | public long Size { get; set; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/FileSystemNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.Serialization;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs.Http
10 | {
11 | ///
12 | [DataContract]
13 | public class FileSystemNode : IFileSystemNode
14 | {
15 | IpfsClient ipfsClient;
16 | IEnumerable links;
17 | long? size;
18 | bool? isDirectory;
19 |
20 | ///
21 | public byte[] DataBytes
22 | {
23 | get
24 | {
25 | using (var stream = DataStream)
26 | {
27 | if (DataStream == null)
28 | return null;
29 |
30 | using (var data = new MemoryStream())
31 | {
32 | stream.CopyTo(data);
33 | return data.ToArray();
34 | }
35 | }
36 | }
37 | }
38 |
39 | ///
40 | public Stream DataStream
41 | {
42 | get
43 | {
44 | return IpfsClient?.FileSystem.ReadFileAsync(Id).Result;
45 | }
46 | }
47 |
48 | ///
49 | [DataMember]
50 | public Cid Id { get; set; }
51 |
52 | ///
53 | [DataMember]
54 | public IEnumerable Links {
55 | get
56 | {
57 | if (links == null) GetInfo();
58 | return links;
59 | }
60 | set
61 | {
62 | links = value;
63 | }
64 | }
65 |
66 | ///
67 | /// Size of the file contents.
68 | ///
69 | ///
70 | /// This is the size of the file not the raw encoded contents
71 | /// of the block.
72 | ///
73 | [DataMember]
74 | public long Size
75 | {
76 | get
77 | {
78 | if (!size.HasValue) GetInfo();
79 | return size.Value;
80 | }
81 | set
82 | {
83 | size = value;
84 | }
85 | }
86 |
87 | ///
88 | /// Determines if the link is a directory (folder).
89 | ///
90 | ///
91 | /// true if the link is a directory; Otherwise false ,
92 | /// the link is some type of a file.
93 | ///
94 | [DataMember]
95 | public bool IsDirectory
96 | {
97 | get
98 | {
99 | if (!isDirectory.HasValue) GetInfo();
100 | return isDirectory.Value;
101 | }
102 | set
103 | {
104 | isDirectory = value;
105 | }
106 | }
107 |
108 | ///
109 | /// The file name of the IPFS node.
110 | ///
111 | [DataMember]
112 | public string Name { get; set; }
113 |
114 | ///
115 | public IFileSystemLink ToLink(string name = "")
116 | {
117 | var link = new FileSystemLink
118 | {
119 | Name = string.IsNullOrWhiteSpace(name) ? Name : name,
120 | Id = Id,
121 | Size = Size,
122 | };
123 | return link;
124 | }
125 |
126 | ///
127 | /// The client to IPFS.
128 | ///
129 | ///
130 | /// Used to fetch additional information on the node.
131 | ///
132 | public IpfsClient IpfsClient
133 | {
134 | get
135 | {
136 | if (ipfsClient == null)
137 | {
138 | lock (this)
139 | {
140 | ipfsClient = new IpfsClient();
141 | }
142 | }
143 | return ipfsClient;
144 | }
145 | set
146 | {
147 | ipfsClient = value;
148 | }
149 | }
150 |
151 | void GetInfo()
152 | {
153 | var node = IpfsClient.FileSystem.ListFileAsync(Id).Result;
154 | this.IsDirectory = node.IsDirectory;
155 | this.Links = node.Links;
156 | this.Size = node.Size;
157 | }
158 |
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/IpfsHttpClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard14;netstandard2;net45
5 | Ipfs.Http.Client
6 | Ipfs.Http
7 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
8 | full
9 | true
10 |
11 |
12 | 0.42
13 | 0.42
14 |
15 |
16 | Ipfs.Http.Client
17 | Richard Schneider
18 | IPFS HTTP Client
19 | Provides .Net client access to the InterPlanetary File System.
20 | false
21 | https://github.com/richardschneider/net-ipfs-http-client/releases
22 | © 2015-2019 Richard Schneider
23 | ipfs peer-to-peer distributed file-system
24 | True
25 | https://github.com/richardschneider/net-ipfs-http-client
26 | https://raw.githubusercontent.com/richardschneider/net-ipfs-core/master/doc/images/ipfs-cs-logo-64x64.png
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/MerkleNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Newtonsoft.Json.Linq;
6 | using System.IO;
7 | using System.Runtime.Serialization;
8 |
9 | namespace Ipfs.Http
10 | {
11 | ///
12 | /// The IPFS MerkleDag is the datastructure at the heart of IPFS. It is an acyclic directed graph whose edges are hashes.
13 | ///
14 | ///
15 | /// Initially an MerkleNode is just constructed with its Cid.
16 | ///
17 | [DataContract]
18 | public class MerkleNode : IMerkleNode, IEquatable
19 | {
20 | bool hasBlockStats;
21 | long blockSize;
22 | string name;
23 | IEnumerable links;
24 | IpfsClient ipfsClient;
25 |
26 | ///
27 | /// Creates a new instance of the with the specified
28 | /// and optional .
29 | ///
30 | ///
31 | /// The of the node.
32 | ///
33 | /// A name for the node.
34 | public MerkleNode(Cid id, string name = null)
35 | {
36 | if (id == null)
37 | throw new ArgumentNullException("id");
38 |
39 | Id = id;
40 | Name = name;
41 | }
42 |
43 | ///
44 | /// Creates a new instance of the with the specified
45 | /// cid and optional .
46 | ///
47 | ///
48 | /// The string representation of a of the node or "/ipfs/cid".
49 | ///
50 | /// A name for the node.
51 | public MerkleNode(string path, string name = null)
52 | {
53 | if (string.IsNullOrWhiteSpace(path))
54 | throw new ArgumentNullException("path");
55 |
56 | if (path.StartsWith("/ipfs/"))
57 | path = path.Substring(6);
58 |
59 | Id = Cid.Decode(path);
60 | Name = name;
61 | }
62 |
63 | ///
64 | /// Creates a new instance of the from the
65 | /// .
66 | ///
67 | /// The link to a node.
68 | public MerkleNode(IMerkleLink link)
69 | {
70 | Id = link.Id;
71 | Name = link.Name;
72 | blockSize = link.Size;
73 | hasBlockStats = true;
74 | }
75 |
76 | internal IpfsClient IpfsClient
77 | {
78 | get
79 | {
80 | if (ipfsClient == null)
81 | {
82 | lock (this)
83 | {
84 | ipfsClient = new IpfsClient();
85 | }
86 | }
87 | return ipfsClient;
88 | }
89 | set
90 | {
91 | ipfsClient = value;
92 | }
93 | }
94 |
95 | ///
96 | [DataMember]
97 | public Cid Id { get; private set; }
98 |
99 | ///
100 | /// The name for the node. If unknown it is "" (not null).
101 | ///
102 | [DataMember]
103 | public string Name
104 | {
105 | get { return name; }
106 | set { name = value ?? string.Empty; }
107 | }
108 |
109 | ///
110 | /// Size of the raw, encoded node.
111 | ///
112 | [DataMember]
113 | public long BlockSize
114 | {
115 | get
116 | {
117 | GetBlockStats();
118 | return blockSize;
119 | }
120 | }
121 |
122 | ///
123 | ///
124 | [DataMember]
125 | public long Size
126 | {
127 | get
128 | {
129 | return BlockSize;
130 | }
131 | }
132 |
133 |
134 | ///
135 | [DataMember]
136 | public IEnumerable Links
137 | {
138 | get
139 | {
140 | if (links == null)
141 | {
142 | links = IpfsClient.Object.LinksAsync(Id).Result;
143 | }
144 |
145 | return links;
146 | }
147 | }
148 |
149 | ///
150 | [DataMember]
151 | public byte[] DataBytes
152 | {
153 | get
154 | {
155 | return IpfsClient.Block.GetAsync(Id).Result.DataBytes;
156 | }
157 | }
158 |
159 | ///
160 | public Stream DataStream
161 | {
162 | get
163 | {
164 | return IpfsClient.Block.GetAsync(Id).Result.DataStream;
165 | }
166 | }
167 |
168 | ///
169 | public IMerkleLink ToLink(string name = null)
170 | {
171 | return new DagLink(name ?? Name, Id, BlockSize);
172 | }
173 |
174 | ///
175 | /// Get block statistics about the node, ipfs block stat key
176 | ///
177 | ///
178 | /// The object stats include the block stats.
179 | ///
180 | void GetBlockStats()
181 | {
182 | if (hasBlockStats)
183 | return;
184 |
185 | var stats = IpfsClient.Block.StatAsync(Id).Result;
186 | blockSize = stats.Size;
187 |
188 | hasBlockStats = true;
189 | }
190 |
191 | ///
192 | public override int GetHashCode()
193 | {
194 | return Id.GetHashCode();
195 | }
196 |
197 | ///
198 | public override bool Equals(object obj)
199 | {
200 | var that = obj as MerkleNode;
201 | return that != null && this.Id == that.Id;
202 | }
203 |
204 | ///
205 | public bool Equals(MerkleNode that)
206 | {
207 | return that != null && this.Id == that.Id;
208 | }
209 |
210 | ///
211 | /// TODO
212 | ///
213 | public static bool operator ==(MerkleNode a, MerkleNode b)
214 | {
215 | if (object.ReferenceEquals(a, b)) return true;
216 | if (object.ReferenceEquals(a, null)) return false;
217 | if (object.ReferenceEquals(b, null)) return false;
218 |
219 | return a.Equals(b);
220 | }
221 |
222 | ///
223 | /// TODO
224 | ///
225 | public static bool operator !=(MerkleNode a, MerkleNode b)
226 | {
227 | if (object.ReferenceEquals(a, b)) return false;
228 | if (object.ReferenceEquals(a, null)) return true;
229 | if (object.ReferenceEquals(b, null)) return true;
230 |
231 | return !a.Equals(b);
232 | }
233 |
234 | ///
235 | public override string ToString()
236 | {
237 | return "/ipfs/" + Id;
238 | }
239 |
240 | ///
241 | /// TODO
242 | ///
243 | static public implicit operator MerkleNode(string hash)
244 | {
245 | return new MerkleNode(hash);
246 | }
247 |
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/src/PublishedMessage.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json.Linq;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.IO;
6 | using System.Text;
7 | using System.Runtime.Serialization;
8 |
9 | namespace Ipfs.Http
10 | {
11 | ///
12 | /// A published message.
13 | ///
14 | ///
15 | /// The is used to publish and subsribe to a message.
16 | ///
17 | [DataContract]
18 | public class PublishedMessage : IPublishedMessage
19 | {
20 | ///
21 | /// Creates a new instance of from the
22 | /// specified JSON string.
23 | ///
24 | ///
25 | /// The JSON representation of a published message.
26 | ///
27 | public PublishedMessage(string json)
28 | {
29 | 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"]);
33 | var topics = (JArray) (o["topicIDs"]);
34 | this.Topics = topics.Select(t => (string)t);
35 | }
36 |
37 | ///
38 | [DataMember]
39 | public Peer Sender { get; private set; }
40 |
41 | ///
42 | [DataMember]
43 | public IEnumerable Topics { get; private set; }
44 |
45 | ///
46 | [DataMember]
47 | public byte[] SequenceNumber { get; private set; }
48 |
49 | ///
50 | [DataMember]
51 | public byte[] DataBytes { get; private set; }
52 |
53 | ///
54 | public Stream DataStream
55 | {
56 | get
57 | {
58 | return new MemoryStream(DataBytes, false);
59 | }
60 | }
61 |
62 | ///
63 | [DataMember]
64 | public long Size
65 | {
66 | get { return DataBytes.Length; }
67 | }
68 | ///
69 | /// Contents as a string.
70 | ///
71 | ///
72 | /// The contents interpreted as a UTF-8 string.
73 | ///
74 | public string DataString
75 | {
76 | get
77 | {
78 | return Encoding.UTF8.GetString(DataBytes);
79 | }
80 | }
81 |
82 | /// >
83 | /// NOT SUPPORTED.
84 | ///
85 | ///
86 | /// A published message does not have a content id.
87 | ///
88 | public Cid Id => throw new NotSupportedException();
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/TrustedPeerCollection.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.IO;
8 | using System.Net;
9 | using System.Threading;
10 |
11 | namespace Ipfs.Http
12 | {
13 | ///
14 | /// A list of trusted peers.
15 | ///
16 | ///
17 | /// This is the list of peers that are initially trusted by IPFS. Its equivalent to the
18 | /// ipfs bootstrap command.
19 | ///
20 | ///
21 | /// A series of . Each address ends with an IPNS node id, for
22 | /// example "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ".
23 | ///
24 | public class TrustedPeerCollection : ICollection
25 | {
26 | class BootstrapListResponse
27 | {
28 | public MultiAddress[] Peers { get; set; }
29 | }
30 |
31 | IpfsClient ipfs;
32 | MultiAddress[] peers;
33 |
34 | internal TrustedPeerCollection(IpfsClient ipfs)
35 | {
36 | this.ipfs = ipfs;
37 | }
38 |
39 | ///
40 | public void Add(MultiAddress peer)
41 | {
42 | if (peer == null)
43 | throw new ArgumentNullException();
44 |
45 | ipfs.DoCommandAsync("bootstrap/add", default(CancellationToken), peer.ToString()).Wait();
46 | peers = null;
47 | }
48 |
49 | ///
50 | /// Add the default bootstrap nodes to the trusted peers.
51 | ///
52 | ///
53 | /// Equivalent to ipfs bootstrap add --default .
54 | ///
55 | public void AddDefaultNodes()
56 | {
57 | ipfs.DoCommandAsync("bootstrap/add", default(CancellationToken), null, "default=true").Wait();
58 | peers = null;
59 | }
60 |
61 | ///
62 | /// Remove all the trusted peers.
63 | ///
64 | ///
65 | /// Equivalent to ipfs bootstrap rm --all .
66 | ///
67 | public void Clear()
68 | {
69 | ipfs.DoCommandAsync("bootstrap/rm", default(CancellationToken), null, "all=true").Wait();
70 | peers = null;
71 | }
72 |
73 | ///
74 | public bool Contains(MultiAddress item)
75 | {
76 | Fetch();
77 | return peers.Contains(item);
78 | }
79 |
80 | ///
81 | public void CopyTo(MultiAddress[] array, int index)
82 | {
83 | Fetch();
84 | peers.CopyTo(array, index);
85 | }
86 |
87 | ///
88 | public int Count
89 | {
90 | get
91 | {
92 | if (peers == null)
93 | Fetch();
94 | return peers.Count();
95 | }
96 | }
97 |
98 | ///
99 | public bool IsReadOnly
100 | {
101 | get { return false; }
102 | }
103 |
104 | ///
105 | /// Remove the trusted peer.
106 | ///
107 | ///
108 | /// Equivalent to ipfs bootstrap rm peer .
109 | ///
110 | public bool Remove(MultiAddress peer)
111 | {
112 | if (peer == null)
113 | throw new ArgumentNullException();
114 |
115 | ipfs.DoCommandAsync("bootstrap/rm", default(CancellationToken), peer.ToString()).Wait();
116 | peers = null;
117 | return true;
118 | }
119 |
120 | ///
121 | public IEnumerator GetEnumerator()
122 | {
123 | Fetch();
124 | return ((IEnumerable) peers).GetEnumerator();
125 | }
126 |
127 | ///
128 | IEnumerator IEnumerable.GetEnumerator()
129 | {
130 | Fetch();
131 | return peers.GetEnumerator();
132 | }
133 |
134 | void Fetch()
135 | {
136 | peers = ipfs.DoCommandAsync("bootstrap/list", default(CancellationToken)).Result.Peers;
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/test/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/test/BlockTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.Linq;
5 |
6 | namespace Ipfs.Http
7 | {
8 |
9 | [TestClass]
10 | public class BlockTest
11 | {
12 | byte[] someBytes = new byte[] { 1, 2, 3 };
13 |
14 | [TestMethod]
15 | public void DataBytes()
16 | {
17 | var block = new Block
18 | {
19 | DataBytes = someBytes
20 | };
21 | CollectionAssert.AreEqual(someBytes, block.DataBytes);
22 | }
23 |
24 | [TestMethod]
25 | public void DataStream()
26 | {
27 | var block = new Block
28 | {
29 | DataBytes = someBytes
30 | };
31 | var stream = block.DataStream;
32 | Assert.AreEqual(1, stream.ReadByte());
33 | Assert.AreEqual(2, stream.ReadByte());
34 | Assert.AreEqual(3, stream.ReadByte());
35 | Assert.AreEqual(-1, stream.ReadByte(), "at eof");
36 | }
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/test/CoreApi/BitswapApiTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs.Http
10 | {
11 |
12 | [TestClass]
13 | public class BitswapApiTest
14 | {
15 | IpfsClient ipfs = TestFixture.Ipfs;
16 |
17 | [TestMethod]
18 | public async Task Wants()
19 | {
20 | var block = new DagNode(Encoding.UTF8.GetBytes("BitswapApiTest unknown block"));
21 | #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
22 | Task.Run(() => ipfs.Bitswap.GetAsync(block.Id).Wait());
23 |
24 | var endTime = DateTime.Now.AddSeconds(10);
25 | while (DateTime.Now < endTime)
26 | {
27 | await Task.Delay(100);
28 | var wants = await ipfs.Bitswap.WantsAsync();
29 | if (wants.Contains(block.Id))
30 | return;
31 | }
32 | Assert.Fail("wanted block is missing");
33 | }
34 |
35 | [TestMethod]
36 | [Ignore("https://github.com/ipfs/go-ipfs/issues/5295")]
37 | public async Task Unwant()
38 | {
39 | var block = new DagNode(Encoding.UTF8.GetBytes("BitswapApiTest unknown block 2"));
40 | #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
41 | Task.Run(() => ipfs.Bitswap.GetAsync(block.Id).Wait());
42 |
43 | var endTime = DateTime.Now.AddSeconds(10);
44 | while (true)
45 | {
46 | if (DateTime.Now > endTime)
47 | Assert.Fail("wanted block is missing");
48 | await Task.Delay(100);
49 | var wants = await ipfs.Bitswap.WantsAsync();
50 | if (wants.Contains(block.Id))
51 | break;
52 | }
53 |
54 | await ipfs.Bitswap.UnwantAsync(block.Id);
55 | endTime = DateTime.Now.AddSeconds(10);
56 | while (true)
57 | {
58 | if (DateTime.Now > endTime)
59 | Assert.Fail("unwanted block is present");
60 | await Task.Delay(100);
61 | var wants = await ipfs.Bitswap.WantsAsync();
62 | if (!wants.Contains(block.Id))
63 | break;
64 | }
65 | }
66 |
67 | [TestMethod]
68 | public async Task Ledger()
69 | {
70 | var peer = new Peer { Id = "QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3" };
71 | var ledger = await ipfs.Bitswap.LedgerAsync(peer);
72 | Assert.IsNotNull(ledger);
73 | Assert.AreEqual(peer.Id, ledger.Peer.Id);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/test/CoreApi/BlockApiTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs.Http
10 | {
11 |
12 | [TestClass]
13 | public class BlockApiTest
14 | {
15 | IpfsClient ipfs = TestFixture.Ipfs;
16 | string id = "QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ";
17 | byte[] blob = Encoding.UTF8.GetBytes("blorb");
18 |
19 | [TestMethod]
20 | public void Put_Bytes()
21 | {
22 | var cid = ipfs.Block.PutAsync(blob).Result;
23 | Assert.AreEqual(id, (string)cid);
24 |
25 | var data = ipfs.Block.GetAsync(cid).Result;
26 | Assert.AreEqual(blob.Length, data.Size);
27 | CollectionAssert.AreEqual(blob, data.DataBytes);
28 | }
29 |
30 | [TestMethod]
31 | public void Put_Bytes_ContentType()
32 | {
33 | var cid = ipfs.Block.PutAsync(blob, contentType: "raw").Result;
34 | Assert.AreEqual("bafkreiaxnnnb7qz2focittuqq3ya25q7rcv3bqynnczfzako47346wosmu", (string)cid);
35 |
36 | var data = ipfs.Block.GetAsync(cid).Result;
37 | Assert.AreEqual(blob.Length, data.Size);
38 | CollectionAssert.AreEqual(blob, data.DataBytes);
39 | }
40 |
41 | [TestMethod]
42 | public void Put_Bytes_Hash()
43 | {
44 | var cid = ipfs.Block.PutAsync(blob, "raw", "sha2-512").Result;
45 | Assert.AreEqual("bafkrgqelljziv4qfg5mefz36m2y3h6voaralnw6lwb4f53xcnrf4mlsykkn7vt6eno547tw5ygcz62kxrle45wnbmpbofo5tvu57jvuaf7k7e", (string)cid);
46 |
47 | var data = ipfs.Block.GetAsync(cid).Result;
48 | Assert.AreEqual(blob.Length, data.Size);
49 | CollectionAssert.AreEqual(blob, data.DataBytes);
50 | }
51 |
52 | [TestMethod]
53 | public void Put_Bytes_Pinned()
54 | {
55 | var data1 = new byte[] { 23, 24, 127 };
56 | var cid1 = ipfs.Block.PutAsync(data1, contentType: "raw", pin: true).Result;
57 | var pins = ipfs.Pin.ListAsync().Result;
58 | Assert.IsTrue(pins.Any(pin => pin == cid1));
59 |
60 | var data2 = new byte[] { 123, 124, 27 };
61 | var cid2 = ipfs.Block.PutAsync(data2, contentType: "raw", pin: false).Result;
62 | pins = ipfs.Pin.ListAsync().Result;
63 | Assert.IsFalse(pins.Any(pin => pin == cid2));
64 | }
65 |
66 | [TestMethod]
67 | public void Put_Stream()
68 | {
69 | var cid = ipfs.Block.PutAsync(new MemoryStream(blob)).Result;
70 | Assert.AreEqual(id, (string)cid);
71 |
72 | var data = ipfs.Block.GetAsync(cid).Result;
73 | Assert.AreEqual(blob.Length, data.Size);
74 | CollectionAssert.AreEqual(blob, data.DataBytes);
75 | }
76 |
77 | [TestMethod]
78 | public void Put_Stream_ContentType()
79 | {
80 | var cid = ipfs.Block.PutAsync(new MemoryStream(blob), contentType: "raw").Result;
81 | Assert.AreEqual("bafkreiaxnnnb7qz2focittuqq3ya25q7rcv3bqynnczfzako47346wosmu", (string)cid);
82 |
83 | var data = ipfs.Block.GetAsync(cid).Result;
84 | Assert.AreEqual(blob.Length, data.Size);
85 | CollectionAssert.AreEqual(blob, data.DataBytes);
86 | }
87 |
88 | [TestMethod]
89 | public void Put_Stream_Hash()
90 | {
91 | var cid = ipfs.Block.PutAsync(new MemoryStream(blob), "raw", "sha2-512").Result;
92 | Assert.AreEqual("bafkrgqelljziv4qfg5mefz36m2y3h6voaralnw6lwb4f53xcnrf4mlsykkn7vt6eno547tw5ygcz62kxrle45wnbmpbofo5tvu57jvuaf7k7e", (string)cid);
93 |
94 | var data = ipfs.Block.GetAsync(cid).Result;
95 | Assert.AreEqual(blob.Length, data.Size);
96 | CollectionAssert.AreEqual(blob, data.DataBytes);
97 | }
98 |
99 | [TestMethod]
100 | public void Put_Stream_Pinned()
101 | {
102 | var data1 = new MemoryStream(new byte[] { 23, 24, 127 });
103 | var cid1 = ipfs.Block.PutAsync(data1, contentType: "raw", pin: true).Result;
104 | var pins = ipfs.Pin.ListAsync().Result;
105 | Assert.IsTrue(pins.Any(pin => pin == cid1));
106 |
107 | var data2 = new MemoryStream(new byte[] { 123, 124, 27 });
108 | var cid2 = ipfs.Block.PutAsync(data2, contentType: "raw", pin: false).Result;
109 | pins = ipfs.Pin.ListAsync().Result;
110 | Assert.IsFalse(pins.Any(pin => pin == cid2));
111 | }
112 |
113 | [TestMethod]
114 | public void Get()
115 | {
116 | var _ = ipfs.Block.PutAsync(blob).Result;
117 | var block = ipfs.Block.GetAsync(id).Result;
118 | Assert.AreEqual(id, (string)block.Id);
119 | CollectionAssert.AreEqual(blob, block.DataBytes);
120 | var blob1 = new byte[blob.Length];
121 | block.DataStream.Read(blob1, 0, blob1.Length);
122 | CollectionAssert.AreEqual(blob, blob1);
123 | }
124 |
125 | [TestMethod]
126 | public void Stat()
127 | {
128 | var _ = ipfs.Block.PutAsync(blob).Result;
129 | var info = ipfs.Block.StatAsync(id).Result;
130 | Assert.AreEqual(id, (string)info.Id);
131 | Assert.AreEqual(5, info.Size);
132 | }
133 |
134 | [TestMethod]
135 | public async Task Remove()
136 | {
137 | var _ = ipfs.Block.PutAsync(blob).Result;
138 | var cid = await ipfs.Block.RemoveAsync(id);
139 | Assert.AreEqual(id, (string)cid);
140 | }
141 |
142 | [TestMethod]
143 | public void Remove_Unknown()
144 | {
145 | ExceptionAssert.Throws(() => { var _ = ipfs.Block.RemoveAsync("QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rFF").Result; });
146 | }
147 |
148 | [TestMethod]
149 | public async Task Remove_Unknown_OK()
150 | {
151 | var cid = await ipfs.Block.RemoveAsync("QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rFF", true);
152 | }
153 |
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/test/CoreApi/BlockRepositoryTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Ipfs.Http
9 | {
10 |
11 | [TestClass]
12 | public class BlockRepositoryTest
13 | {
14 |
15 | [TestMethod]
16 | public async Task Stats()
17 | {
18 | var ipfs = TestFixture.Ipfs;
19 | var stats = await ipfs.BlockRepository.StatisticsAsync();
20 | Assert.IsNotNull(stats);
21 | }
22 |
23 | [TestMethod]
24 | public async Task Version()
25 | {
26 | var ipfs = TestFixture.Ipfs;
27 | var version = await ipfs.BlockRepository.VersionAsync();
28 | Assert.IsFalse(string.IsNullOrWhiteSpace(version));
29 | }
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/test/CoreApi/BootstrapTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs.Http
10 | {
11 |
12 | [TestClass]
13 | public class BootstapApiTest
14 | {
15 | IpfsClient ipfs = TestFixture.Ipfs;
16 | MultiAddress somewhere = "/ip4/127.0.0.1/tcp/4009/ipfs/QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ";
17 |
18 | [TestMethod]
19 | public async Task Add_Remove()
20 | {
21 | var addr = await ipfs.Bootstrap.AddAsync(somewhere);
22 | Assert.IsNotNull(addr);
23 | Assert.AreEqual(somewhere, addr);
24 | var addrs = await ipfs.Bootstrap.ListAsync();
25 | Assert.IsTrue(addrs.Any(a => a == somewhere));
26 |
27 | addr = await ipfs.Bootstrap.RemoveAsync(somewhere);
28 | Assert.IsNotNull(addr);
29 | Assert.AreEqual(somewhere, addr);
30 | addrs = await ipfs.Bootstrap.ListAsync();
31 | Assert.IsFalse(addrs.Any(a => a == somewhere));
32 | }
33 |
34 | [TestMethod]
35 | public async Task List()
36 | {
37 | var addrs = await ipfs.Bootstrap.ListAsync();
38 | Assert.IsNotNull(addrs);
39 | Assert.AreNotEqual(0, addrs.Count());
40 | }
41 |
42 | [TestMethod]
43 | public async Task Remove_All()
44 | {
45 | var original = await ipfs.Bootstrap.ListAsync();
46 | await ipfs.Bootstrap.RemoveAllAsync();
47 | var addrs = await ipfs.Bootstrap.ListAsync();
48 | Assert.AreEqual(0, addrs.Count());
49 | foreach (var addr in original)
50 | {
51 | await ipfs.Bootstrap.AddAsync(addr);
52 | }
53 | }
54 |
55 | [TestMethod]
56 | public async Task Add_Defaults()
57 | {
58 | var original = await ipfs.Bootstrap.ListAsync();
59 | await ipfs.Bootstrap.RemoveAllAsync();
60 | try
61 | {
62 | await ipfs.Bootstrap.AddDefaultsAsync();
63 | var addrs = await ipfs.Bootstrap.ListAsync();
64 | Assert.AreNotEqual(0, addrs.Count());
65 | }
66 | finally
67 | {
68 | await ipfs.Bootstrap.RemoveAllAsync();
69 | foreach (var addr in original)
70 | {
71 | await ipfs.Bootstrap.AddAsync(addr);
72 | }
73 | }
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/test/CoreApi/CancellationTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Newtonsoft.Json.Linq;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs.Http
10 | {
11 | [TestClass]
12 | public class CancellationTest
13 | {
14 | [TestMethod]
15 | public async Task Cancel_Operation()
16 | {
17 | var ipfs = TestFixture.Ipfs;
18 | var cs = new CancellationTokenSource(500);
19 | try
20 | {
21 | await Task.Delay(1000);
22 | var result = await ipfs.IdAsync(cancel: cs.Token);
23 | Assert.Fail("Did not throw TaskCanceledException");
24 | }
25 | catch (TaskCanceledException)
26 | {
27 | return;
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/CoreApi/ConfigApiTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Ipfs.Http
9 | {
10 |
11 | [TestClass]
12 | public class ConfigApiTest
13 | {
14 | const string apiAddress = "/ip4/127.0.0.1/tcp/";
15 | const string gatewayAddress = "/ip4/127.0.0.1/tcp/";
16 |
17 | [TestMethod]
18 | public void Get_Entire_Config()
19 | {
20 | IpfsClient ipfs = TestFixture.Ipfs;
21 | var config = ipfs.Config.GetAsync().Result;
22 | StringAssert.StartsWith(config["Addresses"]["API"].Value(), apiAddress);
23 | }
24 |
25 | [TestMethod]
26 | public void Get_Scalar_Key_Value()
27 | {
28 | IpfsClient ipfs = TestFixture.Ipfs;
29 | var api = ipfs.Config.GetAsync("Addresses.API").Result;
30 | StringAssert.StartsWith(api.Value(), apiAddress);
31 | }
32 |
33 | [TestMethod]
34 | public void Get_Object_Key_Value()
35 | {
36 | IpfsClient ipfs = TestFixture.Ipfs;
37 | var addresses = ipfs.Config.GetAsync("Addresses").Result;
38 | StringAssert.StartsWith(addresses["API"].Value(), apiAddress);
39 | StringAssert.StartsWith(addresses["Gateway"].Value(), gatewayAddress);
40 | }
41 |
42 | [TestMethod]
43 | public void Keys_are_Case_Sensitive()
44 | {
45 | IpfsClient ipfs = TestFixture.Ipfs;
46 | var api = ipfs.Config.GetAsync("Addresses.API").Result;
47 | StringAssert.StartsWith(api.Value(), apiAddress);
48 |
49 | ExceptionAssert.Throws(() => { var x = ipfs.Config.GetAsync("Addresses.api").Result; });
50 | }
51 |
52 | [TestMethod]
53 | public void Set_String_Value()
54 | {
55 | const string key = "foo";
56 | const string value = "foobar";
57 | IpfsClient ipfs = TestFixture.Ipfs;
58 | ipfs.Config.SetAsync(key, value).Wait();
59 | Assert.AreEqual(value, ipfs.Config.GetAsync(key).Result);
60 | }
61 |
62 | [TestMethod]
63 | public void Set_JSON_Value()
64 | {
65 | const string key = "API.HTTPHeaders.Access-Control-Allow-Origin";
66 | JToken value = JToken.Parse("['http://example.io']");
67 | IpfsClient ipfs = TestFixture.Ipfs;
68 | ipfs.Config.SetAsync(key, value).Wait();
69 | Assert.AreEqual("http://example.io", ipfs.Config.GetAsync(key).Result[0]);
70 | }
71 |
72 | [TestMethod]
73 | public async Task Replace_Entire_Config()
74 | {
75 | IpfsClient ipfs = TestFixture.Ipfs;
76 | var original = await ipfs.Config.GetAsync();
77 | try
78 | {
79 | var a = JObject.Parse("{ \"foo-x-bar\": 1 }");
80 | await ipfs.Config.ReplaceAsync(a);
81 | }
82 | finally
83 | {
84 | await ipfs.Config.ReplaceAsync(original);
85 | }
86 | }
87 |
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/test/CoreApi/DagApiTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.Http
8 | {
9 | [TestClass]
10 | public class DagApiTest
11 | {
12 | class Name
13 | {
14 | public string First { get; set; }
15 | public string Last { get; set; }
16 | }
17 |
18 | [TestMethod]
19 | public async Task PutAndGet_JSON()
20 | {
21 | var ipfs = TestFixture.Ipfs;
22 | var expected = new JObject();
23 | expected["a"] = "alpha";
24 | var expectedId = "bafyreigdhej736dobd6z3jt2vxsxvbwrwgyts7e7wms6yrr46rp72uh5bu";
25 | var id = await ipfs.Dag.PutAsync(expected);
26 | Assert.IsNotNull(id);
27 | Assert.AreEqual(expectedId, (string)id);
28 |
29 | var actual = await ipfs.Dag.GetAsync(id);
30 | Assert.IsNotNull(actual);
31 | Assert.AreEqual(expected["a"], actual["a"]);
32 |
33 | var value = (string) await ipfs.Dag.GetAsync(expectedId + "/a");
34 | Assert.AreEqual(expected["a"], value);
35 | }
36 |
37 | [TestMethod]
38 | public async Task PutAndGet_POCO()
39 | {
40 | var ipfs = TestFixture.Ipfs;
41 | var expected = new Name { First = "John", Last = "Smith" };
42 | var id = await ipfs.Dag.PutAsync(expected);
43 | Assert.IsNotNull(id);
44 |
45 | var actual = await ipfs.Dag.GetAsync(id);
46 | Assert.IsNotNull(actual);
47 | Assert.AreEqual(expected.First, actual.First);
48 | Assert.AreEqual(expected.Last, actual.Last);
49 |
50 | var value = (string)await ipfs.Dag.GetAsync(id.Encode() + "/Last");
51 | Assert.AreEqual(expected.Last, value);
52 | }
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/test/CoreApi/DhtApiTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs.Http
10 | {
11 |
12 | [TestClass]
13 | public class DhtApiTest
14 | {
15 | const string helloWorldID = "QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o";
16 |
17 | [TestMethod]
18 | public async Task FindPeer()
19 | {
20 | var ipfs = TestFixture.Ipfs;
21 | var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));
22 | var mars = await ipfs.Dht.FindPeerAsync("QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", cts.Token);
23 | Assert.IsNotNull(mars);
24 | }
25 |
26 | [TestMethod]
27 | public async Task FindProviders()
28 | {
29 | var ipfs = TestFixture.Ipfs;
30 | var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));
31 | var providers = await ipfs.Dht.FindProvidersAsync(helloWorldID, 1, cancel: cts.Token);
32 | Assert.AreNotEqual(0, providers.Count());
33 | }
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/test/CoreApi/DnsApiTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ipfs.Http
11 | {
12 |
13 | [TestClass]
14 | public class DnsApiTest
15 | {
16 |
17 | [TestMethod]
18 | public void Api_Exists()
19 | {
20 | IpfsClient ipfs = TestFixture.Ipfs;
21 | Assert.IsNotNull(ipfs.Dns);
22 | }
23 |
24 | [TestMethod]
25 | public async Task Resolve()
26 | {
27 | IpfsClient ipfs = TestFixture.Ipfs;
28 | var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
29 | var path = await ipfs.Dns.ResolveAsync("ipfs.io", recursive: true, cancel: cts.Token);
30 | StringAssert.StartsWith(path, "/ipfs/");
31 | }
32 |
33 | [TestMethod]
34 | [Ignore("takes forever")]
35 | public async Task Publish()
36 | {
37 | var ipfs = TestFixture.Ipfs;
38 | var cs = new CancellationTokenSource(TimeSpan.FromMinutes(5));
39 | var content = await ipfs.FileSystem.AddTextAsync("hello world");
40 | var key = await ipfs.Key.CreateAsync("name-publish-test", "rsa", 1024);
41 | try
42 | {
43 | var result = await ipfs.Name.PublishAsync(content.Id, key.Name, cancel: cs.Token);
44 | Assert.IsNotNull(result);
45 | StringAssert.EndsWith(result.NamePath, key.Id.ToString());
46 | StringAssert.EndsWith(result.ContentPath, content.Id.Encode());
47 | }
48 | finally
49 | {
50 | await ipfs.Key.RemoveAsync(key.Name);
51 | }
52 | }
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/test/CoreApi/GenericApiTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System.Linq;
3 | using System;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.Http
8 | {
9 | [TestClass]
10 | public class GenericApiTest
11 | {
12 | [TestMethod]
13 | public void Local_Node_Info()
14 | {
15 | var ipfs = TestFixture.Ipfs;
16 | var node = ipfs.IdAsync().Result;
17 | Assert.IsInstanceOfType(node, typeof(Peer));
18 | }
19 |
20 | [TestMethod]
21 | public async Task Peer_Node_Info()
22 | {
23 | var ipfs = TestFixture.Ipfs;
24 | var mars = await ipfs.IdAsync("QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3");
25 | Assert.IsNotNull(mars);
26 | }
27 |
28 | [TestMethod]
29 | public void Version_Info()
30 | {
31 | var ipfs = TestFixture.Ipfs;
32 | var versions = ipfs.VersionAsync().Result;
33 | Assert.IsNotNull(versions);
34 | Assert.IsTrue(versions.ContainsKey("Version"));
35 | Assert.IsTrue(versions.ContainsKey("Repo"));
36 | }
37 |
38 | [TestMethod]
39 | public void Resolve()
40 | {
41 | var ipfs = TestFixture.Ipfs;
42 | var path = ipfs.ResolveAsync("QmYNQJoKGNHTpPxCBPh9KkDpaExgd2duMa3aF6ytMpHdao").Result;
43 | Assert.AreEqual("/ipfs/QmYNQJoKGNHTpPxCBPh9KkDpaExgd2duMa3aF6ytMpHdao", path);
44 | }
45 |
46 | [TestMethod]
47 | public async Task Ping_Peer()
48 | {
49 | var ipfs = TestFixture.Ipfs;
50 | MultiHash peer = "QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3";
51 | var actual = await ipfs.Generic.PingAsync(peer, count: 1);
52 | Assert.IsNotNull(actual);
53 | Assert.AreNotEqual(0, actual.Count());
54 | }
55 |
56 | [TestMethod]
57 | public async Task Ping_Address()
58 | {
59 | var ipfs = TestFixture.Ipfs;
60 | MultiAddress addr = "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM";
61 | var actual = await ipfs.Generic.PingAsync(addr, count: 1);
62 | Assert.IsNotNull(actual);
63 | Assert.AreNotEqual(0, actual.Count());
64 | }
65 | }
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/test/CoreApi/KeyApiTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ipfs.Http
11 | {
12 |
13 | [TestClass]
14 | public class KeyApiTest
15 | {
16 |
17 | [TestMethod]
18 | public void Api_Exists()
19 | {
20 | IpfsClient ipfs = TestFixture.Ipfs;
21 | Assert.IsNotNull(ipfs.Key);
22 | }
23 |
24 | [TestMethod]
25 | public async Task Self_Key_Exists()
26 | {
27 | IpfsClient ipfs = TestFixture.Ipfs;
28 | var keys = await ipfs.Key.ListAsync();
29 | var self = keys.Single(k => k.Name == "self");
30 | var me = await ipfs.IdAsync();
31 | Assert.AreEqual("self", self.Name);
32 | Assert.AreEqual(me.Id, self.Id);
33 | }
34 |
35 | [TestMethod]
36 | public async Task Create_RSA_Key()
37 | {
38 | var name = "net-api-test-create";
39 | IpfsClient ipfs = TestFixture.Ipfs;
40 | var key = await ipfs.Key.CreateAsync(name, "rsa", 1024);
41 | try
42 | {
43 | Assert.IsNotNull(key);
44 | Assert.IsNotNull(key.Id);
45 | Assert.AreEqual(name, key.Name);
46 |
47 | var keys = await ipfs.Key.ListAsync();
48 | var clone = keys.Single(k => k.Name == name);
49 | Assert.AreEqual(key.Name, clone.Name);
50 | Assert.AreEqual(key.Id, clone.Id);
51 | }
52 | finally
53 | {
54 | await ipfs.Key.RemoveAsync(name);
55 | }
56 | }
57 |
58 | [TestMethod]
59 | public async Task Remove_Key()
60 | {
61 | var name = "net-api-test-remove";
62 | IpfsClient ipfs = TestFixture.Ipfs;
63 | var key = await ipfs.Key.CreateAsync(name, "rsa", 1024);
64 | var keys = await ipfs.Key.ListAsync();
65 | var clone = keys.Single(k => k.Name == name);
66 | Assert.IsNotNull(clone);
67 |
68 | var removed = await ipfs.Key.RemoveAsync(name);
69 | Assert.IsNotNull(removed);
70 | Assert.AreEqual(key.Name, removed.Name);
71 | Assert.AreEqual(key.Id, removed.Id);
72 |
73 | keys = await ipfs.Key.ListAsync();
74 | Assert.IsFalse(keys.Any(k => k.Name == name));
75 | }
76 |
77 | [TestMethod]
78 | public async Task Rename_Key()
79 | {
80 | var oname = "net-api-test-rename1";
81 | var rname = "net-api-test-rename2";
82 | IpfsClient ipfs = TestFixture.Ipfs;
83 | var okey = await ipfs.Key.CreateAsync(oname, "rsa", 1024);
84 | try
85 | {
86 | Assert.AreEqual(oname, okey.Name);
87 |
88 | var rkey = await ipfs.Key.RenameAsync(oname, rname);
89 | Assert.AreEqual(okey.Id, rkey.Id);
90 | Assert.AreEqual(rname, rkey.Name);
91 |
92 | var keys = await ipfs.Key.ListAsync();
93 | Assert.IsTrue(keys.Any(k => k.Name == rname));
94 | Assert.IsFalse(keys.Any(k => k.Name == oname));
95 | }
96 | finally
97 | {
98 | try
99 | {
100 | await ipfs.Key.RemoveAsync(oname);
101 | }
102 | catch (Exception) { }
103 | try
104 | {
105 | await ipfs.Key.RemoveAsync(rname);
106 | }
107 | catch (Exception) { }
108 | }
109 | }
110 |
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/test/CoreApi/NameApiTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ipfs.Http
11 | {
12 |
13 | [TestClass]
14 | public class NameApiTest
15 | {
16 |
17 | [TestMethod]
18 | public void Api_Exists()
19 | {
20 | IpfsClient ipfs = TestFixture.Ipfs;
21 | Assert.IsNotNull(ipfs.Name);
22 | }
23 |
24 | [TestMethod]
25 | public async Task Resolve()
26 | {
27 | IpfsClient ipfs = TestFixture.Ipfs;
28 | var id = await ipfs.Name.ResolveAsync("ipfs.io", recursive: true);
29 | StringAssert.StartsWith(id, "/ipfs/");
30 | }
31 |
32 | [TestMethod]
33 | [Ignore("takes forever")]
34 | public async Task Publish()
35 | {
36 | var ipfs = TestFixture.Ipfs;
37 | var cs = new CancellationTokenSource(TimeSpan.FromMinutes(5));
38 | var content = await ipfs.FileSystem.AddTextAsync("hello world");
39 | var key = await ipfs.Key.CreateAsync("name-publish-test", "rsa", 1024);
40 | try
41 | {
42 | var result = await ipfs.Name.PublishAsync(content.Id, key.Name, cancel: cs.Token);
43 | Assert.IsNotNull(result);
44 | StringAssert.EndsWith(result.NamePath, key.Id.ToString());
45 | StringAssert.EndsWith(result.ContentPath, content.Id.Encode());
46 | }
47 | finally
48 | {
49 | await ipfs.Key.RemoveAsync(key.Name);
50 | }
51 | }
52 |
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/test/CoreApi/ObjectApiTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ipfs.Http
11 | {
12 |
13 | [TestClass]
14 | public class ObjectApiTest
15 | {
16 | IpfsClient ipfs = TestFixture.Ipfs;
17 |
18 | [TestMethod]
19 | public async Task New_Template_Null()
20 | {
21 | var node = await ipfs.Object.NewAsync();
22 | Assert.AreEqual("QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n", (string)node.Id);
23 | }
24 |
25 | [TestMethod]
26 | public async Task New_Template_UnixfsDir()
27 | {
28 | var node = await ipfs.Object.NewAsync("unixfs-dir");
29 | Assert.AreEqual("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn", (string)node.Id);
30 |
31 | node = await ipfs.Object.NewDirectoryAsync();
32 | Assert.AreEqual("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn", (string)node.Id);
33 |
34 | }
35 |
36 | [TestMethod]
37 | public async Task Put_Get_Dag()
38 | {
39 | var adata = Encoding.UTF8.GetBytes("alpha");
40 | var bdata = Encoding.UTF8.GetBytes("beta");
41 | var alpha = new DagNode(adata);
42 | var beta = new DagNode(bdata, new[] { alpha.ToLink() });
43 | var x = await ipfs.Object.PutAsync(beta);
44 | var node = await ipfs.Object.GetAsync(x.Id);
45 | CollectionAssert.AreEqual(beta.DataBytes, node.DataBytes);
46 | Assert.AreEqual(beta.Links.Count(), node.Links.Count());
47 | Assert.AreEqual(beta.Links.First().Id, node.Links.First().Id);
48 | Assert.AreEqual(beta.Links.First().Name, node.Links.First().Name);
49 | Assert.AreEqual(beta.Links.First().Size, node.Links.First().Size);
50 | }
51 |
52 | [TestMethod]
53 | public async Task Put_Get_Data()
54 | {
55 | var adata = Encoding.UTF8.GetBytes("alpha");
56 | var bdata = Encoding.UTF8.GetBytes("beta");
57 | var alpha = new DagNode(adata);
58 | var beta = await ipfs.Object.PutAsync(bdata, new[] { alpha.ToLink() });
59 | var node = await ipfs.Object.GetAsync(beta.Id);
60 | CollectionAssert.AreEqual(beta.DataBytes, node.DataBytes);
61 | Assert.AreEqual(beta.Links.Count(), node.Links.Count());
62 | Assert.AreEqual(beta.Links.First().Id, node.Links.First().Id);
63 | Assert.AreEqual(beta.Links.First().Name, node.Links.First().Name);
64 | Assert.AreEqual(beta.Links.First().Size, node.Links.First().Size);
65 | }
66 |
67 | [TestMethod]
68 | public async Task Data()
69 | {
70 | var adata = Encoding.UTF8.GetBytes("alpha");
71 | var node = await ipfs.Object.PutAsync(adata);
72 | using (var stream = await ipfs.Object.DataAsync(node.Id))
73 | {
74 | var bdata = new byte[adata.Length];
75 | stream.Read(bdata, 0, bdata.Length);
76 | CollectionAssert.AreEqual(adata, bdata);
77 | }
78 | }
79 |
80 | [TestMethod]
81 | public async Task Links()
82 | {
83 | var adata = Encoding.UTF8.GetBytes("alpha");
84 | var bdata = Encoding.UTF8.GetBytes("beta");
85 | var alpha = new DagNode(adata);
86 | var beta = await ipfs.Object.PutAsync(bdata, new[] { alpha.ToLink() });
87 | var links = await ipfs.Object.LinksAsync(beta.Id);
88 | Assert.AreEqual(beta.Links.Count(),links.Count());
89 | Assert.AreEqual(beta.Links.First().Id, links.First().Id);
90 | Assert.AreEqual(beta.Links.First().Name, links.First().Name);
91 | Assert.AreEqual(beta.Links.First().Size, links.First().Size);
92 | }
93 |
94 | [TestMethod]
95 | public async Task Stat()
96 | {
97 | var data1 = Encoding.UTF8.GetBytes("Some data 1");
98 | var data2 = Encoding.UTF8.GetBytes("Some data 2");
99 | var node2 = new DagNode(data2);
100 | var node1 = await ipfs.Object.PutAsync(data1,
101 | new[] { node2.ToLink("some-link") });
102 | var info = await ipfs.Object.StatAsync(node1.Id);
103 | Assert.AreEqual(1, info.LinkCount);
104 | Assert.AreEqual(64, info.BlockSize);
105 | Assert.AreEqual(53, info.LinkSize);
106 | Assert.AreEqual(11, info.DataSize);
107 | Assert.AreEqual(77, info.CumulativeSize);
108 | }
109 |
110 | [TestMethod]
111 | public async Task Get_Nonexistent()
112 | {
113 | var data = Encoding.UTF8.GetBytes("Some data for net-ipfs-http-client-test that cannot be found");
114 | var node = new DagNode(data);
115 | var id = node.Id;
116 | var cs = new CancellationTokenSource(500);
117 | try
118 | {
119 | var _ = await ipfs.Object.GetAsync(id, cs.Token);
120 | Assert.Fail("Did not throw TaskCanceledException");
121 | }
122 | catch (TaskCanceledException)
123 | {
124 | return;
125 | }
126 | }
127 |
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/test/CoreApi/PinApiTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs.Http
10 | {
11 |
12 | [TestClass]
13 | public class PinApiTest
14 | {
15 | [TestMethod]
16 | public void List()
17 | {
18 | var ipfs = TestFixture.Ipfs;
19 | var pins = ipfs.Pin.ListAsync().Result;
20 | Assert.IsNotNull(pins);
21 | Assert.IsTrue(pins.Count() > 0);
22 | }
23 |
24 | [TestMethod]
25 | public async Task Add_Remove()
26 | {
27 | var ipfs = TestFixture.Ipfs;
28 | var result = await ipfs.FileSystem.AddTextAsync("I am pinned");
29 | var id = result.Id;
30 |
31 | var pins = await ipfs.Pin.AddAsync(id);
32 | Assert.IsTrue(pins.Any(pin => pin == id));
33 | var all = await ipfs.Pin.ListAsync();
34 | Assert.IsTrue(all.Any(pin => pin == id));
35 |
36 | pins = await ipfs.Pin.RemoveAsync(id);
37 | Assert.IsTrue(pins.Any(pin => pin == id));
38 | all = await ipfs.Pin.ListAsync();
39 | Assert.IsFalse(all.Any(pin => pin == id));
40 | }
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/test/CoreApi/PubSubApiTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Newtonsoft.Json.Linq;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | namespace Ipfs.Http
13 | {
14 |
15 | [TestClass]
16 | public class PubSubApiTest
17 | {
18 |
19 | [TestMethod]
20 | public void Api_Exists()
21 | {
22 | IpfsClient ipfs = TestFixture.Ipfs;
23 | Assert.IsNotNull(ipfs.PubSub);
24 | }
25 |
26 | [TestMethod]
27 | public async Task Peers()
28 | {
29 | var ipfs = TestFixture.Ipfs;
30 | var topic = "net-ipfs-http-client-test-" + Guid.NewGuid().ToString();
31 | var cs = new CancellationTokenSource();
32 | try
33 | {
34 | await ipfs.PubSub.SubscribeAsync(topic, msg => { }, cs.Token);
35 | var peers = ipfs.PubSub.PeersAsync().Result.ToArray();
36 | Assert.IsTrue(peers.Length > 0);
37 | }
38 | finally
39 | {
40 | cs.Cancel();
41 | }
42 | }
43 |
44 | [TestMethod]
45 | public void Peers_Unknown_Topic()
46 | {
47 | var ipfs = TestFixture.Ipfs;
48 | var topic = "net-ipfs-http-client-test-unknown" + Guid.NewGuid().ToString();
49 | var peers = ipfs.PubSub.PeersAsync(topic).Result.ToArray();
50 | Assert.AreEqual(0, peers.Length);
51 | }
52 |
53 | [TestMethod]
54 | public async Task Subscribed_Topics()
55 | {
56 | var ipfs = TestFixture.Ipfs;
57 | var topic = "net-ipfs-http-client-test-" + Guid.NewGuid().ToString();
58 | var cs = new CancellationTokenSource();
59 | try
60 | {
61 | await ipfs.PubSub.SubscribeAsync(topic, msg => { }, cs.Token);
62 | var topics = ipfs.PubSub.SubscribedTopicsAsync().Result.ToArray();
63 | Assert.IsTrue(topics.Length > 0);
64 | CollectionAssert.Contains(topics, topic);
65 | }
66 | finally
67 | {
68 | cs.Cancel();
69 | }
70 | }
71 |
72 | volatile int messageCount = 0;
73 |
74 | [TestMethod]
75 | public async Task Subscribe()
76 | {
77 | messageCount = 0;
78 | var ipfs = TestFixture.Ipfs;
79 | var topic = "net-ipfs-http-client-test-" + Guid.NewGuid().ToString();
80 | var cs = new CancellationTokenSource();
81 | try
82 | {
83 | await ipfs.PubSub.SubscribeAsync(topic, msg =>
84 | {
85 | Interlocked.Increment(ref messageCount);
86 | }, cs.Token);
87 | await ipfs.PubSub.PublishAsync(topic, "hello world!");
88 |
89 | await Task.Delay(1000);
90 | Assert.AreEqual(1, messageCount);
91 | }
92 | finally
93 | {
94 | cs.Cancel();
95 | }
96 | }
97 |
98 | [TestMethod]
99 | public async Task Subscribe_Mutiple_Messages()
100 | {
101 | messageCount = 0;
102 | var messages = "hello world this is pubsub".Split();
103 | var ipfs = TestFixture.Ipfs;
104 | var topic = "net-ipfs-http-client-test-" + Guid.NewGuid().ToString();
105 | var cs = new CancellationTokenSource();
106 | try
107 | {
108 | await ipfs.PubSub.SubscribeAsync(topic, msg =>
109 | {
110 | Interlocked.Increment(ref messageCount);
111 | }, cs.Token);
112 | foreach (var msg in messages)
113 | {
114 | await ipfs.PubSub.PublishAsync(topic, msg);
115 | }
116 |
117 | await Task.Delay(1000);
118 | Assert.AreEqual(messages.Length, messageCount);
119 | }
120 | finally
121 | {
122 | cs.Cancel();
123 | }
124 | }
125 |
126 | [TestMethod]
127 | public async Task Multiple_Subscribe_Mutiple_Messages()
128 | {
129 | messageCount = 0;
130 | var messages = "hello world this is pubsub".Split();
131 | var ipfs = TestFixture.Ipfs;
132 | var topic = "net-ipfs-http-client-test-" + Guid.NewGuid().ToString();
133 | var cs = new CancellationTokenSource();
134 | Action processMessage = (msg) =>
135 | {
136 | Interlocked.Increment(ref messageCount);
137 | };
138 | try
139 | {
140 | await ipfs.PubSub.SubscribeAsync(topic, processMessage, cs.Token);
141 | await ipfs.PubSub.SubscribeAsync(topic, processMessage, cs.Token);
142 | foreach (var msg in messages)
143 | {
144 | await ipfs.PubSub.PublishAsync(topic, msg);
145 | }
146 |
147 | await Task.Delay(1000);
148 | Assert.AreEqual(messages.Length * 2, messageCount);
149 | }
150 | finally
151 | {
152 | cs.Cancel();
153 | }
154 | }
155 |
156 | volatile int messageCount1 = 0;
157 |
158 | [TestMethod]
159 | public async Task Unsubscribe()
160 | {
161 | messageCount1 = 0;
162 | var ipfs = TestFixture.Ipfs;
163 | var topic = "net-ipfs-http-client-test-" + Guid.NewGuid().ToString();
164 | var cs = new CancellationTokenSource();
165 | await ipfs.PubSub.SubscribeAsync(topic, msg =>
166 | {
167 | Interlocked.Increment(ref messageCount1);
168 | }, cs.Token);
169 | await ipfs.PubSub.PublishAsync(topic, "hello world!");
170 | await Task.Delay(1000);
171 | Assert.AreEqual(1, messageCount1);
172 |
173 | cs.Cancel();
174 | await ipfs.PubSub.PublishAsync(topic, "hello world!!!");
175 | await Task.Delay(1000);
176 | Assert.AreEqual(1, messageCount1);
177 | }
178 |
179 | [TestMethod]
180 | public async Task Subscribe_BinaryMessage()
181 | {
182 | var messages = new List();
183 | var expected = new byte[] { 0, 1, 2, 4, (byte)'a', (byte)'b', 0xfe, 0xff };
184 | var ipfs = TestFixture.Ipfs;
185 | var topic = "net-ipfs-http-client-test-" + Guid.NewGuid().ToString();
186 | var cs = new CancellationTokenSource();
187 | try
188 | {
189 | await ipfs.PubSub.SubscribeAsync(topic, msg =>
190 | {
191 | messages.Add(msg);
192 | }, cs.Token);
193 | await ipfs.PubSub.PublishAsync(topic, expected);
194 |
195 | await Task.Delay(1000);
196 | Assert.AreEqual(1, messages.Count);
197 | CollectionAssert.AreEqual(expected, messages[0].DataBytes);
198 | }
199 | finally
200 | {
201 | cs.Cancel();
202 | }
203 | }
204 |
205 | [TestMethod]
206 | public async Task Subscribe_StreamMessage()
207 | {
208 | var messages = new List();
209 | var expected = new byte[] { 0, 1, 2, 4, (byte)'a', (byte)'b', 0xfe, 0xff };
210 | var ipfs = TestFixture.Ipfs;
211 | var topic = "net-ipfs-http-client-test-" + Guid.NewGuid().ToString();
212 | var cs = new CancellationTokenSource();
213 | try
214 | {
215 | await ipfs.PubSub.SubscribeAsync(topic, msg =>
216 | {
217 | messages.Add(msg);
218 | }, cs.Token);
219 | var ms = new MemoryStream(expected, false);
220 | await ipfs.PubSub.PublishAsync(topic, ms);
221 |
222 | await Task.Delay(1000);
223 | Assert.AreEqual(1, messages.Count);
224 | CollectionAssert.AreEqual(expected, messages[0].DataBytes);
225 | }
226 | finally
227 | {
228 | cs.Cancel();
229 | }
230 | }
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/test/CoreApi/StatsApiTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Ipfs.Http
9 | {
10 |
11 | [TestClass]
12 | public class StatsApiTest
13 | {
14 |
15 | [TestMethod]
16 | public async Task SmokeTest()
17 | {
18 | var ipfs = TestFixture.Ipfs;
19 | var bandwidth = await ipfs.Stats.BandwidthAsync();
20 | var bitswap = await ipfs.Stats.BitswapAsync();
21 | var repository = await ipfs.Stats.RepositoryAsync();
22 | }
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/test/CoreApi/SwarmApiTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Ipfs.Http
9 | {
10 |
11 | [TestClass]
12 | public class SwarmApiTest
13 | {
14 |
15 | [TestMethod]
16 | public async Task Addresses()
17 | {
18 | var ipfs = TestFixture.Ipfs;
19 | var swarm = await ipfs.Swarm.AddressesAsync();
20 | foreach (var peer in swarm)
21 | {
22 | Assert.IsNotNull(peer.Id);
23 | Assert.IsNotNull(peer.Addresses);
24 | Assert.AreNotEqual(0, peer.Addresses.Count());
25 | }
26 | }
27 |
28 | [TestMethod]
29 | public async Task Peers()
30 | {
31 | var ipfs = TestFixture.Ipfs;
32 | var peers = await ipfs.Swarm.PeersAsync();
33 | Assert.AreNotEqual(0, peers.Count());
34 | foreach (var peer in peers)
35 | {
36 | Assert.IsNotNull(peer.Id);
37 | Assert.IsNotNull(peer.ConnectedAddress);
38 | }
39 | }
40 |
41 | [TestMethod]
42 | public async Task Peers_Info()
43 | {
44 | var ipfs = TestFixture.Ipfs;
45 | var peers = await ipfs.Swarm.PeersAsync();
46 | await Task.WhenAll(peers
47 | .Where(p => p.Latency != TimeSpan.Zero)
48 | .OrderBy(p => p.Latency)
49 | .Take(1)
50 | .Select(async p =>
51 | {
52 | var peer = await ipfs.IdAsync(p.Id);
53 | Assert.AreNotEqual("", peer.PublicKey);
54 | }));
55 | }
56 |
57 | [TestMethod]
58 | public async Task Connection()
59 | {
60 | var ipfs = TestFixture.Ipfs;
61 | var peers = await ipfs.Swarm.PeersAsync();
62 |
63 | // Sometimes we cannot connect to a specific peer. This
64 | // tests that a connection can be made to at least one peer.
65 | foreach (var peer in peers.Take(2))
66 | {
67 | try
68 | {
69 | await ipfs.Swarm.ConnectAsync(peer.ConnectedAddress);
70 | return;
71 | }
72 | catch (Exception)
73 | {
74 | // eat it
75 | }
76 | }
77 |
78 | Assert.Fail("Cannot connect to any peer");
79 | }
80 |
81 | [TestMethod]
82 | public async Task Filter_Add_Remove()
83 | {
84 | var ipfs = TestFixture.Ipfs;
85 | var somewhere = new MultiAddress("/ip4/192.127.0.0/ipcidr/16");
86 | var filter = await ipfs.Swarm.AddAddressFilterAsync(somewhere, true);
87 | Assert.IsNotNull(filter);
88 | Assert.AreEqual(somewhere, filter);
89 | var filters = await ipfs.Swarm.ListAddressFiltersAsync();
90 | Assert.IsTrue(filters.Any(a => a == somewhere));
91 | filters = await ipfs.Swarm.ListAddressFiltersAsync(true);
92 | Assert.IsTrue(filters.Any(a => a == somewhere));
93 |
94 | filter = await ipfs.Swarm.RemoveAddressFilterAsync(somewhere, true);
95 | Assert.IsNotNull(filter);
96 | Assert.AreEqual(somewhere, filter);
97 | filters = await ipfs.Swarm.ListAddressFiltersAsync();
98 | Assert.IsFalse(filters.Any(a => a == somewhere));
99 | filters = await ipfs.Swarm.ListAddressFiltersAsync(true);
100 | Assert.IsFalse(filters.Any(a => a == somewhere));
101 | }
102 |
103 | [TestMethod]
104 | public async Task Filter_List()
105 | {
106 | var ipfs = TestFixture.Ipfs;
107 | var filters = await ipfs.Swarm.ListAddressFiltersAsync(persist: false);
108 | Assert.IsNotNull(filters);
109 | }
110 |
111 | [TestMethod]
112 | public async Task Filter_Remove_Unknown()
113 | {
114 | var ipfs = TestFixture.Ipfs;
115 | var somewhere = new MultiAddress("/ip4/192.168.0.3/ipcidr/2");
116 |
117 | var filter = await ipfs.Swarm.RemoveAddressFilterAsync(somewhere);
118 | Assert.IsNull(filter);
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/test/ExceptionAssert.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace Ipfs.Http
6 | {
7 | ///
8 | /// Asserting an .
9 | ///
10 | public static class ExceptionAssert
11 | {
12 |
13 | public static T Throws(Action action, string expectedMessage = null) where T : Exception
14 | {
15 | try
16 | {
17 | action();
18 | }
19 | catch (AggregateException e)
20 | {
21 | var match = e.InnerExceptions.OfType().FirstOrDefault();
22 | if (match != null)
23 | {
24 | if (expectedMessage != null)
25 | Assert.AreEqual(expectedMessage, match.Message, "Wrong exception message.");
26 | return match;
27 | }
28 |
29 | throw;
30 | }
31 | catch (T e)
32 | {
33 | if (expectedMessage != null)
34 | Assert.AreEqual(expectedMessage, e.Message);
35 | return e;
36 | }
37 | Assert.Fail("Exception of type {0} should be thrown.", typeof(T));
38 |
39 | // The compiler doesn't know that Assert.Fail will always throw an exception
40 | return null;
41 | }
42 |
43 | public static Exception Throws(Action action, string expectedMessage = null)
44 | {
45 | return Throws(action, expectedMessage);
46 | }
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/test/FileSystemNodeTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.Linq;
5 | using System.IO;
6 | using System.Threading.Tasks;
7 | using Newtonsoft.Json;
8 |
9 | namespace Ipfs.Http
10 | {
11 |
12 | [TestClass]
13 | public class FileSystemNodeTest
14 | {
15 | [TestMethod]
16 | public async Task Serialization()
17 | {
18 | var ipfs = TestFixture.Ipfs;
19 | var a = await ipfs.FileSystem.AddTextAsync("hello world");
20 | Assert.AreEqual("Qmf412jQZiuVUtdgnB36FXFX7xg5V6KEbSJ4dpQuhkLyfD", (string)a.Id);
21 |
22 | var b = await ipfs.FileSystem.ListFileAsync(a.Id);
23 | var json = JsonConvert.SerializeObject(b);
24 | var c = JsonConvert.DeserializeObject(json);
25 | Assert.AreEqual(b.Id, c.Id);
26 | Assert.AreEqual(b.IsDirectory, c.IsDirectory);
27 | Assert.AreEqual(b.Size, c.Size);
28 | CollectionAssert.AreEqual(b.Links.ToArray(), c.Links.ToArray());
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/IpfsClientTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.Net.Http;
5 | using System.Threading;
6 |
7 | namespace Ipfs.Http
8 | {
9 |
10 | ///
11 | ///This is a test class for IpfsClientTest and is intended
12 | ///to contain all IpfsClientTest Unit Tests
13 | ///
14 | [TestClass]
15 | public partial class IpfsClientTest
16 | {
17 | ///
18 | /// A test for IpfsClient Constructor
19 | ///
20 | [TestMethod]
21 | public void Can_Create()
22 | {
23 | IpfsClient target = TestFixture.Ipfs;
24 | Assert.IsNotNull(target);
25 | }
26 |
27 | [TestMethod]
28 | public void Do_Command_Throws_Exception_On_Invalid_Command()
29 | {
30 | IpfsClient target = TestFixture.Ipfs;
31 | object unknown;
32 | ExceptionAssert.Throws(() => unknown = target.DoCommandAsync("foobar", default(CancellationToken)).Result);
33 | }
34 |
35 | [TestMethod]
36 | public void Do_Command_Throws_Exception_On_Missing_Argument()
37 | {
38 | IpfsClient target = TestFixture.Ipfs;
39 | object unknown;
40 | ExceptionAssert.Throws(() => unknown = target.DoCommandAsync("key/gen", default(CancellationToken)).Result);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/test/IpfsHttpClientTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net45;netcoreapp1.1;netcoreapp2.0
5 |
6 | false
7 | full
8 | Ipfs.Http
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/test/MerkleNodeTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.Linq;
5 | using System.IO;
6 |
7 | namespace Ipfs.Http
8 | {
9 |
10 | [TestClass]
11 | public partial class MerkleNodeTest
12 | {
13 | const string IpfsInfo = "QmVtU7ths96fMgZ8YSZAbKghyieq7AjxNdcqyVzxTt3qVe";
14 |
15 | [TestMethod]
16 | public void HashWithNamespace()
17 | {
18 | var node = new MerkleNode("/ipfs/" + IpfsInfo);
19 | Assert.AreEqual(IpfsInfo, (string)node.Id);
20 | }
21 |
22 | [TestMethod]
23 | public void Stringify()
24 | {
25 | var node = new MerkleNode(IpfsInfo);
26 | Assert.AreEqual("/ipfs/" + IpfsInfo, node.ToString());
27 | }
28 |
29 | [TestMethod]
30 | public void FromString()
31 | {
32 | var a = new MerkleNode(IpfsInfo);
33 | var b = (MerkleNode)IpfsInfo;
34 | Assert.AreEqual(a, b);
35 | }
36 |
37 | [TestMethod]
38 | public void NullHash()
39 | {
40 | ExceptionAssert.Throws(() => new MerkleNode((string)null));
41 | ExceptionAssert.Throws(() => new MerkleNode(""));
42 | ExceptionAssert.Throws(() => new MerkleNode((Cid)null));
43 | }
44 |
45 | [TestMethod]
46 | public void FromALink()
47 | {
48 | var node = new MerkleNode(IpfsInfo);
49 | var link = new MerkleNode(node.Links.First());
50 | Assert.AreEqual(link.Id, node.Links.First().Id);
51 | Assert.AreEqual(link.Name, node.Links.First().Name);
52 | Assert.AreEqual(link.BlockSize, node.Links.First().Size);
53 | }
54 |
55 | [TestMethod]
56 | public void ToALink()
57 | {
58 | var node = new MerkleNode(IpfsInfo);
59 | var link = node.ToLink();
60 | Assert.AreEqual(link.Id, node.Id);
61 | Assert.AreEqual(link.Name, node.Name);
62 | Assert.AreEqual(link.Size, node.BlockSize);
63 |
64 | }
65 |
66 | [TestMethod]
67 | public void Value_Equality()
68 | {
69 | var a0 = new MerkleNode("QmStfpa7ppKPSsdnazBy3Q5QH4zNzGLcpWV88otjVSV7SY");
70 | var a1 = new MerkleNode("QmStfpa7ppKPSsdnazBy3Q5QH4zNzGLcpWV88otjVSV7SY");
71 | var b = new MerkleNode("QmagNHT6twJRBZcGeviiGzHVTMbNnJZameLyL6T14GUHCS");
72 | MerkleNode nullNode = null;
73 |
74 | #pragma warning disable 1718
75 | Assert.IsTrue(a0 == a0);
76 | Assert.IsTrue(a0 == a1);
77 | Assert.IsFalse(a0 == b);
78 | Assert.IsFalse(a0 == null);
79 |
80 | #pragma warning disable 1718
81 | Assert.IsFalse(a0 != a0);
82 | Assert.IsFalse(a0 != a1);
83 | Assert.IsTrue(a0 != b);
84 | Assert.IsTrue(a0 != null);
85 |
86 | Assert.IsTrue(a0.Equals(a0));
87 | Assert.IsTrue(a0.Equals(a1));
88 | Assert.IsFalse(a0.Equals(b));
89 | Assert.IsFalse(a0.Equals(null));
90 |
91 | Assert.AreEqual(a0, a0);
92 | Assert.AreEqual(a0, a1);
93 | Assert.AreNotEqual(a0, b);
94 | Assert.AreNotEqual(a0, null);
95 |
96 | Assert.AreEqual(a0, a0);
97 | Assert.AreEqual(a0, a1);
98 | Assert.AreNotEqual(a0, b);
99 | Assert.AreNotEqual(a0, null);
100 |
101 | Assert.AreEqual(a0.GetHashCode(), a0.GetHashCode());
102 | Assert.AreEqual(a0.GetHashCode(), a1.GetHashCode());
103 | Assert.AreNotEqual(a0.GetHashCode(), b.GetHashCode());
104 |
105 | Assert.IsTrue(nullNode == null);
106 | Assert.IsFalse(null == a0);
107 | Assert.IsFalse(nullNode != null);
108 | Assert.IsTrue(null != a0);
109 | }
110 |
111 | [TestMethod]
112 | public void DataBytes()
113 | {
114 | var node = new MerkleNode(IpfsInfo);
115 | byte[] data = node.DataBytes;
116 | Assert.AreEqual(node.BlockSize, data.Length);
117 | }
118 |
119 | [TestMethod]
120 | public void DataStream()
121 | {
122 | var node = new MerkleNode(IpfsInfo);
123 | byte[] data = node.DataBytes;
124 | var streamData = new MemoryStream();
125 | node.DataStream.CopyTo(streamData);
126 | CollectionAssert.AreEqual(data, streamData.ToArray());
127 | }
128 |
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/test/PublishedMessageTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.Linq;
5 | using System.IO;
6 |
7 | namespace Ipfs.Http
8 | {
9 |
10 | [TestClass]
11 | public partial class PublishedMessageTest
12 | {
13 | const string json = @"{
14 | ""from"":""EiDzOYdzT4BE42JXwxVM8Q19w6tx30Bp2N3T7tOH/a2nCw=="",
15 | ""data"":""aGVsbG8gd29ybGQ="",
16 | ""seqno"":""FPBVj+oTUug="",
17 | ""topicIDs"":[""net-ipfs-http-client-test""]
18 | }";
19 |
20 | [TestMethod]
21 | public void FromJson()
22 | {
23 | var msg = new PublishedMessage(json);
24 | Assert.AreEqual("Qmei6fBYij8gjbetgHLXmoR54iRc9hioPR7dtmBTNG3oWa", msg.Sender);
25 | Assert.AreEqual("14f0558fea1352e8", msg.SequenceNumber.ToHexString());
26 | Assert.AreEqual("68656c6c6f20776f726c64", msg.DataBytes.ToHexString());
27 | Assert.AreEqual("hello world", msg.DataString);
28 | CollectionAssert.Contains(msg.Topics.ToArray(), "net-ipfs-http-client-test");
29 |
30 | var data = msg.DataBytes;
31 | var streamData = new MemoryStream();
32 | msg.DataStream.CopyTo(streamData);
33 | CollectionAssert.AreEqual(data, streamData.ToArray());
34 | }
35 |
36 | [TestMethod]
37 | public void Id_NotSupported()
38 | {
39 | var msg = new PublishedMessage(json);
40 | ExceptionAssert.Throws(() => {
41 | var _ = msg.Id;
42 | });
43 | }
44 |
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/test/TestFixture.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.Http
8 | {
9 | public static class TestFixture
10 | {
11 | ///
12 | /// Fiddler cannot see localhost traffic because .Net bypasses the network stack for localhost/127.0.0.1.
13 | /// By using "127.0.0.1." (note trailing dot) fiddler will receive the traffic and if its not running
14 | /// the localhost will get it!
15 | ///
16 | //IpfsClient.DefaultApiUri = new Uri("http://127.0.0.1.:5001");
17 |
18 | public static IpfsClient Ipfs = new IpfsClient();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/test/TrustedPeersTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.Http;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.Linq;
5 |
6 | namespace Ipfs.Http
7 | {
8 |
9 | public partial class IpfsClientTest
10 | {
11 | MultiAddress newTrustedPeer = new MultiAddress("/ip4/25.196.147.100/tcp/4001/ipfs/QmaMqSwWShsPg2RbredZtoneFjXhim7AQkqbLxib45Lx4S");
12 |
13 | [TestMethod]
14 | public void Trusted_Peers_List()
15 | {
16 | var ipfs = TestFixture.Ipfs;
17 | Assert.IsNotNull(ipfs.TrustedPeers);
18 | Assert.IsTrue(ipfs.TrustedPeers.Count > 0);
19 | }
20 |
21 | [TestMethod]
22 | public void Trusted_Peers_Add_Remove()
23 | {
24 | var ipfs = TestFixture.Ipfs;
25 | Assert.IsFalse(ipfs.TrustedPeers.Contains(newTrustedPeer));
26 |
27 | ipfs.TrustedPeers.Add(newTrustedPeer);
28 | Assert.IsTrue(ipfs.TrustedPeers.Contains(newTrustedPeer));
29 |
30 | ipfs.TrustedPeers.Remove(newTrustedPeer);
31 | Assert.IsFalse(ipfs.TrustedPeers.Contains(newTrustedPeer));
32 | }
33 |
34 | // js-ipfs does NOT check IPFS addresses.
35 | // And this bad addr eventually breaks the server.
36 | // https://github.com/ipfs/js-ipfs/issues/1066
37 | #if false
38 | [TestMethod]
39 | public void Trusted_Peers_Add_Missing_Peer_ID()
40 | {
41 | var missingPeerId = new MultiAddress("/ip4/25.196.147.100/tcp/4001");
42 | var ipfs = TestFixture.Ipfs;
43 | ExceptionAssert.Throws(() => ipfs.TrustedPeers.Add(missingPeerId), "invalid IPFS address");
44 | }
45 | #endif
46 |
47 | [TestMethod]
48 | public void Trusted_Peers_Clear()
49 | {
50 | var ipfs = TestFixture.Ipfs;
51 | var original = ipfs.TrustedPeers.ToArray();
52 |
53 | ipfs.TrustedPeers.Clear();
54 | Assert.AreEqual(0, ipfs.TrustedPeers.Count);
55 |
56 | foreach (var a in original)
57 | ipfs.TrustedPeers.Add(a);
58 | }
59 |
60 | [TestMethod]
61 | public void Trusted_Peers_Add_Default_Nodes()
62 | {
63 | var ipfs = TestFixture.Ipfs;
64 | var original = ipfs.TrustedPeers.ToArray();
65 |
66 | ipfs.TrustedPeers.Clear();
67 | Assert.AreEqual(0, ipfs.TrustedPeers.Count);
68 | ipfs.TrustedPeers.AddDefaultNodes();
69 | Assert.AreNotEqual(0, ipfs.TrustedPeers.Count);
70 |
71 | ipfs.TrustedPeers.Clear();
72 | foreach (var a in original)
73 | ipfs.TrustedPeers.Add(a);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------