├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ ├── generated-pr.yml │ ├── publish.yml │ └── stale.yml ├── .gitignore ├── Directory.Build.props ├── IpfsCore.sln ├── LICENSE ├── README.md ├── doc ├── .gitignore ├── Properties │ └── AssemblyInfo.cs ├── api │ └── .gitignore ├── articles │ ├── cid.md │ ├── core-api.md │ ├── dag.md │ ├── intro.md │ ├── multiaddress.md │ ├── multihash.md │ ├── toc.yml │ └── varint.md ├── 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 └── toc.yml ├── src ├── Base32.cs ├── Base32z.cs ├── Base36.cs ├── Base58.cs ├── Base64NoPad.cs ├── Base64Url.cs ├── Cid.cs ├── CoreApi │ ├── AddFileOptions.cs │ ├── BandwidthData.cs │ ├── BitswapData.cs │ ├── BitswapLedger.cs │ ├── CarImportOutput.cs │ ├── DagResolveOutput.cs │ ├── DagStat.cs │ ├── DagStatSummary.cs │ ├── FilePart.cs │ ├── FileStat.cs │ ├── FilestoreDuplicate.cs │ ├── FilestoreItem.cs │ ├── FolderPart.cs │ ├── IBitswapApi.cs │ ├── IBlockApi.cs │ ├── IBlockRepository.cs │ ├── IBootstrapApi.cs │ ├── IConfigApi.cs │ ├── IContentRouting.cs │ ├── ICoreApi.cs │ ├── IDagApi.cs │ ├── IDhtApi.cs │ ├── IDnsApi.cs │ ├── IFileSystemApi.cs │ ├── IFilestoreApi.cs │ ├── IGenericApi.cs │ ├── IKeyApi.cs │ ├── IMfsApi.cs │ ├── INameApi.cs │ ├── IPeerRouting.cs │ ├── IPinApi.cs │ ├── IPubSubApi.cs │ ├── IStatsApi.cs │ ├── ISwarmApi.cs │ ├── IValueStore.cs │ ├── MfsWriteOptions.cs │ ├── PingResult.cs │ ├── RepositoryData.cs │ └── TransferProgress.cs ├── Cryptography │ ├── BouncyDigest.cs │ ├── DoubleSha256.cs │ ├── IdentityHash.cs │ ├── Keccak.cs │ └── KeccakManaged.cs ├── DagCid.cs ├── DagLink.cs ├── DagNode.cs ├── Duration.cs ├── HexString.cs ├── IBlockStat.cs ├── IDataBlock.cs ├── IFileSystemLink.cs ├── IFileSystemNode.cs ├── IKey.cs ├── IMerkleLink.cs ├── IMerkleNode.cs ├── IPublishedMessage.cs ├── IpfsCore.csproj ├── MultiAddress.cs ├── MultiBase.cs ├── MultiCodec.cs ├── MultiHash.cs ├── NamedContent.cs ├── NetworkProtocol.cs ├── Peer.cs ├── ProtobufHelper.cs ├── Registry │ ├── Codec.cs │ ├── HashingAlgorithm.cs │ └── MultiBaseAlgorithm .cs ├── VarInt.cs ├── icon.png ├── ipfs.ci.snk.enc └── ipfs.dev.snk └── test ├── App.config ├── Base32Test.cs ├── Base58Test.cs ├── CidTest.cs ├── CoreApi ├── BitswapLedgerTest.cs └── PingResultTest.cs ├── Cryptography └── HashingTest.cs ├── DagLinkTest.cs ├── DagNodeTest.cs ├── DurationTest.cs ├── ExceptionAssert.cs ├── HexStringTest.cs ├── IpfsCoreTests.csproj ├── MultBaseTest.cs ├── MultiAddressTest.cs ├── MultiHashTest.cs ├── NamedContentTest.cs ├── NetworkProtocolTest.cs ├── PeerTest.cs ├── Registry ├── CodecTest.cs ├── HashingAlgorithmTest.cs └── MultibaseAlgorithmTest.cs ├── VarintTest.cs └── packages.config /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | name: Build Validation 3 | 4 | # Controls when the action will run. 5 | on: 6 | # Triggers the workflow on push or pull request events but only for the main branch 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 16 | jobs: 17 | # This workflow contains a single job called "run-tests" 18 | run-tests: 19 | # The type of runner that the job will run on 20 | runs-on: ubuntu-latest 21 | 22 | # Steps represent a sequence of tasks that will be executed as part of the job 23 | steps: 24 | - name: Install .NET 6 SDK 25 | uses: actions/setup-dotnet@v4 26 | with: 27 | dotnet-version: '6.0.201' 28 | 29 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 30 | - name: Checkout Repository 31 | uses: actions/checkout@v4 32 | 33 | - name: dotnet build 34 | run: dotnet build /r 35 | 36 | - name: dotnet test 37 | run: dotnet test 38 | -------------------------------------------------------------------------------- /.github/workflows/generated-pr.yml: -------------------------------------------------------------------------------- 1 | name: Close Generated PRs 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | stale: 14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-generated-pr.yml@v1 15 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to Nuget 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | 7 | # Allows you to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Setup .NET 16 | uses: actions/setup-dotnet@v4 17 | with: 18 | dotnet-version: 6.0.x 19 | - name: Restore dependencies 20 | run: dotnet restore 21 | - name: Build 22 | run: dotnet build --no-restore -p:Configuration=Release 23 | - name: Test 24 | run: dotnet test --no-build --verbosity normal -p:Configuration=Release 25 | - name: Publish to NuGet 26 | run: dotnet nuget push "/home/runner/work/net-ipfs-core/net-ipfs-core/src/bin/Release/IpfsShipyard.Ipfs.Core.*.*.*.nupkg" --skip-duplicate --api-key ${{secrets.NUGET_KEY}} --source https://api.nuget.org/v3/index.json 27 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Close Stale Issues 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | stale: 14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1 15 | -------------------------------------------------------------------------------- /.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 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | 198 | # VS 2017 creates this 199 | src/Ipfs.Core.xml 200 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | enable 5 | true 6 | 10.0 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /IpfsCore.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.27004.2005 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpfsCore", "src\IpfsCore.csproj", "{6401AF07-B7F2-4664-86AA-FAD99F82DFAD}" 6 | EndProject 7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpfsCoreTests", "test\IpfsCoreTests.csproj", "{FE639401-D4C7-4528-A07C-4290A7710889}" 8 | EndProject 9 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DA715302-8746-4884-95F9-B56F069A0451}" 10 | ProjectSection(SolutionItems) = preProject 11 | .codacy.yml = .codacy.yml 12 | .travis.yml = .travis.yml 13 | appveyor.yml = appveyor.yml 14 | builddocs.cmd = builddocs.cmd 15 | IpfsCore.vsmdi = IpfsCore.vsmdi 16 | LICENSE = LICENSE 17 | Local.testsettings = Local.testsettings 18 | README.md = README.md 19 | TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings 20 | EndProjectSection 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {6401AF07-B7F2-4664-86AA-FAD99F82DFAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {6401AF07-B7F2-4664-86AA-FAD99F82DFAD}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {6401AF07-B7F2-4664-86AA-FAD99F82DFAD}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {6401AF07-B7F2-4664-86AA-FAD99F82DFAD}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {FE639401-D4C7-4528-A07C-4290A7710889}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {FE639401-D4C7-4528-A07C-4290A7710889}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {FE639401-D4C7-4528-A07C-4290A7710889}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {FE639401-D4C7-4528-A07C-4290A7710889}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {F3A32EA9-0B2F-46A3-B47A-33B4C04BD423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {F3A32EA9-0B2F-46A3-B47A-33B4C04BD423}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(ExtensibilityGlobals) = postSolution 43 | SolutionGuid = {36ED5AA7-8F41-4F7D-A665-230635EF64A1} 44 | EndGlobalSection 45 | GlobalSection(TestCaseManagementSettings) = postSolution 46 | CategoryFile = IpfsCore.vsmdi 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # net-ipfs-core 2 | 3 | ![Version](https://img.shields.io/nuget/v/IpfsShipyard.Ipfs.Core.svg) 4 | 5 | The core objects and interfaces of the [IPFS](https://github.com/ipfs/ipfs) (Inter Planetary File System) for .Net (C#, VB, F# etc.) 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 | This library supports .NET Standard 2.0. 10 | 11 | ## Install 12 | 13 | Published releases are available on [NuGet](https://www.nuget.org/packages/IpfsShipyard.Ipfs.Core). To install, run the following command in the [Package Manager Console](https://docs.nuget.org/docs/start-here/using-the-package-manager-console). 14 | 15 | PM> Install-Package IpfsShipyard.Ipfs.Core 16 | 17 | Or using [dotnet](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet) 18 | 19 | > dotnet add package IpfsShipyard.Ipfs.Core 20 | 21 | ## Major objects 22 | 23 | - [MerkleDag](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.DagNode.html) 24 | - [MultiAddress](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.MultiAddress.html) 25 | - [MultiHash](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.MultiHash.html) 26 | 27 | See the [API Documentation](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.html) for a list of all objects. 28 | 29 | ### MultiHash 30 | 31 | All hashes in IPFS are encoded with [multihash](https://github.com/multiformats/multihash), a self-describing hash format. The actual hash function used depends on security requirements. The cryptosystem of IPFS is upgradeable, meaning that as hash functions are broken, networks can shift to stronger hashes. There is no free lunch, as objects may need to be rehashed, or links duplicated. But ensuring that tools built do not assume a pre-defined length of hash digest means tools that work with today's hash functions will also work with tomorrows longer hash functions too. 32 | 33 | ### MultiAddress 34 | 35 | A standard way to represent a networks address that supports [multiple network protocols](https://github.com/multiformats/multiaddr). It is represented as a series of tuples, a protocol code and an optional value. For example, an IPFS file at a sepcific address over ipv4 and tcp is 36 | 37 | /ip4/10.1.10.10/tcp/80/ipfs/QmVcSqVEsvm5RR9mBLjwpb2XjFVn5bPdPL69mL8PH45pPC 38 | 39 | ### Merkle DAG 40 | 41 | The [DagNode](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.DagNode.html) is a directed acyclic graph whose edges are a 42 | [DagLink](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.DagLink.html). This means that links to objects can authenticate 43 | the objects themselves, and that every object contains a secure 44 | representation of its children. 45 | 46 | Every Merkle is a directed acyclic graph (DAG) because each node is accessed via its name (the hash of `DagNode`). Each branch of Merkle is the hash of its local content (data and links); naming children by their hash instead of their full contents. So after creation there is no way to edit a DagNode. This prevents cycles (assuming there are no hash collisions) since one can not link the first created node to the last note to create the last reference. 47 | 48 | ## Related Projects 49 | 50 | - [IPFS HTTP Client](https://github.com/ipfs-shipyard/net-ipfs-http-client) - A .Net client library for the IPFS HTTP API. 51 | 52 | ## License 53 | The IPFS Core 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](LICENSE) file for more information. 54 | 55 | -------------------------------------------------------------------------------- /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/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 | .manifest 6 | -------------------------------------------------------------------------------- /doc/articles/cid.md: -------------------------------------------------------------------------------- 1 | # Content ID 2 | 3 | A [Cid](xref:Ipfs.Cid) is a self-describing content-addressed identifier for distributed systems. It doesn't indicate *where* 4 | the content is stored, but it forms a kind of address based on the content itself. 5 | 6 | For background information, see [cid concept](https://docs.ipfs.io/guides/concepts/cid/). 7 | 8 | # Encoding 9 | 10 | In June 2019 the IPFS ecosystem switched from **base58btc** encoding 11 | to the case-insensitive **base32** encoding. This plays much 12 | better with DNS and URL based systems. 13 | -------------------------------------------------------------------------------- /doc/articles/core-api.md: -------------------------------------------------------------------------------- 1 | # Core API 2 | 3 | [ICoreApi](xref:Ipfs.CoreApi.ICoreApi) is a set of interfaces to IPFS features. 4 | 5 | 6 | | Feature | Purpose | 7 | | ------- | ------- | 8 | | [Bitswap](xref:Ipfs.CoreApi.IBitswapApi) | Block trading between peers | 9 | | [Block](xref:Ipfs.CoreApi.IBlockApi) | Manages the blocks | 10 | | [BlockRepository](xref:Ipfs.CoreApi.IBlockRepositoryApi) | Manages the repository for [blocks](xref:Ipfs.CoreApi.IBlockApi) | 11 | | [Bootstrap](xref:Ipfs.CoreApi.IBootstrapApi) | Trusted peers | 12 | | [Config](xref:Ipfs.CoreApi.IConfigApi) | Manages the configuration of the local peer | 13 | | [Dag](xref:Ipfs.CoreApi.IDagApi) | Manages the IPLD (linked data) Directed Acrylic Graph | 14 | | [Dht](xref:Ipfs.CoreApi.IDhtApi) | Manages the Distributed Hash Table | 15 | | [Dns](xref:Ipfs.CoreApi.IDnsApi) | DNS mapping to IPFS | 16 | | [FileSystem](xref:Ipfs.CoreApi.IFileSystemApi) | Manages the files/directories in IPFS | 17 | | [Key](xref:Ipfs.CoreApi.IKeyApi) | Manages the cryptographic keys | 18 | | [Misc](xref:Ipfs.CoreApi.IGenericApi) | Some miscellaneous methods | 19 | | [Name](xref:Ipfs.CoreApi.INameApi) | Manages the Interplanetary Name Space (IPNS) | 20 | | [Object](xref:Ipfs.CoreApi.IObjectApi) | Manages the IPFS Directed Acrylic Graph | 21 | | [Pin](xref:Ipfs.CoreApi.IPinApi) | Manage objects that are locally stored and permanent | 22 | | [PubSub](xref:Ipfs.CoreApi.IPubSubApi) | Publish and subscribe topic messages | 23 | | [Swarm](xref:Ipfs.CoreApi.ISwarmApi) | Manages the swarm of peers | 24 | | [Stats](xref:Ipfs.CoreApi.IStatsApi) | Statistics on IPFS components | 25 | 26 | -------------------------------------------------------------------------------- /doc/articles/dag.md: -------------------------------------------------------------------------------- 1 | # Merkle DAG 2 | 3 | The [DagNode](xref:Ipfs.DagNode) is a directed acyclic graph whose edges are a 4 | [DagLink](xref:Ipfs.DagLink). This means that links to objects can authenticate 5 | the objects themselves, and that every object contains a secure 6 | representation of its children. 7 | 8 | Every Merkle node is a directed acyclic graph (DAG) because each child node is accessed via its [CID](cid.md), 9 | basically the [hash](multihash.md) of the child's dag node. It's [ID](xref:Ipfs.DagNode.Id) 10 | is the hash of its local content ([data](xref:Ipfs.DagNode.DataBytes) and [links](xref:Ipfs.DagNode.Links)). 11 | So after creation there is no way to edit a DagNode. This prevents cycles (assuming there are no hash collisions) 12 | since one can not link the first created node to the last node to create the last reference. 13 | 14 | ```csharp 15 | var a = Encoding.UTF8.GetBytes("a"); 16 | var anode = new DagNode(a); 17 | var alink = anode.ToLink("a"); 18 | 19 | var b = Encoding.UTF8.GetBytes("b"); 20 | var bnode = new DagNode(b); 21 | var blink = bnode.ToLink("b"); 22 | 23 | var node = new DagNode(null, new[] { alink, blink }); 24 | Assert.AreEqual(2, node.Links.Count()); 25 | Assert.AreEqual("QmbNgNPPykP4YTuAeSa3DsnBJWLVxccrqLUZDPNQfizGKs", (string)node.Id); 26 | ``` 27 | -------------------------------------------------------------------------------- /doc/articles/intro.md: -------------------------------------------------------------------------------- 1 | # IPFS Core 2 | 3 | The core objects and interfaces of the [IPFS](https://ipfs.io) (Inter Planetary File System) for .Net (C#, VB, F# etc.) 4 | 5 | The interplanetary file system is the permanent web. It is a new hypermedia distribution protocol, addressed by content and identities. 6 | IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open. 7 | 8 | The source code is on [GitHub](https://github.com/richardschneider/net-ipfs-core) and the 9 | package is published on [NuGet](https://www.nuget.org/packages/Ipfs.Core). 10 | -------------------------------------------------------------------------------- /doc/articles/multiaddress.md: -------------------------------------------------------------------------------- 1 | # MultiAddress 2 | 3 | A standard way to represent a networks address that supports [multiple network protocols](xref:Ipfs.MultiAddress). It is represented as 4 | a series of tuples, a protocol code and an optional value. For example, an IPFS node at a sepcific address over ipv4 and tcp is 5 | 6 | /ip4/10.1.10.10/tcp/80/p2p/QmVcSqVEsvm5RR9mBLjwpb2XjFVn5bPdPL69mL8PH45pPC 7 | 8 | -------------------------------------------------------------------------------- /doc/articles/multihash.md: -------------------------------------------------------------------------------- 1 | # MultiHash 2 | 3 | All hashes in IPFS are encoded as a [MultiHash](xref:Ipfs.MultiHash), a self-describing hash format. 4 | The actual [hash function](#algorithms) used depends on security requirements; "sha2-256" is todays default. 5 | 6 | A multihash is used to identify a [peer](xref:Ipfs.Peer), [key](xref:Ipfs.IKey) and [content](cid.md). 7 | For background information, see [hash concept](https://docs.ipfs.io/guides/concepts/hashes/). 8 | 9 | ```csharp 10 | var hello = Encoding.UTF8.GetBytes("Hello world"); 11 | var mh = MultiHash.ComputeHash(hello, "sha2-256"); 12 | ``` 13 | 14 | ## Format 15 | 16 | The binary representation consists of the [hash code](xref:Ipfs.MultiHash.Algorithm), the [digest's](xref:Ipfs.MultiHash.Digest) 17 | length and value. The code and length are encoded as [varints](varint.md). 18 | 19 | The textual representation is usually the [Base58](xref:Ipfs.MultiHash.ToBase58*) encoding of the 20 | binary format. [Base32](xref:Ipfs.MultiHash.ToBase32*) encoding is used when case insensity is required. 21 | 22 | From the above example, the following is produced 23 | 24 | | Name | Value | 25 | | ---- | ----- | 26 | | hash code | 0x12 | 27 | | digest length | 0x20 | 28 | | digest value | 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c | 29 | | binary | 12 20 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c | 30 | | base 58 | QmV8cfu6n4NT5xRr2AHdKxFMTZEJrA44qgrBCr739BN9Wb | 31 | | base 32 | ciqgj3eiziale2hfxindkz4kdnjrnuqs6tzwnmshoizfgsuk5srx6pa | 32 | 33 | ## Algorithms 34 | 35 | IPFS assigns a unique [Name](xref:Ipfs.Registry.HashingAlgorithm.Name) and [Code](xref:Ipfs.Registry.HashingAlgorithm.Code) 36 | to a hashing algorithm. See [hashtable.csv](https://github.com/multiformats/multicodec/blob/master/table.csv") 37 | for the currently defined hashing algorithms. 38 | 39 | These algorithms are implemented: 40 | 41 | - blake2b-160, blake2b-256 blake2b-384 and blake2b-512 42 | - blake2s-128, blake2s-160, blake2s-224 a nd blake2s-256 43 | - keccak-224, keccak-256, keccak-384 and keccak-512 44 | - md4 and md5 45 | - sha1 46 | - sha2-256, sha2-512 and dbl-sha2-256 47 | - sha3-224, sha3-256, sha3-384 and sha3-512 48 | - shake-128 and shake-256 49 | 50 | The identity hash is also implemented; which just returns the input bytes. This is used to inline a small amount of 51 | data into a [CID](cid.md). 52 | 53 | ## Registry 54 | 55 | The [hashing registry](xref:Ipfs.Registry.HashingAlgorithm) contains the metadata on hashing algorithms. You can use 56 | [Register](xref:Ipfs.Registry.HashingAlgorithm.Register*) to add a new hashing algorithm. 57 | 58 | ### Example 59 | 60 | Using an hashing algorithm. Note that `ComputeHash` can take a byte array or a `Stream`. 61 | 62 | ```csharp 63 | public void GetHasher() 64 | { 65 | using (var hasher = HashingAlgorithm.GetAlgorithm("sha3-256")) 66 | { 67 | Assert.IsNotNull(hasher); 68 | var input = new byte[] { 0xe9 }; 69 | var expected = "f0d04dd1e6cfc29a4460d521796852f25d9ef8d28b44ee91ff5b759d72c1e6d6".ToHexBuffer(); 70 | 71 | var actual = hasher.ComputeHash(input); 72 | CollectionAssert.AreEqual(expected, actual); 73 | } 74 | } 75 | ``` 76 | -------------------------------------------------------------------------------- /doc/articles/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Introduction 2 | href: intro.md 3 | - name: Core API 4 | href: core-api.md 5 | - name: CID 6 | href: cid.md 7 | - name: Merkle DAG 8 | href: dag.md 9 | - name: MultiAddress 10 | href: multiaddress.md 11 | - name: MultiHash 12 | href: multihash.md 13 | - name: Varint 14 | href: varint.md 15 | - name: Class Reference 16 | href: ../api/Ipfs.yml 17 | -------------------------------------------------------------------------------- /doc/articles/varint.md: -------------------------------------------------------------------------------- 1 | # Variable Integer 2 | 3 | A [varint](xref:Ipfs.Varint) is used to encode a non-negative integer of up to 64 bits. 4 | It is encoded in network byte order (Big Endian). Each byte (except the last) contains 7 bits 5 | of information with the most significant bit set to 1. The last byte has the MSB set to 0. 6 | 7 | | Value | Varint encoding | 8 | | ----- | --------------- | 9 | | 1 (0x1) | 01 | 10 | | 16 (0x10) | 10 | 11 | | 256 (0x100) | 80 02 | 12 | | 4096 (0x1000) | 80 20 | 13 | | 65536 (0x10000) | 80 80 04 | 14 | | 1048576 (0x100000) | 80 80 40 | 15 | | 16777216 (0x1000000) | 80 80 80 08 | 16 | -------------------------------------------------------------------------------- /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": "netcoreapp3.0" 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 | "globalMetadata": { 71 | "_appTitle": "IPFS Core documentation", 72 | "_appFooter": "Generated by DocFX", 73 | "_appFaviconPath": "images/ipfs-favicon.ico", 74 | "_appLogoPath": "images/ipfs-cs-logo-48x48.png" 75 | }, 76 | "dest": "_site", 77 | "globalMetadataFiles": [], 78 | "fileMetadataFiles": [], 79 | "template": [ 80 | "default" 81 | ], 82 | "postProcessors": [], 83 | "noLangKeyword": false 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /doc/images/docs-latest-green.svg: -------------------------------------------------------------------------------- 1 | docsdocslatestlatest -------------------------------------------------------------------------------- /doc/images/ipfs-cs-logo-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipfs-shipyard/net-ipfs-core/fa36f50a0081b3b72fa1b47d14030afdaf30646b/doc/images/ipfs-cs-logo-48x48.png -------------------------------------------------------------------------------- /doc/images/ipfs-cs-logo-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipfs-shipyard/net-ipfs-core/fa36f50a0081b3b72fa1b47d14030afdaf30646b/doc/images/ipfs-cs-logo-64x64.png -------------------------------------------------------------------------------- /doc/images/ipfs-favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipfs-shipyard/net-ipfs-core/fa36f50a0081b3b72fa1b47d14030afdaf30646b/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 Core 2 | 3 | The [core objects](api/Ipfs.yml) of the [Inter Planetary File System](https://ipfs.io/) (IPFS) for .Net (C#, VB, F# etc.) 4 | The source code is on [GitHub](https://github.com/richardschneider/net-ipfs-core) and the 5 | package on [NuGet](https://www.nuget.org/packages/Ipfs.Core). 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 core objects 10 | - [API Documentation](api/Ipfs.yml) describes the core objects in detail -------------------------------------------------------------------------------- /doc/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Articles 2 | href: articles/ 3 | - name: Api Documentation 4 | href: api/ 5 | - name: Github 6 | href: https://github.com/richardschneider/net-ipfs-core 7 | -------------------------------------------------------------------------------- /src/Base32.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs; 2 | 3 | /// 4 | /// A codec for Base-32. 5 | /// 6 | /// 7 | /// 8 | /// A codec for Base-32, and . Adds the extension method 9 | /// to encode a byte array and to decode a Base-32 string. 10 | /// 11 | /// 12 | /// and produce the lower case form of 13 | /// with no padding. 14 | /// and are case-insensitive and 15 | /// allow optional padding. 16 | /// 17 | /// 18 | /// A thin wrapper around . 19 | /// 20 | /// 21 | public static class Base32 22 | { 23 | /// 24 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is 25 | /// encoded with base-32 characters. 26 | /// s 27 | /// 28 | /// An array of 8-bit unsigned integers. 29 | /// 30 | /// 31 | /// The string representation, in base 32, of the contents of . 32 | /// 33 | public static string Encode(byte[] input) 34 | { 35 | return SimpleBase.Base32.Rfc4648.Encode(input, false).ToLowerInvariant(); 36 | } 37 | 38 | /// 39 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is 40 | /// encoded with base-32 digits. 41 | /// 42 | /// 43 | /// An array of 8-bit unsigned integers. 44 | /// 45 | /// 46 | /// The string representation, in base 32, of the contents of . 47 | /// 48 | public static string ToBase32(this byte[] bytes) 49 | { 50 | return Encode(bytes); 51 | } 52 | 53 | /// 54 | /// Converts the specified , which encodes binary data as base 32 digits, 55 | /// to an equivalent 8-bit unsigned integer array. 56 | /// 57 | /// 58 | /// The base 32 string to convert. 59 | /// 60 | /// 61 | /// An array of 8-bit unsigned integers that is equivalent to . 62 | /// 63 | /// 64 | /// is case-insensitive and allows padding. 65 | /// 66 | public static byte[] Decode(string input) 67 | { 68 | return SimpleBase.Base32.Rfc4648.Decode(input); 69 | } 70 | 71 | /// 72 | /// Converts the specified , which encodes binary data as base 32 digits, 73 | /// to an equivalent 8-bit unsigned integer array. 74 | /// 75 | /// 76 | /// The base 32 string to convert; case-insensitive and allows padding. 77 | /// 78 | /// 79 | /// An array of 8-bit unsigned integers that is equivalent to . 80 | /// 81 | public static byte[] FromBase32(this string s) 82 | { 83 | return Decode(s); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Base32z.cs: -------------------------------------------------------------------------------- 1 | using SimpleBase; 2 | 3 | namespace Ipfs 4 | { 5 | /// 6 | /// Base32 encoding designed to be easier for human use and more compact. 7 | /// 8 | /// 9 | /// Commonly referred to as 'z-base-32'. 10 | /// 11 | /// 12 | public static class Base32z 13 | { 14 | private static readonly Base32Alphabet Alphabet = new("ybndrfg8ejkmcpqxot1uwisza345h769"); 15 | 16 | /// 17 | /// The encoder/decoder for z-base-32. 18 | /// 19 | public static readonly SimpleBase.Base32 Codec = new(Alphabet); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Base58.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Ipfs 7 | { 8 | /// 9 | /// A codec for IPFS Base-58. 10 | /// 11 | /// 12 | /// 13 | /// A codec for Base-58, and . Adds the extension method 14 | /// to encode a byte array and to decode a Base-58 string. 15 | /// 16 | /// 17 | /// This is just thin wrapper of . 18 | /// 19 | /// 20 | /// This codec uses the BitCoin alphabet not Flickr's. 21 | /// 22 | /// 23 | public static class Base58 24 | { 25 | /// 26 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is 27 | /// encoded with base-58 characters. 28 | /// s 29 | /// 30 | /// An array of 8-bit unsigned integers. 31 | /// 32 | /// 33 | /// The string representation, in base 58, of the contents of . 34 | /// 35 | public static string Encode(byte[] bytes) 36 | { 37 | return SimpleBase.Base58.Bitcoin.Encode(bytes); 38 | } 39 | 40 | /// 41 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is 42 | /// encoded with base-58 digits. 43 | /// 44 | /// 45 | /// An array of 8-bit unsigned integers. 46 | /// 47 | /// 48 | /// The string representation, in base 58, of the contents of . 49 | /// 50 | public static string ToBase58(this byte[] bytes) 51 | { 52 | return Encode(bytes); 53 | } 54 | 55 | /// 56 | /// Converts the specified , which encodes binary data as base 58 digits, 57 | /// to an equivalent 8-bit unsigned integer array. 58 | /// 59 | /// 60 | /// The base 58 string to convert. 61 | /// 62 | /// 63 | /// An array of 8-bit unsigned integers that is equivalent to . 64 | /// 65 | public static byte[] Decode(string s) 66 | { 67 | return SimpleBase.Base58.Bitcoin.Decode(s); 68 | } 69 | 70 | /// 71 | /// Converts the specified , which encodes binary data as base 58 digits, 72 | /// to an equivalent 8-bit unsigned integer array. 73 | /// 74 | /// 75 | /// The base 58 string to convert. 76 | /// 77 | /// 78 | /// An array of 8-bit unsigned integers that is equivalent to . 79 | /// 80 | public static byte[] FromBase58(this string s) 81 | { 82 | return Decode(s); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Base64NoPad.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Ipfs 7 | { 8 | /// 9 | /// A codec for Base-64 (RFC 4648) with no padding. 10 | /// 11 | /// 12 | /// 13 | /// A codec for Base-64, and . Adds the extension method 14 | /// to encode a byte array and to decode a Base-64 string. 15 | /// 16 | /// 17 | public static class Base64NoPad 18 | { 19 | /// 20 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is 21 | /// encoded with base-64 characters. 22 | /// s 23 | /// 24 | /// An array of 8-bit unsigned integers. 25 | /// 26 | /// 27 | /// The string representation, in base 64, of the contents of . 28 | /// 29 | public static string Encode(byte[] bytes) 30 | { 31 | return Convert.ToBase64String(bytes) 32 | .TrimEnd('='); 33 | } 34 | 35 | /// 36 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is 37 | /// encoded with base-64 digits. 38 | /// 39 | /// 40 | /// An array of 8-bit unsigned integers. 41 | /// s 42 | /// 43 | /// The string representation, in base 64, of the contents of . 44 | /// 45 | public static string ToBase64NoPad(this byte[] bytes) 46 | { 47 | return Encode(bytes); 48 | } 49 | 50 | /// 51 | /// Converts the specified , which encodes binary data as base 64 digits, 52 | /// to an equivalent 8-bit unsigned integer array. 53 | /// 54 | /// 55 | /// The base 64 string to convert. 56 | /// 57 | /// 58 | /// An array of 8-bit unsigned integers that is equivalent to . 59 | /// 60 | public static byte[] Decode(string s) 61 | { 62 | switch (s.Length % 4) // Pad with trailing '='s 63 | { 64 | case 0: break; // No pad chars in this case 65 | case 2: s += "=="; break; // Two pad chars 66 | case 3: s += "="; break; // One pad char 67 | default: throw new Exception("Illegal base64 string!"); 68 | } 69 | 70 | return Convert.FromBase64String(s); // Standard base64 decoder 71 | } 72 | 73 | /// 74 | /// Converts the specified , which encodes binary data as base 64 digits, 75 | /// to an equivalent 8-bit unsigned integer array. 76 | /// 77 | /// 78 | /// The base 64 string to convert. 79 | /// 80 | /// 81 | /// An array of 8-bit unsigned integers that is equivalent to . 82 | /// 83 | public static byte[] FromBase64NoPad(this string s) 84 | { 85 | return Decode(s); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Base64Url.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ipfs 4 | { 5 | /// 6 | /// A codec for Base-64 URL (RFC 4648). 7 | /// 8 | /// 9 | /// 10 | /// A codec for Base-64 URL, and . Adds the extension method 11 | /// to encode a byte array and to decode a Base-64 URL string. 12 | /// 13 | /// 14 | /// The original code was found at . 15 | /// 16 | /// 17 | public static class Base64Url 18 | { 19 | /// 20 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is 21 | /// encoded with base-64 URL characters. 22 | /// s 23 | /// 24 | /// An array of 8-bit unsigned integers. 25 | /// 26 | /// 27 | /// The string representation, in base 64, of the contents of . 28 | /// 29 | public static string Encode(byte[] bytes) 30 | { 31 | string s = Convert.ToBase64String(bytes); // Standard base64 encoder 32 | 33 | s = s.TrimEnd('='); // Remove any trailing '='s 34 | s = s.Replace('+', '-'); // 62nd char of encoding 35 | s = s.Replace('/', '_'); // 63rd char of encoding 36 | 37 | return s; 38 | } 39 | 40 | /// 41 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is 42 | /// encoded with base-64 URL digits. 43 | /// 44 | /// 45 | /// An array of 8-bit unsigned integers. 46 | /// s 47 | /// 48 | /// The string representation, in base 64, of the contents of . 49 | /// 50 | public static string ToBase64Url(this byte[] bytes) 51 | { 52 | return Encode(bytes); 53 | } 54 | 55 | /// 56 | /// Converts the specified , which encodes binary data as base 64 URL digits, 57 | /// to an equivalent 8-bit unsigned integer array. 58 | /// 59 | /// 60 | /// The base 64 string to convert. 61 | /// 62 | /// 63 | /// An array of 8-bit unsigned integers that is equivalent to . 64 | /// 65 | public static byte[] Decode(string s) 66 | { 67 | s = s.Replace('-', '+'); // 62nd char of encoding 68 | s = s.Replace('_', '/'); // 63rd char of encoding 69 | 70 | switch (s.Length % 4) // Pad with trailing '='s 71 | { 72 | case 0: break; // No pad chars in this case 73 | case 2: s += "=="; break; // Two pad chars 74 | case 3: s += "="; break; // One pad char 75 | default: throw new Exception("Illegal base64url string!"); 76 | } 77 | 78 | return Convert.FromBase64String(s); // Standard base64 decoder 79 | } 80 | 81 | /// 82 | /// Converts the specified , which encodes binary data as base 64 url digits, 83 | /// to an equivalent 8-bit unsigned integer array. 84 | /// 85 | /// 86 | /// The base 64 string to convert. 87 | /// 88 | /// 89 | /// An array of 8-bit unsigned integers that is equivalent to . 90 | /// 91 | public static byte[] FromBase64Url(this string s) 92 | { 93 | return Decode(s); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/CoreApi/AddFileOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | /// 6 | /// The options when adding data to the IPFS file system. 7 | /// 8 | /// 9 | public class AddFileOptions 10 | { 11 | /// 12 | /// Determines if the data is pinned to local storage. 13 | /// 14 | /// 15 | /// If true the data is pinned to local storage and will not be 16 | /// garbage collected. Required: no. The default is true. 17 | /// 18 | public bool? Pin { get; set; } 19 | 20 | /// 21 | /// Chunking algorithm, size-[bytes], rabin-[min]-[avg]-[max] or buzhash. Required: no. 22 | /// 23 | /// 24 | /// Required: no. The default is 256 * 1024 (size-‭262144) bytes.‬ 25 | /// 26 | public string? Chunker { get; set; } 27 | 28 | /// 29 | /// Determines if the trickle-dag format is used for dag generation. 30 | /// 31 | /// 32 | /// Required: no. The default is false. 33 | /// 34 | public bool? Trickle { get; set; } 35 | 36 | /// 37 | /// Determines if added file(s) are wrapped in a directory object. 38 | /// 39 | /// 40 | /// Required: no. The default is false. 41 | /// 42 | public bool? Wrap { get; set; } 43 | 44 | /// 45 | /// Determines if raw blocks are used for leaf nodes. 46 | /// 47 | /// 48 | /// Required: no. The default is false. 49 | /// 50 | public bool? RawLeaves { get; set; } 51 | 52 | /// 53 | /// The hashing algorithm name to use. 54 | /// 55 | /// 56 | /// The algorithm name used to produce the . 57 | /// Defaults to . 58 | /// 59 | /// 60 | public string? Hash { get; set; } 61 | 62 | /// 63 | /// Determines if only file information is produced. 64 | /// 65 | /// 66 | /// If true no data is added to IPFS. Required: no. The default is false. 67 | /// 68 | public bool? OnlyHash { get; set; } 69 | 70 | /// 71 | /// Used to report the progress of a file transfer. 72 | /// 73 | public IProgress? Progress { get; set; } 74 | 75 | /// 76 | /// Add the file using filestore. Implies raw-leaves. 77 | /// 78 | public bool? NoCopy { get; set; } 79 | 80 | /// 81 | /// Check the filestore for pre-existing blocks. 82 | /// 83 | public bool? FsCache { get; set; } 84 | 85 | /// 86 | /// Defaults to 0 unless an option that depends on CIDv1 is passed. 87 | /// Passing version 1 will cause the raw-leaves option to default to true. 88 | /// Required: no. 89 | /// 90 | public int? CidVersion { get; set; } 91 | 92 | /// 93 | /// Inline small blocks into CIDs. (experimental). Required: no. 94 | /// 95 | public bool? Inline { get; set; } 96 | 97 | /// 98 | /// Maximum block size to inline. (experimental). Default: 32. Required: no. 99 | /// 100 | public int? InlineLimit { get; set; } 101 | 102 | /// 103 | /// Add reference to Files API (MFS) at the provided path. Required: no. 104 | /// 105 | public string? ToFiles { get; set; } 106 | 107 | /// 108 | /// Apply existing POSIX permissions to created UnixFS entries. Disables raw-leaves. (experimental). Required: no. 109 | /// 110 | public bool? PreserveMode { get; set; } 111 | 112 | /// 113 | /// Apply existing POSIX modification time to created UnixFS entries. Disables raw-leaves. (experimental). Required: no. 114 | /// 115 | public bool? PreserveMtime { get; set; } 116 | 117 | /// 118 | /// Custom POSIX file mode to store in created UnixFS entries. Disables raw-leaves. (experimental). Required: no. 119 | /// 120 | public uint? Mode { get; set; } 121 | 122 | /// 123 | /// Custom POSIX modification time to store in created UnixFS entries (seconds before or after the Unix Epoch). Disables raw-leaves. (experimental). Required: no. 124 | /// 125 | public long? Mtime { get; set; } 126 | 127 | /// 128 | /// Custom POSIX modification time (optional time fraction in nanoseconds). 129 | /// 130 | public uint? MtimeNsecs { get; set; } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/CoreApi/BandwidthData.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs.CoreApi 2 | { 3 | /// 4 | /// The statistics for . 5 | /// 6 | public class BandwidthData 7 | { 8 | /// 9 | /// The number of bytes received. 10 | /// 11 | public ulong TotalIn { get; set; } 12 | 13 | /// 14 | /// The number of bytes sent. 15 | /// 16 | public ulong TotalOut { get; set; } 17 | 18 | /// 19 | /// TODO 20 | /// 21 | public double RateIn { get; set; } 22 | 23 | /// 24 | /// TODO 25 | /// 26 | public double RateOut { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/CoreApi/BitswapData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | /// 6 | /// The statistics for . 7 | /// 8 | public class BitswapData 9 | { 10 | /// 11 | /// TODO: Unknown. 12 | /// 13 | public int ProvideBufLen { get; set; } 14 | 15 | /// 16 | /// The content that is wanted. 17 | /// 18 | public IEnumerable? Wantlist { get; set; } 19 | 20 | /// 21 | /// The known peers. 22 | /// 23 | public IEnumerable? Peers { get; set; } 24 | 25 | /// 26 | /// The number of blocks sent by other peers. 27 | /// 28 | public ulong BlocksReceived { get; set; } 29 | 30 | /// 31 | /// The number of bytes sent by other peers. 32 | /// 33 | public ulong DataReceived { get; set; } 34 | 35 | /// 36 | /// The number of blocks sent to other peers. 37 | /// 38 | public ulong BlocksSent { get; set; } 39 | 40 | /// 41 | /// The number of bytes sent to other peers. 42 | /// 43 | public ulong DataSent { get; set; } 44 | 45 | /// 46 | /// The number of duplicate blocks sent by other peers. 47 | /// 48 | /// 49 | /// A duplicate block is a block that is already stored in the 50 | /// local repository. 51 | /// 52 | public ulong DupBlksReceived { get; set; } 53 | 54 | /// 55 | /// The number of duplicate bytes sent by other peers. 56 | /// 57 | /// 58 | /// A duplicate block is a block that is already stored in the 59 | /// local repository. 60 | /// 61 | public ulong DupDataReceived { get; set; } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/CoreApi/BitswapLedger.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs.CoreApi 2 | { 3 | /// 4 | /// Statistics on the bitswap blocks exchanged with another . 5 | /// 6 | /// 7 | public class BitswapLedger 8 | { 9 | /// 10 | /// The that pertains to this ledger. 11 | /// 12 | /// 13 | /// The peer that is being monitored. 14 | /// 15 | public Peer? Peer { get; set; } 16 | 17 | /// 18 | /// The number of blocks exchanged with the . 19 | /// 20 | /// 21 | /// The number of blocks sent by the peer or sent by us to the peer. 22 | /// 23 | public ulong BlocksExchanged { get; set; } 24 | 25 | /// 26 | /// The number of bytes sent by the to us. 27 | /// 28 | /// 29 | /// The number of bytes. 30 | /// 31 | public ulong DataReceived { get; set; } 32 | 33 | /// 34 | /// The number of bytes sent by us to the 35 | /// 36 | /// 37 | /// The number of bytes. 38 | /// 39 | public ulong DataSent { get; set; } 40 | 41 | /// 42 | /// The calculated debt to the peer. 43 | /// 44 | /// 45 | /// divided by . 46 | /// A value less than 1 indicates that we are in debt to the 47 | /// . 48 | /// 49 | public float DebtRatio => (float)DataSent / (float)(DataReceived + 1); // +1 is to prevent division by zero 50 | 51 | /// 52 | /// Determines if we owe the some blocks. 53 | /// 54 | /// 55 | /// true if we owe data to the peer; otherwise, false. 56 | /// 57 | public bool IsInDebt => DebtRatio < 1; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/CoreApi/CarImportOutput.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | /// 6 | /// CarImportOutput is the output type of the 'dag import' commands 7 | /// 8 | /// See also 9 | public class CarImportOutput 10 | { 11 | /// 12 | /// Root is the metadata for a root pinning response 13 | /// 14 | [JsonProperty("Root", NullValueHandling = NullValueHandling.Ignore)] 15 | public RootMeta? Root { get; set; } 16 | 17 | /// 18 | /// Stats contains statistics about the imported CAR file, if requested. 19 | /// 20 | [JsonProperty("Stats", NullValueHandling = NullValueHandling.Ignore)] 21 | public CarImportStats? Stats { get; set; } 22 | 23 | /// 24 | /// RootMeta is the metadata for a root pinning response 25 | /// 26 | public record RootMeta 27 | { 28 | /// 29 | /// The CID of the root of the imported DAG. 30 | /// 31 | public required DagCid Cid { get; set; } 32 | 33 | /// 34 | /// The error message if pinning failed 35 | /// 36 | public string? PinErrorMsg { get; set; } 37 | } 38 | 39 | /// 40 | /// Statistics about an imported CAR file. 41 | /// 42 | public record CarImportStats 43 | { 44 | /// 45 | /// The number of blocks in the CAR file. 46 | /// 47 | [JsonProperty("BlockCount")] 48 | public ulong BlockCount { get; set; } 49 | 50 | /// 51 | /// The number of block bytes in the CAR file. 52 | /// 53 | [JsonProperty("BlockBytesCount")] 54 | public ulong BlockBytesCount { get; set; } 55 | } 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/CoreApi/DagResolveOutput.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs.CoreApi 2 | { 3 | /// 4 | /// The result of a DAG resolve operation. 5 | /// 6 | /// The cid of the resolved dag path. 7 | /// Unknown usage. See 8 | public record DagResolveOutput(DagCid Id, string RemPath); 9 | } 10 | -------------------------------------------------------------------------------- /src/CoreApi/DagStat.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | /// 6 | /// Statistics about a DAG block. 7 | /// 8 | public record DagStat 9 | { 10 | /// 11 | /// The CID of the block. 12 | /// 13 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 14 | public DagCid? Cid { get; set; } 15 | 16 | /// 17 | /// The size of the block. 18 | /// 19 | public ulong? Size { get; set; } 20 | 21 | /// 22 | /// The number of links in the block. 23 | /// 24 | public long NumBlocks { get; set; } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/CoreApi/DagStatSummary.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace Ipfs.CoreApi 5 | { 6 | /// 7 | /// The output of a DAG stat operation. 8 | /// 9 | /// 10 | /// Adapted from 11 | /// 12 | public record DagStatSummary 13 | { 14 | /// 15 | /// The size of redundant nodes in this Dag tree. 16 | /// 17 | /// 18 | /// Docs sourced from 19 | /// 20 | [JsonIgnore] 21 | public ulong RedundantSize { get; set; } 22 | 23 | /// 24 | /// The number of unique CIDs in this Dag tree. 25 | /// 26 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 27 | public int? UniqueBlocks { get; set; } 28 | 29 | /// 30 | /// The total size of all unique dag blocks in this tree. 31 | /// 32 | /// 33 | /// Docs sourced from 34 | /// 35 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 36 | public ulong? TotalSize { get; set; } 37 | 38 | /// 39 | /// The difference between and . 40 | /// 41 | /// 42 | /// Docs sourced from code 43 | /// 44 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 45 | public ulong? SharedSize { get; set; } 46 | 47 | /// 48 | /// The ratio of to . 49 | /// 50 | /// 51 | /// Docs sourced from code 52 | /// 53 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 54 | public float? Ratio { get; set; } 55 | 56 | /// 57 | /// If requested, the stats for each DAG in the tree. 58 | /// 59 | [JsonProperty("DagStats", NullValueHandling = NullValueHandling.Ignore)] 60 | public IEnumerable? DagStatsArray { get; set; } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/CoreApi/FilePart.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | /// 6 | /// Represents a file to be added to IPFS. 7 | /// 8 | public class FilePart 9 | { 10 | /// 11 | /// The name of the file or the relative path to the file in a folder. 12 | /// 13 | public required string Name { get; set; } 14 | 15 | /// 16 | /// A stream containing the file's data. 17 | /// 18 | public required Stream? Data { get; set; } 19 | 20 | /// 21 | /// Can be set to the location of the file in the filesystem (within the IPFS root), or to its full web URL. 22 | /// 23 | /// 24 | /// Included for filestore/urlstore features that are enabled with the nocopy option 25 | /// 26 | public string? AbsolutePath { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/CoreApi/FileStat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | /// 6 | /// Information on a MFS file path 7 | /// 8 | /// 9 | public class FileStatResult 10 | { 11 | /// 12 | /// The of the file or directory. 13 | /// 14 | public Cid? Hash { get; set; } 15 | 16 | /// 17 | /// The serialised size (in bytes) of the linked node. 18 | /// 19 | public long Size { get; set; } 20 | 21 | /// 22 | /// Size of object and its references. 23 | /// 24 | public long CumulativeSize { get; set; } 25 | 26 | /// 27 | /// Determines if the node is a directory (folder). 28 | /// 29 | /// 30 | /// true if the node is a directory; Otherwise false, 31 | /// it is some type of a file. 32 | /// 33 | public bool IsDirectory { get; set; } 34 | 35 | /// 36 | /// Number of blocks 37 | /// 38 | public int Blocks { get; set; } 39 | } 40 | 41 | /// 42 | /// Expanded result when parameter is-local=true is used. 43 | /// 44 | /// 45 | public class FileStatWithLocalityResult : FileStatResult 46 | { 47 | /// 48 | /// Is local object. 49 | /// 50 | public bool Local { get; set; } 51 | 52 | /// 53 | /// The serialised size (in bytes) of the linked node that is local. 54 | /// 55 | public long SizeLocal { get; set; } 56 | 57 | /// 58 | /// Reflection of the parameter is-local. 59 | /// 60 | public bool WithLocality { get; set; } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/CoreApi/FilestoreDuplicate.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs.CoreApi 2 | { 3 | /// 4 | /// The response object for the method. 5 | /// 6 | public record FilestoreDuplicate 7 | { 8 | /// 9 | /// Any error in the Dups response. 10 | /// 11 | public required string Err { get; set; } 12 | 13 | /// 14 | /// The cid in the Dups response. 15 | /// 16 | public required Cid Ref { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/CoreApi/FilestoreItem.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs.CoreApi 2 | { 3 | /// 4 | /// A record that represents an object in a response. 5 | /// 6 | public record FilestoreItem 7 | { 8 | /// 9 | /// The key of the object. 10 | /// 11 | public required DagCid Key { get; set; } 12 | 13 | /// 14 | /// Holds any error message. 15 | /// 16 | public required string ErrorMsg { get; set; } 17 | 18 | /// 19 | /// Path to the file 20 | /// 21 | public required string FilePath { get; set; } 22 | 23 | /// 24 | /// The response offset. 25 | /// 26 | public required ulong Offset { get; set; } 27 | 28 | /// 29 | /// The size of the object. 30 | /// 31 | public ulong Size { get; set; } 32 | 33 | /// 34 | /// The object status. 35 | /// 36 | public int Status { get; set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/CoreApi/FolderPart.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs.CoreApi 2 | { 3 | /// 4 | /// Represents a folder to be added to IPFS. 5 | /// 6 | public record FolderPart 7 | { 8 | /// 9 | /// The name of the folder or the relative path to the folder in another folder. 10 | /// 11 | public required string Name { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/CoreApi/IBitswapApi.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Ipfs.CoreApi 6 | { 7 | /// 8 | /// Data trading module for IPFS. Its purpose is to request blocks from and 9 | /// send blocks to other peers in the network. 10 | /// 11 | /// 12 | /// Bitswap has two primary jobs 13 | /// 14 | /// 15 | /// 16 | /// Attempt to acquire blocks from the network that have been requested by the client 17 | /// 18 | /// 19 | /// 20 | /// 21 | /// Judiciously (though strategically) send blocks in its possession to other peers who want them 22 | /// 23 | /// 24 | /// 25 | /// 26 | /// Bitswap spec 27 | public interface IBitswapApi 28 | { 29 | /// 30 | /// The blocks that are needed by a peer. 31 | /// 32 | /// 33 | /// The id of an IPFS peer. If not specified (e.g. null), then the local 34 | /// peer is used. 35 | /// 36 | /// 37 | /// Is used to stop the task. When cancelled, the is raised. 38 | /// 39 | /// 40 | /// A task that represents the asynchronous operation. The task's value 41 | /// contains the sequence of blocks needed by the . 42 | /// 43 | Task> WantsAsync(MultiHash? peer = null, CancellationToken cancel = default); 44 | 45 | /// 46 | /// Gets information on the blocks exchanged with a specific . 47 | /// 48 | /// 49 | /// The peer to get information on. If the peer is unknown, then a ledger 50 | /// with zeros is returned. 51 | /// 52 | /// 53 | /// Is used to stop the task. When cancelled, the is raised. 54 | /// 55 | /// 56 | /// A task that represents the asynchronous operation. The task's value 57 | /// contains the for the . 58 | /// 59 | Task LedgerAsync(Peer peer, CancellationToken cancel = default); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/CoreApi/IBlockRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | 4 | namespace Ipfs.CoreApi 5 | { 6 | /// 7 | /// Manages all the blocks stored locally. 8 | /// 9 | /// 10 | public interface IBlockRepositoryApi 11 | { 12 | /// 13 | /// Perform a garbage collection sweep on the repo. 14 | /// 15 | /// 16 | /// Is used to stop the task. When cancelled, the is raised. 17 | /// 18 | /// 19 | /// TODO: not sure what this should return. 20 | /// 21 | Task RemoveGarbageAsync(CancellationToken cancel = default); 22 | 23 | /// 24 | /// Get statistics on the repository. 25 | /// 26 | /// 27 | /// Is used to stop the task. When cancelled, the is raised. 28 | /// 29 | /// 30 | /// A task that represents the asynchronous operation. The task's result is 31 | /// the current . 32 | /// 33 | /// 34 | /// Same as . 35 | /// 36 | Task StatisticsAsync(CancellationToken cancel = default); 37 | 38 | /// 39 | /// Verify all blocks in repo are not corrupted. 40 | /// 41 | /// 42 | /// Is used to stop the task. When cancelled, the is raised. 43 | /// 44 | /// 45 | /// TODO: not sure what this should return. 46 | /// 47 | Task VerifyAsync(CancellationToken cancel = default); 48 | 49 | /// 50 | /// Gets the version number of the repo. 51 | /// 52 | /// 53 | /// Is used to stop the task. When cancelled, the is raised. 54 | /// 55 | /// 56 | /// A task that represents the asynchronous operation. The task's result is 57 | /// the version number of the data block repository. 58 | /// 59 | Task VersionAsync(CancellationToken cancel = default); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/CoreApi/IBootstrapApi.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Ipfs.CoreApi 6 | { 7 | /// 8 | /// Manages the list of initial peers. 9 | /// 10 | /// 11 | /// The API manipulates the "bootstrap list", which contains 12 | /// the addresses of the bootstrap nodes. These are the trusted peers from 13 | /// which to learn about other peers in the network. 14 | /// 15 | /// 16 | /// Bootstrap API spec 17 | public interface IBootstrapApi 18 | { 19 | /// 20 | /// Adds a new peer. 21 | /// 22 | /// 23 | /// The address must end with the ipfs protocol and the public ID 24 | /// of the peer. For example "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ" 25 | /// 26 | /// 27 | /// Is used to stop the task. When cancelled, the is raised. 28 | /// 29 | /// 30 | /// A task that represents the asynchronous operation. The task's result is 31 | /// the address that was added or null if the address is already 32 | /// in the bootstrap list. 33 | /// 34 | Task AddAsync(MultiAddress address, CancellationToken cancel = default); 35 | 36 | /// 37 | /// Adds the default peers to the list. 38 | /// 39 | /// 40 | /// Is used to stop the task. When cancelled, the is raised. 41 | /// 42 | /// 43 | /// A task that represents the asynchronous operation. The task's result is 44 | /// the sequence of addresses that were added. 45 | /// 46 | Task> AddDefaultsAsync(CancellationToken cancel = default); 47 | 48 | /// 49 | /// List all the peers. 50 | /// 51 | /// 52 | /// Is used to stop the task. When cancelled, the is raised. 53 | /// 54 | /// 55 | /// A task that represents the asynchronous operation. The task's result is 56 | /// a sequence of addresses. 57 | /// 58 | Task> ListAsync(CancellationToken cancel = default); 59 | 60 | /// 61 | /// Delete the specified peer. 62 | /// 63 | /// 64 | /// The address must end with the ipfs protocol and the public ID 65 | /// of the peer. For example "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ" 66 | /// 67 | /// 68 | /// Is used to stop the task. When cancelled, the is raised. 69 | /// 70 | /// 71 | /// A task that represents the asynchronous operation. The task's result is 72 | /// the address that was removed or null if the 73 | /// is not in the bootstrap list. 74 | /// 75 | Task RemoveAsync(MultiAddress address, CancellationToken cancel = default); 76 | 77 | /// 78 | /// Remove all the peers. 79 | /// 80 | /// 81 | /// Is used to stop the task. When cancelled, the is raised. 82 | /// 83 | /// 84 | /// A task that represents the asynchronous operation. 85 | /// 86 | Task RemoveAllAsync(CancellationToken cancel = default); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/CoreApi/IConfigApi.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace Ipfs.CoreApi 7 | { 8 | /// 9 | /// Manages the IPFS Configuration. 10 | /// 11 | /// 12 | /// 13 | /// Configuration values are JSON. Json.NET 14 | /// is used to represent JSON. 15 | /// 16 | /// 17 | /// Config API spec 18 | public interface IConfigApi 19 | { 20 | /// 21 | /// Gets the entire configuration. 22 | /// 23 | /// 24 | /// A containing the configuration. 25 | /// 26 | Task GetAsync(CancellationToken cancel = default); 27 | 28 | /// 29 | /// Gets the value of a configuration key. 30 | /// 31 | /// 32 | /// The key name, such as "Addresses.API". 33 | /// 34 | /// 35 | /// Is used to stop the task. When cancelled, the is raised. 36 | /// 37 | /// 38 | /// The value of the as . 39 | /// 40 | /// 41 | /// When the does not exist. 42 | /// 43 | /// 44 | /// Keys are case sensistive. 45 | /// 46 | Task GetAsync(string key, CancellationToken cancel = default); 47 | 48 | /// 49 | /// Adds or replaces a configuration value. 50 | /// 51 | /// 52 | /// The key name, such as "Addresses.API". 53 | /// 54 | /// 55 | /// The new value of the . 56 | /// 57 | /// 58 | /// Is used to stop the task. When cancelled, the is raised. 59 | /// 60 | Task SetAsync(string key, string value, CancellationToken cancel = default); 61 | 62 | /// 63 | /// Adds or replaces a configuration value. 64 | /// 65 | /// 66 | /// The key name, such as "Addresses.API". 67 | /// 68 | /// 69 | /// The new JSON value of the . 70 | /// 71 | /// 72 | /// Is used to stop the task. When cancelled, the is raised. 73 | /// 74 | Task SetAsync(string key, JToken value, CancellationToken cancel = default); 75 | 76 | /// 77 | /// Replaces the entire configuration. 78 | /// 79 | /// 80 | Task ReplaceAsync(JObject config); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/CoreApi/IContentRouting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace Ipfs.CoreApi 7 | { 8 | /// 9 | /// Find information about who has what content. 10 | /// 11 | /// 12 | /// No IPFS documentation is currently available. See the 13 | /// code. 14 | /// 15 | public interface IContentRouting 16 | { 17 | /// 18 | /// Adds the to the content routing system. 19 | /// 20 | /// 21 | /// The ID of some content that the peer contains. 22 | /// 23 | /// 24 | /// Advertise the to other peers. 25 | /// 26 | /// 27 | /// Is used to stop the task. When cancelled, the is raised. 28 | /// 29 | /// 30 | /// A task that represents the asynchronous operation. 31 | /// 32 | Task ProvideAsync(Cid cid, bool advertise = true, CancellationToken cancel = default); 33 | 34 | /// 35 | /// Find the providers for the specified content. 36 | /// 37 | /// 38 | /// The of the content. 39 | /// 40 | /// 41 | /// The maximum number of peers to return. Defaults to 20. 42 | /// 43 | /// 44 | /// An action to perform when a provider is found. 45 | /// 46 | /// 47 | /// Is used to stop the task. When cancelled, the is raised. 48 | /// 49 | /// 50 | /// A task that represents the asynchronous operation that returns 51 | /// a sequence of IPFS . 52 | /// 53 | Task> FindProvidersAsync( 54 | Cid id, 55 | int limit = 20, 56 | Action? providerFound = null, 57 | CancellationToken cancel = default); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/CoreApi/ICoreApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Ipfs.CoreApi 6 | { 7 | /// 8 | /// The IPFS Core API. 9 | /// 10 | /// 11 | /// The Core API defines a set of interfaces to manage IPFS. 12 | /// 13 | /// 14 | public interface ICoreApi 15 | { 16 | /// 17 | /// Provides access to the Bitswap API. 18 | /// 19 | /// 20 | /// An object that implements . 21 | /// 22 | IBitswapApi Bitswap { get; } 23 | 24 | /// 25 | /// Provides access to the Block API. 26 | /// 27 | /// 28 | /// An object that implements . 29 | /// 30 | IBlockApi Block { get; } 31 | 32 | /// 33 | /// Provides access to the Block Repository API. 34 | /// 35 | /// 36 | /// An object that implements . 37 | /// 38 | IBlockRepositoryApi BlockRepository { get; } 39 | 40 | /// 41 | /// Provides access to the Bootstrap API. 42 | /// 43 | /// 44 | /// An object that implements . 45 | /// 46 | IBootstrapApi Bootstrap { get; } 47 | 48 | /// 49 | /// Provides access to the Config API. 50 | /// 51 | /// 52 | /// An object that implements . 53 | /// 54 | IConfigApi Config { get; } 55 | 56 | /// 57 | /// Provides access to the Dag API. 58 | /// 59 | /// 60 | /// An object that implements . 61 | /// 62 | IDagApi Dag { get; } 63 | 64 | /// 65 | /// Provides access to the DHT API. 66 | /// 67 | /// 68 | /// An object that implements . 69 | /// 70 | IDhtApi Dht { get; } 71 | 72 | /// 73 | /// Provides access to the DNS API. 74 | /// 75 | /// 76 | /// An object that implements . 77 | /// 78 | IDnsApi Dns { get; } 79 | 80 | /// 81 | /// Provides access to the File System API. 82 | /// 83 | /// 84 | /// An object that implements . 85 | /// 86 | IFileSystemApi FileSystem { get; } 87 | 88 | /// 89 | /// Provides access to the Mfs API. 90 | /// 91 | /// 92 | /// An object that implements . 93 | /// 94 | IMfsApi Mfs { get; } 95 | 96 | /// 97 | /// Provides access to the Generic API. 98 | /// 99 | /// 100 | /// An object that implements . 101 | /// 102 | IGenericApi Generic { get; } 103 | 104 | /// 105 | /// Provides access to the Key API. 106 | /// 107 | /// 108 | /// An object that implements . 109 | /// 110 | IKeyApi Key { get; } 111 | 112 | /// 113 | /// Provides access to the Name API. 114 | /// 115 | /// 116 | /// An object that implements . 117 | /// 118 | INameApi Name { get; } 119 | 120 | /// 121 | /// Provides access to the Pin API. 122 | /// 123 | /// 124 | /// An object that implements . 125 | /// 126 | IPinApi Pin { get; } 127 | 128 | /// 129 | /// Provides access to the PubSub API. 130 | /// 131 | /// 132 | /// An object that implements . 133 | /// 134 | IPubSubApi PubSub { get; } 135 | 136 | /// 137 | /// Provides access to the Stats (statistics) API. 138 | /// 139 | /// 140 | /// An object that implements . 141 | /// 142 | IStatsApi Stats { get; } 143 | 144 | /// 145 | /// Provides access to the Swarm API. 146 | /// 147 | /// 148 | /// An object that implements . 149 | /// 150 | ISwarmApi Swarm { get; } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/CoreApi/IDhtApi.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs.CoreApi 2 | { 3 | /// 4 | /// Manages the Distributed Hash Table. 5 | /// 6 | /// 7 | /// The DHT is a place to store, not the value, but pointers to peers who have 8 | /// the actual value. 9 | /// 10 | /// See the ongoing DHT specification at 11 | /// 12 | /// 13 | /// DHT API spec 14 | public interface IDhtApi : IPeerRouting, IContentRouting, IValueStore 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/CoreApi/IDnsApi.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | 4 | namespace Ipfs.CoreApi 5 | { 6 | /// 7 | /// DNS mapping to IPFS. 8 | /// 9 | /// 10 | /// Multihashes are hard to remember, but domain names are usually easy to 11 | /// remember. To create memorable aliases for multihashes, DNS TXT 12 | /// records can point to other DNS links, IPFS objects, IPNS keys, etc. 13 | /// 14 | public interface IDnsApi 15 | { 16 | /// 17 | /// Resolve a domain name to an IPFS path. 18 | /// 19 | /// 20 | /// An domain name, such as "ipfs.io". 21 | /// 22 | /// 23 | /// Resolve until the result is not a DNS link. Defaults to false. 24 | /// 25 | /// 26 | /// Is used to stop the task. When cancelled, the is raised. 27 | /// 28 | /// 29 | /// A task that represents the asynchronous operation. The task's value is 30 | /// the resolved IPFS path as a , such as 31 | /// /ipfs/QmYNQJoKGNHTpPxCBPh9KkDpaExgd2duMa3aF6ytMpHdao. 32 | /// 33 | /// 34 | /// A DNS TXT record with a "dnslink=..." entry is expected to exist. The 35 | /// value of the "dnslink" is an IPFS path to another IPFS object. 36 | /// 37 | /// A DNS query is generated for both and 38 | /// _dnslink.. 39 | /// 40 | /// 41 | /// 42 | /// ResolveAsync("ipfs.io", recursive: false) produces "/ipns/website.ipfs.io". Whereas, 43 | /// ResolveAsync("ipfs.io", recursive: true) produces "/ipfs/QmXZz6vQTMiu6UyGxVgpLB6xJdHvvUbhdWagJQNnxXAjpn". 44 | /// 45 | Task ResolveAsync( 46 | string name, 47 | bool recursive = false, 48 | CancellationToken cancel = default); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/CoreApi/IFilestoreApi.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | 4 | namespace Ipfs.CoreApi 5 | { 6 | /// 7 | /// Manages the filestore API. 8 | /// 9 | public interface IFilestoreApi 10 | { 11 | /// 12 | /// Lists blocks that are both in the filestore and standard block storage. 13 | /// 14 | public IAsyncEnumerable DupsAsync(CancellationToken token = default); 15 | 16 | /// 17 | /// Lists filestore objects 18 | /// 19 | /// Cid of objects to verify. Required: no. 20 | /// Sort the results based on the path of the backing file. Required: no. 21 | /// A token that can be used to cancel the ongoing operation. 22 | public IAsyncEnumerable ListAsync(string? cid = null, bool? fileOrder = null, CancellationToken token = default); 23 | 24 | /// 25 | /// Verify objects in filestore. 26 | /// 27 | /// Cid of objects to list. Required: no. 28 | /// Sort the results based on the path of the backing file. Required: no. 29 | /// A token that can be used to cancel the ongoing operation. 30 | public IAsyncEnumerable VerifyObjectsAsync(string? cid = null, bool? fileOrder = null, CancellationToken token = default); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/CoreApi/IKeyApi.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Ipfs.CoreApi 6 | { 7 | /// 8 | /// Manages cryptographic keys. 9 | /// 10 | /// 11 | /// 12 | /// The Key API is work in progress! There be dragons here. 13 | /// 14 | /// 15 | /// Key API spec 16 | public interface IKeyApi 17 | { 18 | /// 19 | /// Creates a new key. 20 | /// 21 | /// 22 | /// The local name of the key. 23 | /// 24 | /// 25 | /// The type of key to create; "rsa" or "ed25519". 26 | /// 27 | /// 28 | /// The size, in bits, of the key. 29 | /// 30 | /// 31 | /// Is used to stop the task. When cancelled, the is raised. 32 | /// 33 | /// 34 | /// A task that represents the asynchronous operation. The task's result is 35 | /// the key that was created. 36 | /// 37 | Task CreateAsync( 38 | string name, 39 | string keyType, 40 | int size, 41 | CancellationToken cancel = default); 42 | 43 | /// 44 | /// List all the keys. 45 | /// 46 | /// 47 | /// Is used to stop the task. When cancelled, the is raised. 48 | /// 49 | /// 50 | /// A task that represents the asynchronous operation. The task's result is 51 | /// a sequence of IPFS keys. 52 | /// 53 | Task> ListAsync(CancellationToken cancel = default); 54 | 55 | /// 56 | /// Delete the specified key. 57 | /// 58 | /// 59 | /// The local name of the key. 60 | /// 61 | /// 62 | /// Is used to stop the task. When cancelled, the is raised. 63 | /// 64 | /// 65 | /// A task that represents the asynchronous operation. The task's result is 66 | /// the key that was deleted, or null if the key is not present. 67 | /// 68 | Task RemoveAsync(string name, CancellationToken cancel = default); 69 | 70 | /// 71 | /// Rename the specified key. 72 | /// 73 | /// 74 | /// The local name of the key. 75 | /// 76 | /// 77 | /// The new local name of the key. 78 | /// 79 | /// 80 | /// Is used to stop the task. When cancelled, the is raised. 81 | /// 82 | /// 83 | /// A task that represents the asynchronous operation. The task's result is 84 | /// the new key after the rename. 85 | /// 86 | Task RenameAsync(string oldName, string newName, CancellationToken cancel = default); 87 | 88 | /// 89 | /// Export a key to a PEM encoded password protected PKCS #8 container. 90 | /// 91 | /// 92 | /// The local name of the key. 93 | /// 94 | /// 95 | /// The PEM's password. 96 | /// 97 | /// 98 | /// Is used to stop the task. When cancelled, the is raised. 99 | /// 100 | /// 101 | /// A task that represents the asynchronous operation. The task's result is 102 | /// the password protected PEM string. 103 | /// 104 | Task ExportAsync(string name, char[] password, CancellationToken cancel = default); 105 | 106 | /// 107 | /// Import a key from a PEM encoded password protected PKCS #8 container. 108 | /// 109 | /// 110 | /// The local name of the key. 111 | /// 112 | /// 113 | /// The PEM encoded PKCS #8 container. 114 | /// 115 | /// 116 | /// The 's password. 117 | /// 118 | /// 119 | /// Is used to stop the task. When cancelled, the is raised. 120 | /// 121 | /// 122 | /// A task that represents the asynchronous operation. The task's result 123 | /// is the newly imported key. 124 | /// 125 | Task ImportAsync(string name, string pem, char[]? password = null, CancellationToken cancel = default); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/CoreApi/INameApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Ipfs.CoreApi 6 | { 7 | /// 8 | /// Manages the IPNS (Interplanetary Name Space). 9 | /// 10 | /// 11 | /// IPNS is a PKI namespace, where names are the hashes of public keys, and 12 | /// the private key enables publishing new(signed) values. The default name 13 | /// is the node's own , 14 | /// which is the hash of its public key. 15 | /// 16 | /// Name API spec 17 | public interface INameApi 18 | { 19 | /// 20 | /// Publish an IPFS name. 21 | /// 22 | /// 23 | /// The CID or path to the content to publish. 24 | /// 25 | /// 26 | /// Resolve before publishing. Defaults to true. 27 | /// 28 | /// 29 | /// The local key name used to sign the content. Defaults to "self". 30 | /// 31 | /// 32 | /// Duration that the record will be valid for. Defaults to 24 hours. 33 | /// 34 | /// 35 | /// Is used to stop the task. When cancelled, the is raised. 36 | /// 37 | /// 38 | /// A task that represents the asynchronous operation. The task's value is 39 | /// the of the published content. 40 | /// 41 | Task PublishAsync( 42 | string path, 43 | bool resolve = true, 44 | string key = "self", 45 | TimeSpan? lifetime = null, 46 | CancellationToken cancel = default); 47 | 48 | /// 49 | /// Publish an IPFS name. 50 | /// 51 | /// 52 | /// The of the content to publish. 53 | /// 54 | /// 55 | /// The local key name used to sign the content. Defaults to "self". 56 | /// 57 | /// 58 | /// Duration that the record will be valid for. Defaults to 24 hours. 59 | /// 60 | /// 61 | /// Is used to stop the task. When cancelled, the is raised. 62 | /// 63 | /// 64 | /// A task that represents the asynchronous operation. The task's value is 65 | /// the of the published content. 66 | /// 67 | Task PublishAsync( 68 | Cid id, 69 | string key = "self", 70 | TimeSpan? lifetime = null, 71 | CancellationToken cancel = default); 72 | 73 | /// 74 | /// Resolve an IPNS name. 75 | /// 76 | /// 77 | /// An IPNS address, such as: /ipns/ipfs.io or a CID. 78 | /// 79 | /// 80 | /// Resolve until the result is not an IPNS name. Defaults to false. 81 | /// 82 | /// 83 | /// Do not use cached entries. Defaults to false. 84 | /// 85 | /// 86 | /// Is used to stop the task. When cancelled, the is raised. 87 | /// 88 | /// 89 | /// A task that represents the asynchronous operation. The task's value is 90 | /// the resolved path as a , such as 91 | /// /ipfs/QmYNQJoKGNHTpPxCBPh9KkDpaExgd2duMa3aF6ytMpHdao. 92 | /// 93 | Task ResolveAsync( 94 | string name, 95 | bool recursive = false, 96 | bool nocache = false, 97 | CancellationToken cancel = default); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/CoreApi/IPeerRouting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Ipfs.CoreApi 6 | { 7 | /// 8 | /// Find information about a peer. 9 | /// 10 | /// 11 | /// No IPFS documentation is currently available. See the 12 | /// code. 13 | /// 14 | public interface IPeerRouting 15 | { 16 | /// 17 | /// Information about an IPFS peer. 18 | /// 19 | /// 20 | /// The ID of the IPFS peer. 21 | /// 22 | /// 23 | /// Is used to stop the task. When cancelled, the is NOT raised. 24 | /// 25 | /// 26 | /// A task that represents the asynchronous operation that returns 27 | /// the information or a closer peer. 28 | /// 29 | Task FindPeerAsync(MultiHash id, CancellationToken cancel = default(CancellationToken)); 30 | 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/CoreApi/IPinApi.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Ipfs.CoreApi 6 | { 7 | /// 8 | /// Manage pinned objects (locally stored and permanent). 9 | /// 10 | /// Pin API spec 11 | public interface IPinApi 12 | { 13 | /// 14 | /// Adds an IPFS object to the pinset and also stores it to the IPFS repo. pinset is the set of hashes currently pinned (not gc'able). 15 | /// 16 | /// 17 | /// A CID or path to an existing object, such as "QmXarR6rgkQ2fDSHjSY5nM2kuCXKYGViky5nohtwgF65Ec/about" 18 | /// or "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V" 19 | /// 20 | /// 21 | /// true to recursively pin links of the object; otherwise, false to only pin 22 | /// the specified object. Default is true. 23 | /// 24 | /// 25 | /// Is used to stop the task. When cancelled, the is raised. 26 | /// 27 | /// 28 | /// A task that represents the asynchronous operation. The task's value 29 | /// is a sequence of that were pinned. 30 | /// 31 | Task> AddAsync(string path, bool recursive = true, CancellationToken cancel = default); 32 | 33 | /// 34 | /// List all the objects pinned to local storage. 35 | /// 36 | /// 37 | /// Is used to stop the task. When cancelled, the is raised. 38 | /// 39 | /// 40 | /// A task that represents the asynchronous operation. The task's value 41 | /// is a sequence of . 42 | /// 43 | Task> ListAsync(CancellationToken cancel = default); 44 | 45 | /// 46 | /// Unpin an object. 47 | /// 48 | /// 49 | /// The CID of the object. 50 | /// 51 | /// 52 | /// true to recursively unpin links of object; otherwise, false to only unpin 53 | /// the specified object. Default is true. 54 | /// 55 | /// 56 | /// Is used to stop the task. When cancelled, the is raised. 57 | /// 58 | /// 59 | /// A task that represents the asynchronous operation. The task's value 60 | /// is a sequence of that were unpinned. 61 | /// 62 | Task> RemoveAsync(Cid id, bool recursive = true, CancellationToken cancel = default); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/CoreApi/IPubSubApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Ipfs.CoreApi 8 | { 9 | /// 10 | /// Allows you to publish messages to a given topic, and also to 11 | /// subscribe to new messages on a given topic. 12 | /// 13 | /// 14 | /// 15 | /// This is an experimental feature. It is not intended in its current state 16 | /// to be used in a production environment. 17 | /// 18 | /// 19 | /// To use, the daemon must be run with '--enable-pubsub-experiment'. 20 | /// 21 | /// 22 | /// Pubsub API spec 23 | public interface IPubSubApi 24 | { 25 | /// 26 | /// Get the subscribed topics. 27 | /// 28 | /// 29 | /// Is used to stop the task. When cancelled, the is raised. 30 | /// 31 | /// 32 | /// A task that represents the asynchronous operation. The task's value is 33 | /// a sequence of for each topic. 34 | /// 35 | Task> SubscribedTopicsAsync(CancellationToken cancel = default); 36 | 37 | /// 38 | /// Get the peers that are pubsubing with us. 39 | /// 40 | /// 41 | /// When specified, only peers subscribing on the topic are returned. 42 | /// 43 | /// 44 | /// Is used to stop the task. When cancelled, the is raised. 45 | /// 46 | /// 47 | /// A task that represents the asynchronous operation. The task's value is 48 | /// a sequence of . 49 | /// 50 | Task> PeersAsync(string? topic = null, CancellationToken cancel = default); 51 | 52 | /// 53 | /// Publish a string message to a given topic. 54 | /// 55 | /// 56 | /// The topic name. 57 | /// 58 | /// 59 | /// The message to publish. 60 | /// 61 | /// 62 | /// Is used to stop the task. When cancelled, the is raised. 63 | /// 64 | /// 65 | /// A task that represents the asynchronous operation. 66 | /// 67 | Task PublishAsync(string topic, string message, CancellationToken cancel = default); 68 | 69 | /// 70 | /// Publish a binary message to a given topic. 71 | /// 72 | /// 73 | /// The topic name. 74 | /// 75 | /// 76 | /// The message to publish. 77 | /// 78 | /// 79 | /// Is used to stop the task. When cancelled, the is raised. 80 | /// 81 | /// 82 | /// A task that represents the asynchronous operation. 83 | /// 84 | Task PublishAsync(string topic, byte[] message, CancellationToken cancel = default); 85 | 86 | /// 87 | /// Publish a binary message to a given topic. 88 | /// 89 | /// 90 | /// The topic name. 91 | /// 92 | /// 93 | /// The message to publish. 94 | /// 95 | /// 96 | /// Is used to stop the task. When cancelled, the is raised. 97 | /// 98 | /// 99 | /// A task that represents the asynchronous operation. 100 | /// 101 | Task PublishAsync(string topic, Stream message, CancellationToken cancel = default); 102 | 103 | /// 104 | /// Subscribe to messages on a given topic. 105 | /// 106 | /// 107 | /// The topic name. 108 | /// 109 | /// 110 | /// The action to perform when a is received. 111 | /// 112 | /// 113 | /// Is used to stop the topic listener. When cancelled, the 114 | /// is NOT raised. 115 | /// 116 | /// 117 | /// A task that represents the asynchronous operation. 118 | /// 119 | /// 120 | /// The is invoked on the topic listener thread. 121 | /// 122 | Task SubscribeAsync(string topic, Action handler, CancellationToken cancellationToken); 123 | 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/CoreApi/IStatsApi.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | 4 | namespace Ipfs.CoreApi 5 | { 6 | /// 7 | /// Get statistics/diagnostics for the various core components. 8 | /// 9 | public interface IStatsApi 10 | { 11 | /// 12 | /// Get statistics on network bandwidth. 13 | /// 14 | /// 15 | /// Is used to stop the task. When cancelled, the is raised. 16 | /// 17 | /// 18 | /// A task that represents the asynchronous operation. The task's result is 19 | /// the current . 20 | /// 21 | /// 22 | Task BandwidthAsync(CancellationToken cancel = default); 23 | 24 | /// 25 | /// Get statistics on the blocks exchanged with other peers. 26 | /// 27 | /// 28 | /// Is used to stop the task. When cancelled, the is raised. 29 | /// 30 | /// 31 | /// A task that represents the asynchronous operation. The task's result is 32 | /// the current . 33 | /// 34 | /// 35 | Task BitswapAsync(CancellationToken cancel = default); 36 | 37 | /// 38 | /// Get statistics on the repository. 39 | /// 40 | /// 41 | /// Is used to stop the task. When cancelled, the is raised. 42 | /// 43 | /// 44 | /// A task that represents the asynchronous operation. The task's result is 45 | /// the current . 46 | /// 47 | /// 48 | /// Same as . 49 | /// 50 | /// 51 | Task RepositoryAsync(CancellationToken cancel = default); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/CoreApi/ISwarmApi.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Ipfs.CoreApi 6 | { 7 | /// 8 | /// Manages the swarm of peers. 9 | /// 10 | /// 11 | /// The swarm is a sequence of connected peer nodes. 12 | /// 13 | /// Swarm API spec 14 | public interface ISwarmApi 15 | { 16 | /// 17 | /// Get the peers in the current swarm. 18 | /// 19 | /// 20 | /// Is used to stop the task. When cancelled, the is raised. 21 | /// 22 | /// 23 | /// A task that represents the asynchronous operation. The task's value 24 | /// is a sequence of peer nodes. 25 | /// 26 | Task> AddressesAsync(CancellationToken cancel = default); 27 | 28 | /// 29 | /// Get the peers that are connected to this node. 30 | /// 31 | /// 32 | /// Is used to stop the task. When cancelled, the is raised. 33 | /// 34 | /// 35 | /// A task that represents the asynchronous operation. The task's value 36 | /// is a sequence of Connected Peers. 37 | /// 38 | Task> PeersAsync(CancellationToken cancel = default); 39 | 40 | /// 41 | /// Connect to a peer. 42 | /// 43 | /// 44 | /// An ipfs , such as 45 | /// /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ. 46 | /// 47 | /// 48 | /// Is used to stop the task. When cancelled, the is raised. 49 | /// 50 | Task ConnectAsync(MultiAddress address, CancellationToken cancel = default); 51 | 52 | /// 53 | /// Disconnect from a peer. 54 | /// 55 | /// 56 | /// An ipfs , such as 57 | /// /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ. 58 | /// 59 | /// 60 | /// Is used to stop the task. When cancelled, the is raised. 61 | /// 62 | Task DisconnectAsync(MultiAddress address, CancellationToken cancel = default); 63 | 64 | /// 65 | /// Adds a new address filter. 66 | /// 67 | /// 68 | /// An allowed address. For example "/ip4/104.131.131.82" or 69 | /// "/ip4/192.168.0.0/ipcidr/16". 70 | /// 71 | /// 72 | /// If true the filter will persist across daemon reboots. 73 | /// 74 | /// 75 | /// Is used to stop the task. When cancelled, the is raised. 76 | /// 77 | /// 78 | /// A task that represents the asynchronous operation. The task's result is 79 | /// the address filter that was added, or null if the IPFS layer did not return a MultiAddress result. 80 | /// 81 | /// 82 | Task AddAddressFilterAsync(MultiAddress address, bool persist = false, CancellationToken cancel = default); 83 | 84 | /// 85 | /// List all the address filters. 86 | /// 87 | /// 88 | /// If true only persisted filters are listed. 89 | /// 90 | /// 91 | /// Is used to stop the task. When cancelled, the is raised. 92 | /// 93 | /// 94 | /// A task that represents the asynchronous operation. The task's result is 95 | /// a sequence of addresses filters. 96 | /// 97 | /// 98 | Task> ListAddressFiltersAsync(bool persist = false, CancellationToken cancel = default); 99 | 100 | /// 101 | /// Delete the specified address filter. 102 | /// 103 | /// 104 | /// For example "/ip4/104.131.131.82" or 105 | /// "/ip4/192.168.0.0/ipcidr/16". 106 | /// 107 | /// 108 | /// If true the filter is also removed from the persistent store. 109 | /// 110 | /// 111 | /// Is used to stop the task. When cancelled, the is raised. 112 | /// 113 | /// 114 | /// A task that represents the asynchronous operation. The task's result is 115 | /// the address filter that was removed, or null of the address filter was not found. 116 | /// 117 | /// 118 | Task RemoveAddressFilterAsync(MultiAddress address, bool persist = false, CancellationToken cancel = default); 119 | 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/CoreApi/IValueStore.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | 4 | namespace Ipfs.CoreApi 5 | { 6 | /// 7 | /// A basic Put/Get interface. 8 | /// 9 | public interface IValueStore 10 | { 11 | /// 12 | /// Gets th value of a key. 13 | /// 14 | /// 15 | /// A byte array representing the name of a key. 16 | /// 17 | /// 18 | /// Is used to stop the task. When cancelled, the is raised. 19 | /// 20 | /// 21 | /// A task that represents the asynchronous operation that returns 22 | /// the value of the key as a byte array. 23 | /// 24 | Task GetAsync(byte[] key, CancellationToken cancel = default); 25 | 26 | /// 27 | /// Tries to get the value of a key. 28 | /// 29 | /// 30 | /// A byte array representing the name of a key. 31 | /// 32 | /// 33 | /// A byte array containing the value of the 34 | /// 35 | /// 36 | /// Is used to stop the task. When cancelled, the is raised. 37 | /// 38 | /// 39 | /// A task that represents the asynchronous operation that returns 40 | /// true if the key exists; otherwise, false. 41 | /// 42 | Task TryGetAsync(byte[] key, out byte[] value, CancellationToken cancel = default); 43 | 44 | /// 45 | /// Put the value of a key. 46 | /// 47 | /// 48 | /// A byte array representing the name of a key. 49 | /// 50 | /// 51 | /// A byte array containing the value of the 52 | /// 53 | /// 54 | /// Is used to stop the task. When cancelled, the is raised. 55 | /// 56 | /// 57 | /// A task that represents the asynchronous operation. 58 | /// 59 | Task PutAsync(byte[] key, out byte[] value, CancellationToken cancel = default); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/CoreApi/MfsWriteOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | /// 6 | /// The options when adding data to the MFS file system. 7 | /// 8 | /// 9 | /// 10 | public class MfsWriteOptions 11 | { 12 | /// 13 | /// Create the file if it does not exist 14 | /// 15 | /// 16 | /// The default is null and the server will use its default of false. 17 | /// 18 | public bool? Create { get; set; } = null; 19 | 20 | /// 21 | /// Make parent directories as needed. 22 | /// 23 | /// 24 | /// The default is null and the server will use its default of false. 25 | /// 26 | public bool? Parents { get; set; } = null; 27 | 28 | /// 29 | /// Byte offset to begin writing at. 30 | /// 31 | /// 32 | /// The default is null and the argument will be omitted. 33 | /// If ommitted the offset is zero. 34 | /// 35 | public long? Offset { get; set; } = null; 36 | 37 | /// 38 | /// Maximum number of bytes to write. 39 | /// 40 | /// 41 | /// The default is null and the argument will be omitted. 42 | /// If ommitted, all the data will be written. 43 | /// 44 | public long? Count { get; set; } = null; 45 | 46 | /// 47 | /// Cid version to use. 48 | /// 49 | /// 50 | /// The default is null and the server will use its default Cid Version. 51 | /// 52 | /// 53 | public int? CidVersion { get; set; } = null; 54 | 55 | /// 56 | /// Truncate the file to size zero before writing 57 | /// 58 | /// 59 | /// The default is null and the server will use its default of false. 60 | /// 61 | public bool? Truncate { get; set; } = null; 62 | 63 | /// 64 | /// Use raw blocks for newly created leaf nodes. 65 | /// 66 | /// 67 | /// The default is null and the server will use its default of false. 68 | /// 69 | public bool? RawLeaves { get; set; } = null; 70 | 71 | /// 72 | /// The hashing algorithm name to use. 73 | /// 74 | /// 75 | /// The algorithm name used to produce the . 76 | /// The default is null and the server will use its default algorithm name. 77 | /// 78 | /// 79 | public string? Hash { get; set; } = null; 80 | 81 | /// 82 | /// Flush the data to disk after writing. 83 | /// 84 | /// 85 | /// The default is null and the server will use its default of true. 86 | /// 87 | /// 88 | /// Use caution when setting this flag to false. It will improve performance for large numbers of file operations, but it does so at the cost of consistency guarantees. If the daemon is unexpectedly killed before running a proper flush, then data may be lost. This also applies to running the gc concurrently with flush false. 89 | /// 90 | public bool? Flush { get; set; } = null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/CoreApi/PingResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | /// 6 | /// The result from sending a . 7 | /// 8 | public class PingResult 9 | { 10 | /// 11 | /// Indicates success or failure. 12 | /// 13 | public bool Success { get; set; } 14 | 15 | /// 16 | /// The round trip time; nano second resolution. 17 | /// 18 | public TimeSpan Time { get; set; } 19 | 20 | /// 21 | /// The text to echo. 22 | /// 23 | public string? Text { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/CoreApi/RepositoryData.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs.CoreApi 2 | { 3 | /// 4 | /// The statistics for . 5 | /// 6 | public class RepositoryData 7 | { 8 | /// 9 | /// The number of blocks in the repository. 10 | /// 11 | /// 12 | /// The number of blocks in the repository. 13 | /// 14 | public ulong NumObjects { get; set; } 15 | 16 | /// 17 | /// The total number bytes in the repository. 18 | /// 19 | /// 20 | /// The total number bytes in the repository. 21 | /// 22 | public ulong RepoSize { get; set; } 23 | 24 | /// 25 | /// The fully qualified path to the repository. 26 | /// 27 | /// 28 | /// The directory of the repository. 29 | /// 30 | public string RepoPath { get; set; } = string.Empty; 31 | 32 | /// 33 | /// The version number of the repository. 34 | /// 35 | /// 36 | /// The version number of the repository. 37 | /// 38 | public string Version { get; set; } = string.Empty; 39 | 40 | /// 41 | /// The maximum number of bytes allowed in the repository. 42 | /// 43 | /// 44 | /// Max bytes allowed in the repository. 45 | /// 46 | public ulong StorageMax { get; set; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/CoreApi/TransferProgress.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | /// 6 | /// Reports the progress of 7 | /// a transfer operation. 8 | /// 9 | public class TransferProgress 10 | { 11 | /// 12 | /// The name of the item being transferred. 13 | /// 14 | /// 15 | /// Typically, a relative file path. 16 | /// 17 | public string? Name { get; set; } 18 | 19 | /// 20 | /// The cumuative number of bytes transferred for 21 | /// the . 22 | /// 23 | public ulong Bytes { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Cryptography/BouncyDigest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Ipfs.Cryptography 6 | { 7 | /// 8 | /// Thin wrapper around bouncy castle digests. 9 | /// 10 | /// 11 | /// Makes a Bouncy Caslte IDigest speak .Net HashAlgorithm. 12 | /// 13 | internal class BouncyDigest : System.Security.Cryptography.HashAlgorithm 14 | { 15 | private readonly Org.BouncyCastle.Crypto.IDigest _digest; 16 | 17 | /// 18 | /// Wrap the bouncy castle digest. 19 | /// 20 | public BouncyDigest(Org.BouncyCastle.Crypto.IDigest digest) 21 | { 22 | _digest = digest; 23 | } 24 | 25 | /// 26 | public override void Initialize() 27 | { 28 | _digest.Reset(); 29 | } 30 | 31 | /// 32 | protected override void HashCore(byte[] array, int ibStart, int cbSize) 33 | { 34 | _digest.BlockUpdate(array, ibStart, cbSize); 35 | } 36 | 37 | /// 38 | protected override byte[] HashFinal() 39 | { 40 | var output = new byte[_digest.GetDigestSize()]; 41 | _digest.DoFinal(output, 0); 42 | return output; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Cryptography/DoubleSha256.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | 4 | namespace Ipfs.Cryptography 5 | { 6 | internal class DoubleSha256 : HashAlgorithm 7 | { 8 | private readonly HashAlgorithm _digest = SHA256.Create(); 9 | private byte[]? _round1; 10 | 11 | public override void Initialize() 12 | { 13 | _digest.Initialize(); 14 | } 15 | 16 | public override int HashSize => _digest.HashSize; 17 | 18 | protected override void HashCore(byte[] array, int ibStart, int cbSize) 19 | { 20 | if (_round1 is not null) 21 | { 22 | throw new NotSupportedException("Already called."); 23 | } 24 | 25 | _round1 = _digest.ComputeHash(array, ibStart, cbSize); 26 | } 27 | 28 | protected override byte[] HashFinal() 29 | { 30 | _digest.Initialize(); 31 | return _digest.ComputeHash(_round1); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Cryptography/IdentityHash.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | 4 | namespace Ipfs.Cryptography 5 | { 6 | internal class IdentityHash : HashAlgorithm 7 | { 8 | byte[]? digest; 9 | 10 | public override void Initialize() 11 | { 12 | } 13 | 14 | protected override void HashCore(byte[] array, int ibStart, int cbSize) 15 | { 16 | if (digest is null) 17 | { 18 | digest = new byte[cbSize]; 19 | Buffer.BlockCopy(array, ibStart, digest, 0, cbSize); 20 | return; 21 | } 22 | 23 | var buffer = new byte[digest.Length + cbSize]; 24 | Buffer.BlockCopy(digest, 0, buffer, digest.Length, digest.Length); 25 | Buffer.BlockCopy(array, ibStart, digest, digest.Length, cbSize); 26 | digest = buffer; 27 | } 28 | 29 | protected override byte[] HashFinal() 30 | { 31 | return digest ?? Array.Empty(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Cryptography/Keccak.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * The package was named SHA3 it is really Keccak 3 | * https://medium.com/@ConsenSys/are-you-really-using-sha-3-or-old-code-c5df31ad2b0 4 | * See 5 | * 6 | * The SHA3 package doesn't create .Net Standard package. 7 | * This is a copy of https://bitbucket.org/jdluzen/sha3/raw/d1fd55dc225d18a7fb61515b62d3c8f164d2e788/SHA3/SHA3.cs 8 | * with nullable modifications. 9 | */ 10 | using System; 11 | 12 | #pragma warning disable IDE1006 // Naming Styles 13 | #pragma warning disable IDE0025 // Use expression body for property 14 | #pragma warning disable IDE0027 // Use expression body for accessor 15 | 16 | namespace Ipfs.Cryptography 17 | { 18 | internal abstract class Keccak : System.Security.Cryptography.HashAlgorithm 19 | { 20 | 21 | #region Implementation 22 | public const int KeccakB = 1600; 23 | public const int KeccakNumberOfRounds = 24; 24 | public const int KeccakLaneSizeInBits = 8 * 8; 25 | 26 | public readonly ulong[] RoundConstants; 27 | 28 | protected ulong[] state = new ulong[5 * 5]; //1600 bits 29 | protected byte[]? buffer; 30 | protected int buffLength; 31 | protected int keccakR; 32 | 33 | public int KeccakR 34 | { 35 | get 36 | { 37 | return keccakR; 38 | } 39 | protected set 40 | { 41 | keccakR = value; 42 | } 43 | } 44 | 45 | public int SizeInBytes 46 | { 47 | get 48 | { 49 | return KeccakR / 8; 50 | } 51 | } 52 | 53 | public int HashByteLength 54 | { 55 | get 56 | { 57 | return HashSizeValue / 8; 58 | } 59 | } 60 | 61 | public override bool CanReuseTransform 62 | { 63 | get 64 | { 65 | return true; 66 | } 67 | } 68 | 69 | protected Keccak(int hashBitLength) 70 | { 71 | if (hashBitLength != 224 && hashBitLength != 256 && hashBitLength != 384 && hashBitLength != 512) 72 | { 73 | throw new ArgumentException("hashBitLength must be 224, 256, 384, or 512", "hashBitLength"); 74 | } 75 | 76 | Initialize(); 77 | HashSizeValue = hashBitLength; 78 | switch (hashBitLength) 79 | { 80 | case 224: 81 | KeccakR = 1152; 82 | break; 83 | case 256: 84 | KeccakR = 1088; 85 | break; 86 | case 384: 87 | KeccakR = 832; 88 | break; 89 | case 512: 90 | KeccakR = 576; 91 | break; 92 | } 93 | RoundConstants = new ulong[] 94 | { 95 | 0x0000000000000001UL, 96 | 0x0000000000008082UL, 97 | 0x800000000000808aUL, 98 | 0x8000000080008000UL, 99 | 0x000000000000808bUL, 100 | 0x0000000080000001UL, 101 | 0x8000000080008081UL, 102 | 0x8000000000008009UL, 103 | 0x000000000000008aUL, 104 | 0x0000000000000088UL, 105 | 0x0000000080008009UL, 106 | 0x000000008000000aUL, 107 | 0x000000008000808bUL, 108 | 0x800000000000008bUL, 109 | 0x8000000000008089UL, 110 | 0x8000000000008003UL, 111 | 0x8000000000008002UL, 112 | 0x8000000000000080UL, 113 | 0x000000000000800aUL, 114 | 0x800000008000000aUL, 115 | 0x8000000080008081UL, 116 | 0x8000000000008080UL, 117 | 0x0000000080000001UL, 118 | 0x8000000080008008UL 119 | }; 120 | } 121 | 122 | protected ulong ROL(ulong a, int offset) 123 | { 124 | return (((a) << ((offset) % KeccakLaneSizeInBits)) ^ ((a) >> (KeccakLaneSizeInBits - ((offset) % KeccakLaneSizeInBits)))); 125 | } 126 | 127 | protected void AddToBuffer(byte[] array, ref int offset, ref int count) 128 | { 129 | int amount = Math.Min(count, buffer!.Length - buffLength); 130 | Buffer.BlockCopy(array, offset, buffer, buffLength, amount); 131 | offset += amount; 132 | buffLength += amount; 133 | count -= amount; 134 | } 135 | 136 | public override byte[] Hash 137 | { 138 | get 139 | { 140 | return HashValue; 141 | } 142 | } 143 | 144 | public override int HashSize 145 | { 146 | get 147 | { 148 | return HashSizeValue; 149 | } 150 | } 151 | 152 | #endregion 153 | 154 | public override void Initialize() 155 | { 156 | buffLength = 0; 157 | HashValue = null; 158 | } 159 | 160 | protected override void HashCore(byte[] array, int ibStart, int cbSize) 161 | { 162 | if (ibStart < 0) 163 | { 164 | throw new ArgumentOutOfRangeException("ibStart"); 165 | } 166 | 167 | if (cbSize > array.Length) 168 | { 169 | throw new ArgumentOutOfRangeException("cbSize"); 170 | } 171 | 172 | if (ibStart + cbSize > array.Length) 173 | { 174 | throw new ArgumentOutOfRangeException("ibStart or cbSize"); 175 | } 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/DagCid.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Ipfs 4 | { 5 | /// 6 | /// A wrapper for a that is used in an IPLD Directed Acyclic Graph (DAG). 7 | /// 8 | /// 9 | /// See also . 10 | /// 11 | public record DagCid 12 | { 13 | /// 14 | /// The value of this DAG link. 15 | /// 16 | [JsonProperty("/")] 17 | public required Cid Value { get; set; } 18 | 19 | /// 20 | /// Implicit casting of a to a . 21 | /// 22 | /// The to cast. 23 | public static implicit operator Cid(DagCid dagLink) => dagLink.Value; 24 | 25 | /// 26 | /// Explicit casting of a to a . 27 | /// 28 | /// The to cast." 29 | public static explicit operator DagCid(Cid cid) => new DagCid { Value = cid, }; 30 | 31 | /// 32 | /// Returns the string representation of the . 33 | /// 34 | /// 35 | /// e.g. "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V" 36 | /// 37 | public override string ToString() => $"{Value}"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/DagLink.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Google.Protobuf; 3 | 4 | namespace Ipfs 5 | { 6 | /// 7 | /// A link to another node in the IPFS Merkle DAG. 8 | /// 9 | public class DagLink : IMerkleLink 10 | { 11 | /// 12 | /// Create a new instance of class. 13 | /// 14 | /// The name associated with the linked node. 15 | /// The of the linked node. 16 | /// The serialised size (in bytes) of the linked node. 17 | public DagLink(string? name, Cid id, ulong size) 18 | { 19 | Name = name; 20 | Id = id; 21 | Size = size; 22 | } 23 | 24 | /// 25 | /// Creates a new instance of the class from the 26 | /// specified . 27 | /// 28 | /// 29 | /// Some type of a Merkle link. 30 | /// 31 | public DagLink(IMerkleLink link) 32 | { 33 | Name = link.Name; 34 | Id = link.Id; 35 | Size = link.Size; 36 | } 37 | 38 | /// 39 | /// Creates a new instance of the class from the 40 | /// specified . 41 | /// 42 | /// 43 | /// A containing the binary representation of the 44 | /// DagLink. 45 | /// 46 | public DagLink(Stream stream) 47 | { 48 | (Name, Id, Size) = Read(stream); 49 | } 50 | 51 | /// 52 | /// Creates a new instance of the class from the 53 | /// specified . 54 | /// 55 | /// ( 56 | /// A containing the binary representation of the 57 | /// DagLink. 58 | /// 59 | public DagLink(CodedInputStream stream) 60 | { 61 | (Name, Id, Size) = Read(stream); 62 | } 63 | 64 | /// 65 | public string? Name { get; private set; } 66 | 67 | /// 68 | public Cid Id { get; private set; } 69 | 70 | /// 71 | public ulong Size { get; private set; } 72 | 73 | /// 74 | /// Writes the binary representation of the link to the specified . 75 | /// 76 | /// 77 | /// The to write to. 78 | /// 79 | public void Write(Stream stream) 80 | { 81 | using var cos = new CodedOutputStream(stream, true); 82 | Write(cos); 83 | } 84 | 85 | /// 86 | /// Writes the binary representation of the link to the specified . 87 | /// 88 | /// 89 | /// The to write to. 90 | /// 91 | public void Write(CodedOutputStream stream) 92 | { 93 | stream.WriteTag(1, WireFormat.WireType.LengthDelimited); 94 | Id.Write(stream); 95 | 96 | if (Name is not null) 97 | { 98 | stream.WriteTag(2, WireFormat.WireType.LengthDelimited); 99 | stream.WriteString(Name); 100 | } 101 | 102 | stream.WriteTag(3, WireFormat.WireType.Varint); 103 | stream.WriteInt64((long)Size); 104 | } 105 | 106 | private (string?, Cid, ulong) Read(Stream stream) 107 | { 108 | using var cis = new CodedInputStream(stream, true); 109 | return Read(cis); 110 | } 111 | 112 | private (string?, Cid, ulong) Read(CodedInputStream stream) 113 | { 114 | string? name = null; 115 | Cid? id = null; 116 | ulong size = 0; 117 | while (!stream.IsAtEnd) 118 | { 119 | var tag = stream.ReadTag(); 120 | switch (WireFormat.GetTagFieldNumber(tag)) 121 | { 122 | case 1: 123 | id = Cid.Read(stream); 124 | break; 125 | case 2: 126 | name = stream.ReadString(); 127 | break; 128 | case 3: 129 | size = (ulong)stream.ReadInt64(); 130 | break; 131 | default: 132 | throw new InvalidDataException("Unknown field number"); 133 | } 134 | } 135 | 136 | if (id is null) 137 | { 138 | throw new InvalidDataException($"Missing CID id from record"); 139 | } 140 | 141 | return (name, id, size); 142 | } 143 | 144 | /// 145 | /// Returns the IPFS binary representation as a byte array. 146 | /// 147 | /// 148 | /// A byte array. 149 | /// 150 | public byte[] ToArray() 151 | { 152 | using var ms = new MemoryStream(); 153 | Write(ms); 154 | return ms.ToArray(); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/HexString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.IO; 6 | 7 | namespace Ipfs 8 | { 9 | /// 10 | /// A codec for Hexadecimal. 11 | /// 12 | /// 13 | /// 14 | /// A codec for a hexadecimal string, and . Adds the extension method 15 | /// to encode a byte array and to decode a hexadecimal . 16 | /// 17 | /// 18 | public static class HexString 19 | { 20 | private static readonly string[] LowerCaseHexStrings = 21 | Enumerable.Range(byte.MinValue, byte.MaxValue + 1) 22 | .Select(v => v.ToString("x2")) 23 | .ToArray(); 24 | private static readonly string[] UpperCaseHexStrings = 25 | Enumerable.Range(byte.MinValue, byte.MaxValue + 1) 26 | .Select(v => v.ToString("X2")) 27 | .ToArray(); 28 | private static readonly Dictionary HexBytes = 29 | Enumerable.Range(byte.MinValue, byte.MaxValue + 1) 30 | .SelectMany(v => new [] { 31 | new { Value = v, String = v.ToString("x2") } , 32 | new { Value = v, String = v.ToString("X2") } 33 | } ) 34 | .Distinct() 35 | .ToDictionary(v => v.String, v => (byte) v.Value); 36 | 37 | 38 | /// 39 | /// Converts an array of 8-bit unsigned integers to its equivalent hexadecimal string representation. 40 | /// 41 | /// 42 | /// An array of 8-bit unsigned integers. 43 | /// 44 | /// 45 | /// One of the format specifiers ("G" and "x" for lower-case hex digits, or "X" for the upper-case). 46 | /// The default is "G". 47 | /// 48 | /// 49 | /// The string representation, in hexadecimal, of the contents of . 50 | /// 51 | public static string Encode(byte[] buffer, string format = "G") 52 | { 53 | string[] hexStrings = format switch 54 | { 55 | "G" or "x" => LowerCaseHexStrings, 56 | "X" => UpperCaseHexStrings, 57 | _ => throw new FormatException(string.Format("Invalid HexString format '{0}', only 'G', 'x' or 'X' are allowed.", format)), 58 | }; 59 | var s = new StringBuilder(buffer.Length * 2); 60 | foreach (var v in buffer) 61 | { 62 | s.Append(hexStrings[v]); 63 | } 64 | 65 | return s.ToString(); 66 | } 67 | 68 | /// 69 | /// Converts an array of 8-bit unsigned integers to its equivalent hexadecimal string representation. 70 | /// 71 | /// 72 | /// An array of 8-bit unsigned integers. 73 | /// 74 | /// 75 | /// One of the format specifiers ("G" and "x" for lower-case hex digits, or "X" for the upper-case). 76 | /// The default is "G". 77 | /// 78 | /// 79 | /// The string representation, in hexadecimal, of the contents of . 80 | /// 81 | public static string ToHexString(this byte[] buffer, string format = "G") 82 | { 83 | return Encode(buffer, format); 84 | } 85 | 86 | /// 87 | /// Converts the specified , which encodes binary data as hexadecimal digits, 88 | /// to an equivalent 8-bit unsigned integer array. 89 | /// 90 | /// 91 | /// The hexadecimal string to convert. 92 | /// 93 | /// 94 | /// An array of 8-bit unsigned integers that is equivalent to . 95 | /// 96 | public static byte[] Decode(string s) 97 | { 98 | int n = s.Length; 99 | if (n % 2 != 0) 100 | { 101 | throw new InvalidDataException("The hex string length must be a multiple of 2."); 102 | } 103 | 104 | var buffer = new byte[n / 2]; 105 | for (int i = 0, j = 0; i < n; i += 2, j++) 106 | { 107 | var hex = s.Substring(i, 2); 108 | if (!HexBytes.TryGetValue(hex, out byte value)) 109 | { 110 | throw new InvalidDataException(string.Format("'{0}' is not a valid hexadecimal byte.", hex)); 111 | } 112 | 113 | buffer[j] = value; 114 | } 115 | 116 | return buffer; 117 | } 118 | 119 | /// 120 | /// Converts the specified , which encodes binary data as a hexadecimal string, 121 | /// to an equivalent 8-bit unsigned integer array. 122 | /// 123 | /// 124 | /// The hexadecimal string to convert. 125 | /// 126 | /// 127 | /// An array of 8-bit unsigned integers that is equivalent to . 128 | /// 129 | public static byte[] ToHexBuffer(this string s) 130 | { 131 | return Decode(s); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/IBlockStat.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs 2 | { 3 | /// 4 | /// Represents a block provided to or yielded from the . 5 | /// 6 | /// 7 | /// Analogous to the BlockStat struct in Kubo. See . 8 | /// 9 | public interface IBlockStat : IDataBlock 10 | { 11 | /// 12 | /// The size of the block. 13 | /// 14 | public int Size { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/IDataBlock.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs 2 | { 3 | /// 4 | /// Some data that is stored in IPFS. 5 | /// 6 | /// 7 | /// A DataBlock has a unique . 8 | /// and some data. 9 | /// 10 | /// It is useful to talk about them as "blocks" in Bitswap 11 | /// and other things that do not care about what is being stored. 12 | /// 13 | /// 14 | /// 15 | public interface IDataBlock 16 | { 17 | /// 18 | /// The unique ID of the data. 19 | /// 20 | /// 21 | /// A of the content. 22 | /// 23 | Cid Id { get; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/IFileSystemLink.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs 2 | { 3 | /// 4 | /// A link to another file system node in IPFS. 5 | /// 6 | public interface IFileSystemLink : IMerkleLink 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/IFileSystemNode.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs 2 | { 3 | /// 4 | /// A Directed Acyclic Graph (DAG) for IPFS file system node. 5 | /// 6 | public interface IFileSystemNode : IMerkleNode 7 | { 8 | /// 9 | /// Determines if the node is a directory (folder). 10 | /// 11 | /// 12 | /// true if the node is a directory; Otherwise false, 13 | /// it is some type of a file. 14 | /// 15 | bool IsDirectory { get; } 16 | 17 | /// 18 | /// The file name of the IPFS node. 19 | /// 20 | public string Name { get; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/IKey.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs 2 | { 3 | /// 4 | /// Information about a cryptographic key. 5 | /// 6 | public interface IKey 7 | { 8 | /// 9 | /// Unique identifier. 10 | /// 11 | /// 12 | /// A containing the of the public libp2p-key encoded in the requested Multibase. 13 | /// 14 | /// 15 | /// The CID of the ipns libp2p-key encoded in the requested multibase. 16 | /// 17 | Cid Id { get; } 18 | 19 | /// 20 | /// The locally assigned name to the key. 21 | /// 22 | /// 23 | /// The name is only unique within the local peer node. The 24 | /// is universally unique. 25 | /// 26 | string Name { get; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/IMerkleLink.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs 2 | { 3 | /// 4 | /// A link to another node in IPFS. 5 | /// 6 | public interface IMerkleLink 7 | { 8 | /// 9 | /// A name associated with the linked node. 10 | /// 11 | /// A or null. 12 | /// 13 | /// 14 | /// IPFS considers a null name different from a 15 | /// name; 16 | /// 17 | /// 18 | string? Name { get; } 19 | 20 | /// 21 | /// The unique ID of the link. 22 | /// 23 | /// 24 | /// A of the content. 25 | /// 26 | Cid Id { get; } 27 | 28 | /// 29 | /// The serialised size (in bytes) of the linked node. 30 | /// 31 | /// Number of bytes. 32 | /// 33 | /// Both and have a of type . 34 | /// 35 | /// See . 36 | /// 37 | ulong Size { get; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/IMerkleNode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Ipfs 4 | { 5 | /// 6 | /// A Directed Acyclic Graph (DAG) in IPFS. 7 | /// 8 | /// 9 | /// A MerkleNode has a sequence of navigable 10 | /// and some data. 11 | /// 12 | /// 13 | /// The type of used by this node. 14 | /// 15 | /// 16 | /// 17 | public interface IMerkleNode : IDataBlock 18 | where Link : IMerkleLink 19 | { 20 | /// 21 | /// Links to other nodes. 22 | /// 23 | /// 24 | /// A sequence of . 25 | /// 26 | /// 27 | /// It is never null. 28 | /// 29 | /// The links are sorted ascending by . A null 30 | /// name is compared as "". 31 | /// 32 | /// 33 | IEnumerable Links { get; } 34 | 35 | /// 36 | /// Returns a link to the node. 37 | /// 38 | /// 39 | /// A for the link; defaults to "". 40 | /// 41 | /// 42 | /// A new to the node. 43 | /// 44 | Link ToLink(string name = ""); 45 | 46 | /// 47 | /// The serialised size (in bytes) of the linked node. 48 | /// 49 | /// Number of bytes. 50 | /// 51 | /// Both and have a of type . 52 | /// 53 | /// See . 54 | /// 55 | ulong Size { get; } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/IPublishedMessage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Ipfs.CoreApi; 3 | 4 | namespace Ipfs 5 | { 6 | /// 7 | /// A published message. 8 | /// 9 | /// 10 | /// The is used to publish and subsribe to a message. 11 | /// 12 | /// Interface layout sourced from Kubo API: . 13 | /// 14 | public interface IPublishedMessage 15 | { 16 | /// 17 | /// Contents as a byte array. 18 | /// 19 | /// 20 | /// It is never null. 21 | /// 22 | /// 23 | /// The contents as a sequence of bytes. 24 | /// 25 | byte[] DataBytes { get; } 26 | 27 | /// 28 | /// The sender of the message. 29 | /// 30 | /// 31 | /// The peer that sent the message. 32 | /// 33 | Peer Sender { get; } 34 | 35 | /// 36 | /// The topics of the message. 37 | /// 38 | /// 39 | /// All topics related to this message. 40 | /// 41 | IEnumerable Topics { get; } 42 | 43 | /// 44 | /// The sequence number of the message. 45 | /// 46 | /// 47 | /// A sender unique id for the message. 48 | /// 49 | byte[] SequenceNumber { get; } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/MultiBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Ipfs.Registry; 4 | 5 | namespace Ipfs 6 | { 7 | /// 8 | /// Self identifying base encodings. 9 | /// 10 | /// 11 | /// MultiBase is a protocol for distinguishing base encodings 12 | /// and other simple string encodings. 13 | /// See the registry for supported algorithms. 14 | /// 15 | /// 16 | public static class MultiBase 17 | { 18 | /// 19 | /// The default multi-base algorithm is "base58btc". 20 | /// 21 | public const string DefaultAlgorithmName = "base58btc"; 22 | 23 | /// 24 | /// Gets the with the specified IPFS multi-hash name. 25 | /// 26 | /// 27 | /// The name of an algorithm, see 28 | /// for 29 | /// for IPFS defined names. 30 | /// 31 | /// 32 | /// When is not registered. 33 | /// 34 | private static MultiBaseAlgorithm GetAlgorithm(string name) 35 | { 36 | if (MultiBaseAlgorithm.Names.TryGetValue(name, out MultiBaseAlgorithm? algorithm)) 37 | { 38 | return algorithm; 39 | } 40 | 41 | throw new KeyNotFoundException($"MultiBase algorithm '{name}' is not registered."); 42 | } 43 | 44 | /// 45 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation. 46 | /// 47 | /// 48 | /// An array of 8-bit unsigned integers. 49 | /// 50 | /// 51 | /// The name of the multi-base algorithm to use. See . 52 | /// 53 | /// 54 | /// A starting with the algorithm's and 55 | /// followed by the encoded string representation of the . 56 | /// 57 | /// 58 | /// When is not registered. 59 | /// 60 | public static string Encode(byte[] bytes, string algorithmName = DefaultAlgorithmName) 61 | { 62 | var alg = GetAlgorithm(algorithmName); 63 | return alg.Code + alg.Encode(bytes); 64 | } 65 | 66 | /// 67 | /// Converts the specified , which encodes binary data, 68 | /// to an equivalent 8-bit unsigned integer array. 69 | /// 70 | /// 71 | /// The multi-base string to convert. 72 | /// 73 | /// 74 | /// An array of 8-bit unsigned integers that is equivalent to . 75 | /// 76 | /// 77 | /// When the can not be decoded. 78 | /// 79 | public static byte[] Decode(string s) 80 | { 81 | if (string.IsNullOrWhiteSpace(s)) 82 | { 83 | throw new ArgumentNullException(nameof(s)); 84 | } 85 | 86 | MultiBaseAlgorithm.Codes.TryGetValue(s[0], out MultiBaseAlgorithm alg); 87 | if (alg is null) 88 | { 89 | throw new FormatException($"MultiBase '{s}' is invalid. The code is not registered."); 90 | } 91 | 92 | try 93 | { 94 | return alg.Decode(s.Substring(1)); 95 | } 96 | catch (Exception e) 97 | { 98 | throw new FormatException($"MultiBase '{s}' is invalid; decode failed.", e); 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/MultiCodec.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using Ipfs.Registry; 4 | using Google.Protobuf; 5 | 6 | namespace Ipfs 7 | { 8 | /// 9 | /// Wraps other formats with a tiny bit of self-description. 10 | /// 11 | /// 12 | /// MultiCodec is a self-describing multiformat, it wraps other formats with a 13 | /// tiny bit of self-description. A multicodec identifier is both a varint and the code 14 | /// identifying the following data. 15 | /// 16 | /// Adds the following extension methods to 17 | /// 18 | /// ReadMultiCodec 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | public static class MultiCodec 26 | { 27 | /// 28 | /// Reads a from the . 29 | /// 30 | /// 31 | /// A multicodec encoded . 32 | /// 33 | /// The codec. 34 | /// 35 | /// If the code does not exist, a new is 36 | /// registered with the "codec-x"; where 37 | /// 'x' is the code's decimal represention. 38 | /// 39 | public static Codec ReadMultiCodec(this Stream stream) 40 | { 41 | var code = stream.ReadVarint32(); 42 | Codec.Codes.TryGetValue(code, out Codec codec); 43 | codec ??= Codec.Register($"codec-{code}", code); 44 | return codec; 45 | } 46 | 47 | /// 48 | /// Reads a from the . 49 | /// 50 | /// 51 | /// A multicodec encoded . 52 | /// 53 | /// The codec. 54 | /// 55 | /// If the code does not exist, a new is 56 | /// registered with the "codec-x"; where 57 | /// 'x' is the code's decimal represention. 58 | /// 59 | public static Codec ReadMultiCodec(this CodedInputStream stream) 60 | { 61 | var code = stream.ReadInt32(); 62 | Codec.Codes.TryGetValue(code, out Codec codec); 63 | 64 | return codec ?? Codec.Register($"codec-{code}", code); 65 | } 66 | 67 | /// 68 | /// Writes a to the . 69 | /// 70 | /// 71 | /// A multicodec encoded . 72 | /// 73 | /// 74 | /// The . 75 | /// 76 | /// 77 | /// Writes the of the to 78 | /// the . 79 | /// 80 | /// 81 | /// When is not registered. 82 | /// 83 | public static void WriteMultiCodec(this Stream stream, string name) 84 | { 85 | if (!Codec.Names.TryGetValue(name, out Codec codec)) 86 | { 87 | throw new KeyNotFoundException($"Codec '{name}' is not registered."); 88 | } 89 | stream.WriteVarint(codec.Code); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/NamedContent.cs: -------------------------------------------------------------------------------- 1 | namespace Ipfs 2 | { 3 | /// 4 | /// Content that has an associated name. 5 | /// 6 | /// 7 | public class NamedContent 8 | { 9 | /// 10 | /// Path to the name. 11 | /// 12 | /// 13 | /// Typically /ipns/.... 14 | /// 15 | public string? NamePath { get; set; } 16 | 17 | /// 18 | /// Path to the content. 19 | /// 20 | /// 21 | /// Typically /ipfs/.... 22 | /// 23 | public string? ContentPath { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ProtobufHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using Google.Protobuf; 4 | 5 | namespace Ipfs 6 | { 7 | internal static class ProtobufHelper 8 | { 9 | private static readonly MethodInfo WriteRawBytes = typeof(CodedOutputStream) 10 | .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) 11 | .Single(m => 12 | m.Name == "WriteRawBytes" && m.GetParameters().Count() == 1 13 | ); 14 | private static readonly MethodInfo ReadRawBytes = typeof(CodedInputStream) 15 | .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) 16 | .Single(m => 17 | m.Name == "ReadRawBytes" 18 | ); 19 | 20 | public static void WriteSomeBytes(this CodedOutputStream stream, byte[] bytes) 21 | { 22 | WriteRawBytes.Invoke(stream, new object[] { bytes }); 23 | } 24 | 25 | public static byte[] ReadSomeBytes(this CodedInputStream stream, int length) 26 | { 27 | return (byte[])ReadRawBytes.Invoke(stream, new object[] { length }); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Registry/Codec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Ipfs.Registry 5 | { 6 | /// 7 | /// Metadata for IPFS multi-codec. 8 | /// 9 | /// 10 | /// IPFS assigns a unique and to codecs. 11 | /// See table.csv 12 | /// for the currently defined multi-codecs. 13 | /// 14 | /// 15 | public class Codec 16 | { 17 | internal static Dictionary Names = new(StringComparer.Ordinal); 18 | internal static Dictionary Codes = new(); 19 | 20 | /// 21 | /// Register the standard multi-codecs for IPFS. 22 | /// 23 | /// 24 | static Codec() 25 | { 26 | Register("raw", 0x55); 27 | Register("cms", 0x57); // Not official yet, https://github.com/multiformats/multicodec/pull/69 28 | Register("cbor", 0x51); 29 | Register("protobuf", 0x50); 30 | Register("rlp", 0x60); 31 | Register("bencode", 0x63); 32 | Register("multicodec", 0x30); 33 | Register("multihash", 0x31); 34 | Register("multiaddr", 0x32); 35 | Register("multibase", 0x33); 36 | Register("dag-pb", 0x70); 37 | Register("dag-cbor", 0x71); 38 | Register("libp2p-key", 0x72); 39 | Register("git-raw", 0x78); 40 | Register("eth-block", 0x90); 41 | Register("eth-block-list", 0x91); 42 | Register("eth-tx-trie", 0x92); 43 | Register("eth-tx", 0x93); 44 | Register("eth-tx-receipt-trie", 0x94); 45 | Register("eth-tx-receipt", 0x95); 46 | Register("eth-state-trie", 0x96); 47 | Register("eth-account-snapshot", 0x97); 48 | Register("eth-storage-trie", 0x98); 49 | Register("bitcoin-block", 0xb0); 50 | Register("bitcoin-tx", 0xb1); 51 | Register("zcash-block", 0xc0); 52 | Register("zcash-tx", 0xc1); 53 | Register("stellar-block", 0xd0); 54 | Register("stellar-tx", 0xd1); 55 | Register("torrent-info", 0x7b); 56 | Register("torrent-file", 0x7c); 57 | Register("ed25519-pub", 0xed); 58 | } 59 | 60 | /// 61 | /// The name of the codec. 62 | /// 63 | /// 64 | /// A unique name. 65 | /// 66 | public string Name { get; private set; } = string.Empty; 67 | 68 | /// 69 | /// The IPFS code assigned to the codec. 70 | /// 71 | /// 72 | /// Valid codes at . 73 | /// 74 | public int Code { get; private set; } 75 | 76 | /// 77 | /// Use to create a new instance of a . 78 | /// 79 | private Codec() 80 | { 81 | } 82 | 83 | /// 84 | /// The of the codec. 85 | /// 86 | /// 87 | /// The of the codec. 88 | /// 89 | public override string ToString() 90 | { 91 | return Name; 92 | } 93 | 94 | /// 95 | /// Register a new IPFS codec. 96 | /// 97 | /// 98 | /// The name of the codec. 99 | /// 100 | /// 101 | /// The IPFS code assigned to the codec. 102 | /// 103 | /// 104 | /// A new . 105 | /// 106 | /// 107 | /// When the or is already defined. 108 | /// 109 | /// 110 | /// When the is null or empty. 111 | /// 112 | public static Codec Register(string name, int code) 113 | { 114 | if (string.IsNullOrWhiteSpace(name)) 115 | { 116 | throw new ArgumentNullException(nameof(name)); 117 | } 118 | 119 | if (Names.ContainsKey(name)) 120 | { 121 | throw new ArgumentException(string.Format("The IPFS codec name '{0}' is already defined.", name)); 122 | } 123 | 124 | if (Codes.ContainsKey(code)) 125 | { 126 | throw new ArgumentException(string.Format("The IPFS codec code '{0}' is already defined.", code)); 127 | } 128 | 129 | var a = new Codec 130 | { 131 | Name = name, 132 | Code = code 133 | }; 134 | Names[name] = a; 135 | Codes[code] = a; 136 | 137 | return a; 138 | } 139 | /// 140 | /// Remove an IPFS codec from the registry. 141 | /// 142 | /// 143 | /// The to remove. 144 | /// 145 | public static void Deregister(Codec codec) 146 | { 147 | Names.Remove(codec.Name); 148 | Codes.Remove(codec.Code); 149 | } 150 | 151 | /// 152 | /// A sequence consisting of all codecs. 153 | /// 154 | /// 155 | /// All the registered codecs. 156 | /// 157 | public static IEnumerable All => Names.Values; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipfs-shipyard/net-ipfs-core/fa36f50a0081b3b72fa1b47d14030afdaf30646b/src/icon.png -------------------------------------------------------------------------------- /src/ipfs.ci.snk.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipfs-shipyard/net-ipfs-core/fa36f50a0081b3b72fa1b47d14030afdaf30646b/src/ipfs.ci.snk.enc -------------------------------------------------------------------------------- /src/ipfs.dev.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipfs-shipyard/net-ipfs-core/fa36f50a0081b3b72fa1b47d14030afdaf30646b/src/ipfs.dev.snk -------------------------------------------------------------------------------- /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/Base32Test.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Text; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace Ipfs 6 | { 7 | [TestClass] 8 | public class Base32EncodeTests 9 | { 10 | private static byte[] GetStringBytes(string x) 11 | { 12 | return Encoding.ASCII.GetBytes(x); 13 | } 14 | 15 | [TestMethod] 16 | public void Vector1() 17 | { 18 | Assert.AreEqual(string.Empty, Base32.Encode(GetStringBytes(string.Empty))); 19 | } 20 | 21 | [TestMethod] 22 | public void Vector2() 23 | { 24 | Assert.AreEqual("my", Base32.Encode(GetStringBytes("f"))); 25 | } 26 | 27 | [TestMethod] 28 | public void Vector3() 29 | { 30 | Assert.AreEqual("mzxq", Base32.Encode(GetStringBytes("fo"))); 31 | } 32 | 33 | [TestMethod] 34 | public void Vector4() 35 | { 36 | Assert.AreEqual("mzxw6", Base32.Encode(GetStringBytes("foo"))); 37 | } 38 | 39 | [TestMethod] 40 | public void Vector5() 41 | { 42 | Assert.AreEqual("mzxw6yq", Base32.Encode(GetStringBytes("foob"))); 43 | } 44 | 45 | [TestMethod] 46 | public void Vector6() 47 | { 48 | Assert.AreEqual("mzxw6ytb", Base32.Encode(GetStringBytes("fooba"))); 49 | } 50 | 51 | [TestMethod] 52 | public void Vector7() 53 | { 54 | Assert.AreEqual("mzxw6ytboi", Base32.Encode(GetStringBytes("foobar"))); 55 | } 56 | } 57 | 58 | [TestClass] 59 | public class Base32DecodeTests 60 | { 61 | private static byte[] GetStringBytes(string x) 62 | { 63 | return Encoding.ASCII.GetBytes(x); 64 | } 65 | 66 | [TestMethod] 67 | public void Vector1() 68 | { 69 | CollectionAssert.AreEqual(GetStringBytes(string.Empty), Base32.Decode(string.Empty)); 70 | } 71 | 72 | [TestMethod] 73 | public void Vector2() 74 | { 75 | CollectionAssert.AreEqual(GetStringBytes("f"), Base32.Decode("MY======")); 76 | } 77 | 78 | [TestMethod] 79 | public void Vector3() 80 | { 81 | CollectionAssert.AreEqual(GetStringBytes("fo"), Base32.Decode("MZXQ====")); 82 | } 83 | 84 | [TestMethod] 85 | public void Vector4() 86 | { 87 | CollectionAssert.AreEqual(GetStringBytes("foo"), Base32.Decode("MZXW6===")); 88 | } 89 | 90 | [TestMethod] 91 | public void Vector5() 92 | { 93 | CollectionAssert.AreEqual(GetStringBytes("foob"), Base32.Decode("MZXW6YQ=")); 94 | } 95 | 96 | [TestMethod] 97 | public void Vector6() 98 | { 99 | CollectionAssert.AreEqual(GetStringBytes("fooba"), Base32.Decode("MZXW6YTB")); 100 | } 101 | 102 | [TestMethod] 103 | public void Vector7() 104 | { 105 | CollectionAssert.AreEqual(GetStringBytes("foobar"), Base32.Decode("MZXW6YTBOI======")); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /test/Base58Test.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Linq; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | 6 | namespace Ipfs 7 | { 8 | [TestClass] 9 | public class Base58Test 10 | { 11 | [TestMethod] 12 | public void Encode() 13 | { 14 | Assert.AreEqual("jo91waLQA1NNeBmZKUF", Base58.Encode(Encoding.UTF8.GetBytes("this is a test"))); 15 | Assert.AreEqual("jo91waLQA1NNeBmZKUF", Encoding.UTF8.GetBytes("this is a test").ToBase58()); 16 | } 17 | 18 | [TestMethod] 19 | public void Decode() 20 | { 21 | Assert.AreEqual("this is a test", Encoding.UTF8.GetString(Base58.Decode("jo91waLQA1NNeBmZKUF"))); 22 | Assert.AreEqual("this is a test", Encoding.UTF8.GetString("jo91waLQA1NNeBmZKUF".FromBase58())); 23 | } 24 | 25 | /// 26 | /// C# version of base58Test in 27 | /// 28 | [TestMethod] 29 | public void Java() 30 | { 31 | string input = "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB"; 32 | byte[] output = Base58.Decode(input); 33 | string encoded = Base58.Encode(output); 34 | Assert.AreEqual(input, encoded); 35 | } 36 | 37 | [TestMethod] 38 | public void Decode_Bad() 39 | { 40 | ExceptionAssert.Throws(() => Base58.Decode("jo91waLQA1NNeBmZKUF==")); 41 | } 42 | 43 | [TestMethod] 44 | public void Zero() 45 | { 46 | Assert.AreEqual("1111111", Base58.Encode(new byte[7])); 47 | Assert.AreEqual(7, Base58.Decode("1111111").Length); 48 | Assert.IsTrue(Base58.Decode("1111111").All(b => b == 0)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/CoreApi/BitswapLedgerTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace Ipfs.CoreApi 4 | { 5 | [TestClass] 6 | public class BitswapLedgerTest 7 | { 8 | [TestMethod] 9 | public void Defaults() 10 | { 11 | var ledger = new BitswapLedger(); 12 | Assert.IsNull(ledger.Peer); 13 | Assert.AreEqual(0ul, ledger.BlocksExchanged); 14 | Assert.AreEqual(0ul, ledger.DataReceived); 15 | Assert.AreEqual(0ul, ledger.DataSent); 16 | Assert.AreEqual(0f, ledger.DebtRatio); 17 | Assert.IsTrue(ledger.IsInDebt); 18 | } 19 | 20 | [TestMethod] 21 | public void DebtRatio_Positive() 22 | { 23 | var ledger = new BitswapLedger { DataSent = 1024 * 1024 }; 24 | Assert.IsTrue(ledger.DebtRatio >= 1); 25 | Assert.IsFalse(ledger.IsInDebt); 26 | } 27 | 28 | [TestMethod] 29 | public void DebtRatio_Negative() 30 | { 31 | var ledger = new BitswapLedger { DataReceived = 1024 * 1024 }; 32 | Assert.IsTrue(ledger.DebtRatio < 1); 33 | Assert.IsTrue(ledger.IsInDebt); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/CoreApi/PingResultTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace Ipfs.CoreApi 5 | { 6 | [TestClass] 7 | public class PingResultTest 8 | { 9 | [TestMethod] 10 | public void Properties() 11 | { 12 | var time = TimeSpan.FromSeconds(3); 13 | var r = new PingResult 14 | { 15 | Success = true, 16 | Text = "ping", 17 | Time = time 18 | }; 19 | Assert.AreEqual(true, r.Success); 20 | Assert.AreEqual("ping", r.Text); 21 | Assert.AreEqual(time, r.Time); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/DagLinkTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace Ipfs 4 | { 5 | [TestClass] 6 | public class DagLinkTest 7 | { 8 | [TestMethod] 9 | public void Creating() 10 | { 11 | var link = new DagLink("abc", "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V", 5); 12 | Assert.AreEqual("abc", link.Name); 13 | Assert.AreEqual("QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V", (string)link.Id); 14 | Assert.AreEqual(5, link.Size); 15 | } 16 | 17 | [TestMethod] 18 | public void Cloning() 19 | { 20 | var link = new DagLink("abc", "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V", 5); 21 | var clone = new DagLink(link); 22 | 23 | Assert.AreEqual("abc", clone.Name); 24 | Assert.AreEqual("QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V", (string)clone.Id); 25 | Assert.AreEqual(5, clone.Size); 26 | } 27 | 28 | [TestMethod] 29 | public void Encoding() 30 | { 31 | var encoded = "0a22122023dca2a7429612378554b0bb5b85012dec00a17cc2c673f17d2b76a50b839cd51201611803"; 32 | var link = new DagLink("a", "QmQke7LGtfu3GjFP3AnrP8vpEepQ6C5aJSALKAq653bkRi", 3); 33 | Assert.AreEqual(encoded, link.ToArray().ToHexString()); 34 | } 35 | 36 | [TestMethod] 37 | public void Encoding_EmptyName() 38 | { 39 | var encoded = "0a22122023dca2a7429612378554b0bb5b85012dec00a17cc2c673f17d2b76a50b839cd512001803"; 40 | var link = new DagLink("", "QmQke7LGtfu3GjFP3AnrP8vpEepQ6C5aJSALKAq653bkRi", 3); 41 | Assert.AreEqual(encoded, link.ToArray().ToHexString()); 42 | } 43 | 44 | [TestMethod] 45 | public void Encoding_NullName() 46 | { 47 | var encoded = "0a22122023dca2a7429612378554b0bb5b85012dec00a17cc2c673f17d2b76a50b839cd51803"; 48 | var link = new DagLink(null, "QmQke7LGtfu3GjFP3AnrP8vpEepQ6C5aJSALKAq653bkRi", 3); 49 | Assert.AreEqual(encoded, link.ToArray().ToHexString()); 50 | } 51 | 52 | [TestMethod] 53 | public void Cid_V1() 54 | { 55 | var link = new DagLink("hello", "zB7NCdng5WffuNCgHu4PhDj7nbtuVrhPc2pMhanNxYKRsECdjX9nd44g6CRu2xNrj2bG2NNaTsveL5zDGWhbfiug3VekW", 11); 56 | Assert.AreEqual("hello", link.Name); 57 | Assert.AreEqual(1, link.Id.Version); 58 | Assert.AreEqual("raw", link.Id.ContentType); 59 | Assert.AreEqual("sha2-512", link.Id.Hash.Algorithm.Name); 60 | Assert.AreEqual(11, link.Size); 61 | } 62 | 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/DurationTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace Ipfs 5 | { 6 | [TestClass] 7 | public class DurationTest 8 | { 9 | [TestMethod] 10 | public void Parsing_Examples() 11 | { 12 | Assert.AreEqual(TimeSpan.FromMilliseconds(300), Duration.Parse("300ms")); 13 | Assert.AreEqual(TimeSpan.FromHours(-1.5), Duration.Parse("-1.5h")); 14 | Assert.AreEqual(new TimeSpan(2, 45, 0), Duration.Parse("2h45m")); 15 | Assert.AreEqual(new TimeSpan(0, 1, 0) + TimeSpan.FromSeconds(4.483878032), Duration.Parse("1m4.483878032s")); 16 | } 17 | 18 | [TestMethod] 19 | public void Parsing_Zero() 20 | { 21 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("0s")); 22 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("0µs")); 23 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("0ns")); 24 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("n/a")); 25 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("unknown")); 26 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("")); 27 | } 28 | 29 | [TestMethod] 30 | public void Parsing_Negative() 31 | { 32 | Assert.AreEqual(TimeSpan.FromHours(-2), Duration.Parse("-1.5h30m")); 33 | } 34 | 35 | [TestMethod] 36 | public void Parsing_Submilliseconds() 37 | { 38 | // Note: resolution of TimeSpan is 100ns, e.g. 1 tick. 39 | Assert.AreEqual(TimeSpan.FromTicks(2), Duration.Parse("200ns")); 40 | Assert.AreEqual(TimeSpan.FromTicks(2000), Duration.Parse("200us")); 41 | Assert.AreEqual(TimeSpan.FromTicks(2000), Duration.Parse("200µs")); 42 | } 43 | 44 | [TestMethod] 45 | public void Parsing_MissingNumber() 46 | { 47 | ExceptionAssert.Throws(() => 48 | { 49 | var _ = Duration.Parse("s"); 50 | }); 51 | } 52 | 53 | [TestMethod] 54 | public void Parsing_MissingUnit() 55 | { 56 | ExceptionAssert.Throws(() => 57 | { 58 | var _ = Duration.Parse("1"); 59 | }, "Missing IPFS duration unit."); 60 | } 61 | 62 | [TestMethod] 63 | public void Parsing_InvalidUnit() 64 | { 65 | ExceptionAssert.Throws(() => 66 | { 67 | var _ = Duration.Parse("1jiffy"); 68 | }, "Unknown IPFS duration unit 'jiffy'."); 69 | } 70 | 71 | [TestMethod] 72 | public void Stringify() 73 | { 74 | Assert.AreEqual("0s", Duration.Stringify(TimeSpan.Zero)); 75 | Assert.AreEqual("n/a", Duration.Stringify(TimeSpan.Zero, "n/a")); 76 | 77 | Assert.AreEqual("2h", Duration.Stringify(new TimeSpan(2, 0, 0))); 78 | Assert.AreEqual("3m", Duration.Stringify(new TimeSpan(0, 3, 0))); 79 | Assert.AreEqual("4s", Duration.Stringify(new TimeSpan(0, 0, 4))); 80 | Assert.AreEqual("5ms", Duration.Stringify(new TimeSpan(0, 0, 0, 0, 5))); 81 | Assert.AreEqual("2h4s", Duration.Stringify(new TimeSpan(2, 0, 4))); 82 | Assert.AreEqual("26h3m4s5ms", Duration.Stringify(new TimeSpan(1, 2, 3, 4, 5))); 83 | 84 | Assert.AreEqual("-48h", Duration.Stringify(TimeSpan.FromDays(-2))); 85 | Assert.AreEqual("-2h", Duration.Stringify(TimeSpan.FromHours(-2))); 86 | Assert.AreEqual("-1h30m", Duration.Stringify(TimeSpan.FromHours(-1.5))); 87 | 88 | Assert.AreEqual("200ns", Duration.Stringify(TimeSpan.FromTicks(2))); 89 | Assert.AreEqual("200us", Duration.Stringify(TimeSpan.FromTicks(2000))); 90 | Assert.AreEqual("200us300ns", Duration.Stringify(TimeSpan.FromTicks(2003))); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /test/ExceptionAssert.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace Ipfs 6 | { 7 | /// 8 | /// Asserting an . 9 | /// 10 | public static class ExceptionAssert 11 | { 12 | public static T Throws(Action action, string? expectedMessage = null) where T : Exception 13 | { 14 | try 15 | { 16 | action(); 17 | } 18 | catch (AggregateException e) 19 | { 20 | var match = e.InnerExceptions.OfType().FirstOrDefault(); 21 | if (match is not null) 22 | { 23 | if (expectedMessage is not null) 24 | { 25 | Assert.AreEqual(expectedMessage, match.Message, "Wrong exception message."); 26 | } 27 | 28 | return match; 29 | } 30 | 31 | throw; 32 | } 33 | catch (T e) 34 | { 35 | if (expectedMessage is not null) 36 | { 37 | Assert.AreEqual(expectedMessage, e.Message); 38 | } 39 | 40 | return e; 41 | } 42 | Assert.Fail("Exception of type {0} should be thrown.", typeof(T)); 43 | 44 | // The compiler doesn't know that Assert.Fail will always throw an exception 45 | throw new Exception(); 46 | } 47 | 48 | // Avoids analyzer recommendations related to unused values. 49 | public static T Throws(Func func) where T : Exception 50 | { 51 | return Throws(() => { var t = func(); }); 52 | } 53 | 54 | // Avoids analyzer recommendations related to unused values. 55 | public static T Throws(Func func, string? expectedMessage = null) where T : Exception 56 | { 57 | return Throws(() => { var t = func(); }, expectedMessage); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/HexStringTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.IO; 5 | 6 | namespace Ipfs 7 | { 8 | [TestClass] 9 | public class HexStringTest 10 | { 11 | [TestMethod] 12 | public void Encode() 13 | { 14 | var buffer = Enumerable.Range(byte.MinValue, byte.MaxValue).Select(b => (byte) b).ToArray(); 15 | var lowerHex = string.Concat(buffer.Select(b => b.ToString("x2")).ToArray()); 16 | var upperHex = string.Concat(buffer.Select(b => b.ToString("X2")).ToArray()); 17 | 18 | Assert.AreEqual(lowerHex, buffer.ToHexString(), "encode default"); 19 | Assert.AreEqual(lowerHex, buffer.ToHexString("G"), "encode general"); 20 | Assert.AreEqual(lowerHex, buffer.ToHexString("x"), "encode lower"); 21 | Assert.AreEqual(upperHex, buffer.ToHexString("X"), "encode upper"); 22 | } 23 | 24 | [TestMethod] 25 | public void Decode() 26 | { 27 | var buffer = Enumerable.Range(byte.MinValue, byte.MaxValue).Select(b => (byte)b).ToArray(); 28 | var lowerHex = string.Concat(buffer.Select(b => b.ToString("x2")).ToArray()); 29 | var upperHex = string.Concat(buffer.Select(b => b.ToString("X2")).ToArray()); 30 | 31 | CollectionAssert.AreEqual(buffer, lowerHex.ToHexBuffer(), "decode lower"); 32 | CollectionAssert.AreEqual(buffer, upperHex.ToHexBuffer(), "decode upper"); 33 | } 34 | 35 | [TestMethod] 36 | public void InvalidFormatSpecifier() 37 | { 38 | ExceptionAssert.Throws(() => HexString.Encode(Array.Empty(), "...")); 39 | } 40 | 41 | [TestMethod] 42 | public void InvalidHexStrings() 43 | { 44 | ExceptionAssert.Throws(() => HexString.Decode("0")); 45 | ExceptionAssert.Throws(() => HexString.Decode("0Z")); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/IpfsCoreTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 10.0 6 | 7 | false 8 | portable 9 | Ipfs 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/NamedContentTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace Ipfs 4 | { 5 | [TestClass] 6 | public class NamedContentTest 7 | { 8 | [TestMethod] 9 | public void Properties() 10 | { 11 | var nc = new NamedContent 12 | { 13 | ContentPath = "/ipfs/...", 14 | NamePath = "/ipns/..." 15 | }; 16 | Assert.AreEqual("/ipfs/...", nc.ContentPath); 17 | Assert.AreEqual("/ipns/...", nc.NamePath); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/NetworkProtocolTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Google.Protobuf; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | 6 | namespace Ipfs 7 | { 8 | [TestClass] 9 | public class NetworkProtocolTest 10 | { 11 | [TestMethod] 12 | public void Stringing() 13 | { 14 | Assert.AreEqual("/tcp/8080", new MultiAddress("/tcp/8080").Protocols[0].ToString()); 15 | } 16 | 17 | [TestMethod] 18 | public void Register_Name_Already_Exists() 19 | { 20 | ExceptionAssert.Throws(() => NetworkProtocol.Register()); 21 | } 22 | 23 | [TestMethod] 24 | public void Register_Code_Already_Exists() 25 | { 26 | ExceptionAssert.Throws(() => NetworkProtocol.Register()); 27 | } 28 | 29 | private class NameExists : NetworkProtocol 30 | { 31 | public override string Name => "tcp"; 32 | public override uint Code => 0x7FFF; 33 | public override void ReadValue(CodedInputStream stream) { } 34 | public override void ReadValue(TextReader stream) { } 35 | public override void WriteValue(CodedOutputStream stream) { } 36 | } 37 | 38 | private class CodeExists : NetworkProtocol 39 | { 40 | public override string Name => "x-tcp"; 41 | public override uint Code => 6; 42 | public override void ReadValue(CodedInputStream stream) { } 43 | public override void ReadValue(TextReader stream) { } 44 | public override void WriteValue(CodedOutputStream stream) { } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/PeerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace Ipfs 6 | { 7 | [TestClass] 8 | public class PeerTest 9 | { 10 | private const string MarsId = "QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3"; 11 | private const string PlutoId = "QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM"; 12 | private const string MarsPublicKey = "CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKGUtbRQf+a9SBHFEruNAUatS/tsGUnHuCtifGrlbYPELD3UyyhWf/FYczBCavx3i8hIPEW2jQv4ehxQxi/cg9SHswZCQblSi0ucwTBFr8d40JEiyB9CcapiMdFQxdMgGvXEOQdLz1pz+UPUDojkdKZq8qkkeiBn7KlAoGEocnmpAgMBAAE="; 13 | private const string MarsAddress = "/ip4/10.1.10.10/tcp/29087/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3"; 14 | 15 | [TestMethod] 16 | public new void ToString() 17 | { 18 | Assert.AreEqual(string.Empty, new Peer().ToString()); 19 | Assert.AreEqual(MarsId, new Peer { Id = MarsId }.ToString()); 20 | } 21 | 22 | [TestMethod] 23 | public void DefaultValues() 24 | { 25 | var peer = new Peer(); 26 | Assert.IsNull(peer.Id); 27 | Assert.AreEqual(0, peer.Addresses.Count()); 28 | Assert.AreEqual("unknown/0.0", peer.ProtocolVersion); 29 | Assert.AreEqual("unknown/0.0", peer.AgentVersion); 30 | Assert.IsNull(peer.PublicKey); 31 | Assert.AreEqual(false, peer.IsValid()); // missing peer ID 32 | Assert.IsNull(peer.ConnectedAddress); 33 | Assert.IsFalse(peer.Latency.HasValue); 34 | } 35 | 36 | [TestMethod] 37 | public void ConnectedPeer() 38 | { 39 | var peer = new Peer 40 | { 41 | ConnectedAddress = new MultiAddress(MarsAddress), 42 | Latency = TimeSpan.FromHours(3.03 * 2) 43 | }; 44 | Assert.AreEqual(MarsAddress, peer.ConnectedAddress.ToString()); 45 | Assert.AreEqual(3.03 * 2, peer.Latency.Value.TotalHours); 46 | } 47 | 48 | [TestMethod] 49 | public void Validation_No_Id() 50 | { 51 | var peer = new Peer(); 52 | Assert.AreEqual(false, peer.IsValid()); 53 | } 54 | 55 | [TestMethod] 56 | public void Validation_With_Id() 57 | { 58 | Peer peer = MarsId; 59 | Assert.AreEqual(true, peer.IsValid()); 60 | } 61 | 62 | [TestMethod] 63 | public void Validation_With_Id_Pubkey() 64 | { 65 | var peer = new Peer 66 | { 67 | Id = MarsId, 68 | PublicKey = MarsPublicKey 69 | }; 70 | Assert.AreEqual(true, peer.IsValid()); 71 | } 72 | 73 | [TestMethod] 74 | public void Validation_With_Id_Invalid_Pubkey() 75 | { 76 | var peer = new Peer 77 | { 78 | Id = PlutoId, 79 | PublicKey = MarsPublicKey 80 | }; 81 | Assert.AreEqual(false, peer.IsValid()); 82 | } 83 | 84 | [TestMethod] 85 | public void Value_Equality() 86 | { 87 | var a0 = new Peer { Id = MarsId }; 88 | var a1 = new Peer { Id = MarsId }; 89 | var b = new Peer { Id = PlutoId }; 90 | Peer? c = null; 91 | Peer? d = null; 92 | 93 | Assert.IsTrue(c == d); 94 | Assert.IsFalse(c == b); 95 | Assert.IsFalse(b == c); 96 | 97 | Assert.IsFalse(c != d); 98 | Assert.IsTrue(c != b); 99 | Assert.IsTrue(b != c); 100 | 101 | #pragma warning disable 1718 102 | Assert.IsTrue(a0 == a0); 103 | Assert.IsTrue(a0 == a1); 104 | Assert.IsFalse(a0 == b); 105 | 106 | #pragma warning disable 1718 107 | Assert.IsFalse(a0 != a0); 108 | Assert.IsFalse(a0 != a1); 109 | Assert.IsTrue(a0 != b); 110 | 111 | Assert.IsTrue(a0.Equals(a0)); 112 | Assert.IsTrue(a0.Equals(a1)); 113 | Assert.IsFalse(a0.Equals(b)); 114 | 115 | Assert.AreEqual(a0, a0); 116 | Assert.AreEqual(a0, a1); 117 | Assert.AreNotEqual(a0, b); 118 | 119 | Assert.AreEqual(a0, a0); 120 | Assert.AreEqual(a0, a1); 121 | Assert.AreNotEqual(a0, b); 122 | 123 | Assert.AreEqual(a0.GetHashCode(), a0.GetHashCode()); 124 | Assert.AreEqual(a0.GetHashCode(), a1.GetHashCode()); 125 | Assert.AreNotEqual(a0.GetHashCode(), b.GetHashCode()); 126 | } 127 | 128 | 129 | [TestMethod] 130 | public void Implicit_Conversion_From_String() 131 | { 132 | Peer a = MarsId; 133 | Assert.IsInstanceOfType(a, typeof(Peer)); 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /test/Registry/CodecTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace Ipfs.Registry 6 | { 7 | [TestClass] 8 | public class CodecTest 9 | { 10 | [TestMethod] 11 | public void Bad_Name() 12 | { 13 | ExceptionAssert.Throws(() => Codec.Register(null!, 1)); 14 | ExceptionAssert.Throws(() => Codec.Register("", 1)); 15 | ExceptionAssert.Throws(() => Codec.Register(" ", 1)); 16 | } 17 | 18 | [TestMethod] 19 | public void Name_Already_Exists() 20 | { 21 | ExceptionAssert.Throws(() => Codec.Register("raw", 1)); 22 | } 23 | 24 | [TestMethod] 25 | public void Code_Already_Exists() 26 | { 27 | ExceptionAssert.Throws(() => Codec.Register("raw-x", 0x55)); 28 | } 29 | 30 | [TestMethod] 31 | public void Algorithms_Are_Enumerable() 32 | { 33 | Assert.AreNotEqual(0, Codec.All.Count()); 34 | } 35 | 36 | [TestMethod] 37 | public void Register() 38 | { 39 | var codec = Codec.Register("something-new", 0x0bad); 40 | try 41 | { 42 | Assert.AreEqual("something-new", codec.Name); 43 | Assert.AreEqual("something-new", codec.ToString()); 44 | Assert.AreEqual(0x0bad, codec.Code); 45 | } 46 | finally 47 | { 48 | Codec.Deregister(codec); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/Registry/HashingAlgorithmTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | 6 | namespace Ipfs.Registry 7 | { 8 | [TestClass] 9 | public class HashingAlgorithmTest 10 | { 11 | [TestMethod] 12 | public void GetHasher() 13 | { 14 | using var hasher = HashingAlgorithm.GetAlgorithm("sha3-256"); 15 | Assert.IsNotNull(hasher); 16 | var input = new byte[] { 0xe9 }; 17 | var expected = "f0d04dd1e6cfc29a4460d521796852f25d9ef8d28b44ee91ff5b759d72c1e6d6".ToHexBuffer(); 18 | 19 | var actual = hasher.ComputeHash(input); 20 | CollectionAssert.AreEqual(expected, actual); 21 | } 22 | 23 | [TestMethod] 24 | public void GetHasher_Unknown() 25 | { 26 | ExceptionAssert.Throws(() => HashingAlgorithm.GetAlgorithm("unknown")); 27 | } 28 | 29 | [TestMethod] 30 | public void GetMetadata() 31 | { 32 | var info = HashingAlgorithm.GetAlgorithmMetadata("sha3-256"); 33 | Assert.IsNotNull(info); 34 | Assert.AreEqual("sha3-256", info.Name); 35 | Assert.AreEqual(0x16, info.Code); 36 | Assert.AreEqual(256 /8, info.DigestSize); 37 | Assert.IsNotNull(info.Hasher); 38 | } 39 | 40 | [TestMethod] 41 | public void GetMetadata_Unknown() 42 | { 43 | ExceptionAssert.Throws(() => HashingAlgorithm.GetAlgorithmMetadata("unknown")); 44 | } 45 | 46 | [TestMethod] 47 | public void GetMetadata_Alias() 48 | { 49 | var info = HashingAlgorithm.GetAlgorithmMetadata("id"); 50 | Assert.IsNotNull(info); 51 | Assert.AreEqual("identity", info.Name); 52 | Assert.AreEqual(0, info.Code); 53 | Assert.AreEqual(0, info.DigestSize); 54 | Assert.IsNotNull(info.Hasher); 55 | } 56 | 57 | [TestMethod] 58 | public void HashingAlgorithm_Bad_Name() 59 | { 60 | ExceptionAssert.Throws(() => HashingAlgorithm.Register(null!, 1, 1)); 61 | ExceptionAssert.Throws(() => HashingAlgorithm.Register("", 1, 1)); 62 | ExceptionAssert.Throws(() => HashingAlgorithm.Register(" ", 1, 1)); 63 | } 64 | 65 | [TestMethod] 66 | public void HashingAlgorithm_Name_Already_Exists() 67 | { 68 | ExceptionAssert.Throws(() => HashingAlgorithm.Register("sha1", 0x11, 1)); 69 | } 70 | 71 | [TestMethod] 72 | public void HashingAlgorithm_Number_Already_Exists() 73 | { 74 | ExceptionAssert.Throws(() => HashingAlgorithm.Register("sha1-x", 0x11, 1)); 75 | } 76 | 77 | [TestMethod] 78 | public void HashingAlgorithms_Are_Enumerable() 79 | { 80 | Assert.IsTrue(5 <= HashingAlgorithm.All.Count()); 81 | } 82 | 83 | [TestMethod] 84 | public void HashingAlgorithm_Bad_Alias() 85 | { 86 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias(null!, "sha1")); 87 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias("", "sha1")); 88 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias(" ", "sha1")); 89 | } 90 | 91 | [TestMethod] 92 | public void HashingAlgorithm_Alias_Already_Exists() 93 | { 94 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias("id", "identity")); 95 | } 96 | 97 | [TestMethod] 98 | public void HashingAlgorithm_Alias_Target_Does_Not_Exist() 99 | { 100 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias("foo", "sha1-x")); 101 | } 102 | 103 | [TestMethod] 104 | public void HashingAlgorithm_Alias_Target_Is_Bad() 105 | { 106 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias("foo", " ")); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /test/Registry/MultibaseAlgorithmTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace Ipfs.Registry 6 | { 7 | [TestClass] 8 | public class MultiBaseAlgorithmTest 9 | { 10 | [TestMethod] 11 | public void Bad_Name() 12 | { 13 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register(null!, '?')); 14 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register("", '?')); 15 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register(" ", '?')); 16 | } 17 | 18 | [TestMethod] 19 | public void Name_Already_Exists() 20 | { 21 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register("base58btc", 'z')); 22 | } 23 | 24 | [TestMethod] 25 | public void Code_Already_Exists() 26 | { 27 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register("base58btc-x", 'z')); 28 | } 29 | 30 | [TestMethod] 31 | public void Algorithms_Are_Enumerable() 32 | { 33 | Assert.AreNotEqual(0, MultiBaseAlgorithm.All.Count()); 34 | } 35 | 36 | [TestMethod] 37 | public void Roundtrip_All_Algorithms() 38 | { 39 | var bytes = new byte[] { 1, 2, 3, 4, 5 }; 40 | 41 | foreach (var alg in MultiBaseAlgorithm.All) 42 | { 43 | var s = alg.Encode(bytes); 44 | CollectionAssert.AreEqual(bytes, alg.Decode(s), alg.Name); 45 | } 46 | } 47 | 48 | [TestMethod] 49 | public void Name_Is_Also_ToString() 50 | { 51 | foreach (var alg in MultiBaseAlgorithm.All) 52 | { 53 | Assert.AreEqual(alg.Name, alg.ToString()); 54 | } 55 | } 56 | 57 | [TestMethod] 58 | public void Known_But_NYI() 59 | { 60 | var alg = MultiBaseAlgorithm.Register("nyi", 'n'); 61 | try 62 | { 63 | ExceptionAssert.Throws(() => alg.Encode(null!)); 64 | ExceptionAssert.Throws(() => alg.Decode(null!)); 65 | } 66 | finally 67 | { 68 | MultiBaseAlgorithm.Deregister(alg); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /test/VarintTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | 7 | namespace Ipfs 8 | { 9 | [TestClass] 10 | public class VarintTest 11 | { 12 | [TestMethod] 13 | public void Zero() 14 | { 15 | var x = new byte[] { 0 }; 16 | Assert.AreEqual(1, Varint.RequiredBytes(0)); 17 | CollectionAssert.AreEqual(x, Varint.Encode(0)); 18 | Assert.AreEqual(0, Varint.DecodeInt32(x)); 19 | } 20 | 21 | [TestMethod] 22 | public void ThreeHundred() 23 | { 24 | var x = new byte[] { 0xAC, 0x02 }; 25 | Assert.AreEqual(2, Varint.RequiredBytes(300)); 26 | CollectionAssert.AreEqual(x, Varint.Encode(300)); 27 | Assert.AreEqual(300, Varint.DecodeInt32(x)); 28 | } 29 | 30 | [TestMethod] 31 | public void Decode_From_Offset() 32 | { 33 | var x = new byte[] { 0x00, 0xAC, 0x02 }; 34 | Assert.AreEqual(300, Varint.DecodeInt32(x, 1)); 35 | } 36 | 37 | [TestMethod] 38 | public void MaxLong() 39 | { 40 | var x = "ffffffffffffffff7f".ToHexBuffer(); 41 | Assert.AreEqual(9, Varint.RequiredBytes(long.MaxValue)); 42 | CollectionAssert.AreEqual(x, Varint.Encode(long.MaxValue)); 43 | Assert.AreEqual(long.MaxValue, Varint.DecodeInt64(x)); 44 | } 45 | 46 | [TestMethod] 47 | public void Encode_Negative() 48 | { 49 | ExceptionAssert.Throws(() => Varint.Encode(-1)); 50 | } 51 | 52 | [TestMethod] 53 | public void TooBig_Int32() 54 | { 55 | var bytes = Varint.Encode((long)int.MaxValue + 1); 56 | ExceptionAssert.Throws(() => Varint.DecodeInt32(bytes)); 57 | } 58 | 59 | [TestMethod] 60 | public void TooBig_Int64() 61 | { 62 | var bytes = "ffffffffffffffffff7f".ToHexBuffer(); 63 | ExceptionAssert.Throws(() => Varint.DecodeInt64(bytes)); 64 | } 65 | 66 | [TestMethod] 67 | public void Unterminated() 68 | { 69 | var bytes = "ff".ToHexBuffer(); 70 | ExceptionAssert.Throws(() => Varint.DecodeInt64(bytes)); 71 | } 72 | 73 | [TestMethod] 74 | public void Empty() 75 | { 76 | var bytes = Array.Empty(); 77 | ExceptionAssert.Throws(() => Varint.DecodeInt64(bytes)); 78 | } 79 | 80 | [TestMethod] 81 | public async Task WriteAsync() 82 | { 83 | using var ms = new MemoryStream(); 84 | await ms.WriteVarintAsync(long.MaxValue); 85 | ms.Position = 0; 86 | Assert.AreEqual(long.MaxValue, ms.ReadVarint64()); 87 | } 88 | 89 | [TestMethod] 90 | public void WriteAsync_Negative() 91 | { 92 | var ms = new MemoryStream(); 93 | ExceptionAssert.Throws(() => ms.WriteVarintAsync(-1).Wait()); 94 | } 95 | 96 | [TestMethod] 97 | public void WriteAsync_Cancel() 98 | { 99 | var ms = new MemoryStream(); 100 | var cs = new CancellationTokenSource(); 101 | cs.Cancel(); 102 | ExceptionAssert.Throws(() => ms.WriteVarintAsync(0, cs.Token).Wait()); 103 | } 104 | 105 | [TestMethod] 106 | public async Task ReadAsync() 107 | { 108 | using var ms = new MemoryStream("ffffffffffffffff7f".ToHexBuffer()); 109 | var v = await ms.ReadVarint64Async(); 110 | Assert.AreEqual(long.MaxValue, v); 111 | } 112 | 113 | [TestMethod] 114 | public void ReadAsync_Cancel() 115 | { 116 | var ms = new MemoryStream(new byte[] { 0 }); 117 | var cs = new CancellationTokenSource(); 118 | cs.Cancel(); 119 | ExceptionAssert.Throws(() => ms.ReadVarint32Async(cs.Token).Wait()); 120 | } 121 | 122 | [TestMethod] 123 | public void Example() 124 | { 125 | for (long v = 1; v <= 0xFFFFFFFL; v <<= 4) 126 | { 127 | Console.Write($"| {v} (0x{v.ToString("x")}) "); 128 | Console.WriteLine($"| {Varint.Encode(v).ToHexString()} |"); 129 | } 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------