aioipfs¶
aioipfs is an asynchronous Python client library for kubo (formerly called go-ipfs), which is the reference implementation of the IPFS (Interplanetary Filesystem) protocol.
aioipfs uses the aiohttp library to access kubo’s RPC endpoints.
Installation¶
You can use any Python version that supports asyncio and asynchronous generators (from Python version 3.6 to version 3.12).
pip install aioipfs
Support for CAR (Content-Addressable aRchives) decoding (with the ipfs-car-decoder package) can be enabled with the car extra:
pip install 'aioipfs[car]'
If you want to use orjson to decode JSON messages:
pip install 'aioipfs[orjson]'
To install the dependencies required by bohort, a REPL CLI tool to interact with kubo nodes:
pip install 'aioipfs[bohort]'
Checkout the bohort documentation here.
Async IPFS client¶
When creating a AsyncIPFS
client instance it’s
recommended to specify the node’s RPC API address with a multiaddr:
import aioipfs
client = aioipfs.AsyncIPFS(maddr='/ip4/127.0.0.1/tcp/5001')
client = aioipfs.AsyncIPFS(maddr='/dns4/localhost/tcp/5001')
The default constructor assumes that the kubo node you want to connect to is localhost on port 5001 (use the host and port keyword arguments to set different values):
client = aioipfs.AsyncIPFS()
client = aioipfs.AsyncIPFS(host='10.0.12.3', port=5003)
HTTPS RPC: if the node you’re connecting to uses the https protocol to serve the RPC API, specify https in the multiaddr, or force the URL scheme by passing scheme:
client = aioipfs.AsyncIPFS(maddr='/ip4/10.0.1.4/tcp/5001/https')
client = aioipfs.AsyncIPFS(host='10.0.1.4', scheme='https')
Maximum HTTP connections and read timeout parameters:
client = aioipfs.AsyncIPFS(host='localhost', port=5008, conns_max=20)
client = aioipfs.AsyncIPFS(host='localhost', port=5008, read_timeout=30)
RPC authentication credentials¶
Starting with version 0.25.0, kubo supports limiting access to certain parts of the RPC API by requiring the client to provide credentials via the HTTP Authorization header, either with a simple Basic Auth login and password, or with a token. kubo RPC Authorization documentation.
If the kubo server requires authentication, you can pass the RPC authentication credentials via the constructor’s auth keyword argument:
client = aioipfs.AsyncIPFS(auth=aioipfs.BasicAuth('john', 'password123'))
client = aioipfs.AsyncIPFS(auth=aioipfs.BearerAuth('my-secret-token'))
You can change the credentials at any time by setting the auth object attribute:
client.auth = aioipfs.BasicAuth('alice', 'anotherpass')
client.auth = None
A RPCAccessDenied
exception will be raised
if you are forbidden to use a certain API or if your credentials are invalid.
Async context manager¶
You can use an async context manager in your code:
async with aioipfs.AsyncIPFS() as client:
async for reply in client.ping(peer_id):
...
Closing¶
When finished you should always call AsyncIPFS.close()
on your client:
await client.close()
Content-Addressable aRchives decoding support¶
- CAR
The Content Archive format is a way of packaging up content addressed data into archive files that can be easily stored and transferred. You can think of them like TAR files that are designed for storing collections of content addressed data.
Source: What is a Content Archive Specs: CAR Specs
If you’ve installed the ipfs-car-decoder package via the car extra, you can use various utility functions and APIs to decode the Content-Addressable aRchives generated by kubo, or to open .car files:
Use
aioipfs.util.car_open()
to open a .car archive file (this returns a FileByteStream)Use
aioipfs.util.car_bytes()
to get the raw bytes content from a CAR stream. The first argument is the CAR stream, the second argument must be the CID of a UnixFS file:from pathlib import Path from aioipfs import util data = await util.car_bytes( util.car_open(Path('docs.car')), 'bafybeiawyahkjt4kzrzc3bjylqupniukbpnbvys7pt536c64gxg7onq36m' )
Use the
apis.dag.DagAPI.export()
coroutine to export a DAG to a .car file:from pathlib import Path import aioipfs async with aioipfs.AsyncIPFS() as client: await client.dag.export( 'bafybeiawyahkjt4kzrzc3bjylqupniukbpnbvys7pt536c64gxg7onq36m', output_path=Path('output.car') )
Use the
apis.dag.DagAPI.export_to_directory()
coroutine to export a UnixFS DAG to a CAR and unpack it to a directory on the filesystem. Example:from pathlib import Path import aioipfs async with aioipfs.AsyncIPFS() as client: await client.dag.export_to_directory( 'bafybeiawyahkjt4kzrzc3bjylqupniukbpnbvys7pt536c64gxg7onq36m', Path('car-contents') )
API sectioning¶
The kubo (formerly called go-ipfs) RPC HTTP API provides many endpoints which allow to access the different subsystems of the IPFS daemon. You can read the RPC API specifications here.
Important: The aioipfs client API closely follows kubo’s RPC endpoints path hierarchy, as each subsystem has its own namespace/attribute inside the AsyncIPFS client object, for example:
client.core for the
CoreAPI
client.pin for the
PinAPI
client.pin.remote for the
PinRemoteAPI
client.files for the
FilesAPI
client.pubsub for the
PubSubAPI
etc …
All API functions will raise an APIError
(or a more specific exception) if there’s an error raised during the request.
Core API¶
Adding files¶
Add files to the IPFS repository with the api.CoreAPI.add()
async
generator:
async for added in client.core.add('file1.txt', '/usr/local/src',
recursive=True):
print(added['Hash'])
async for added in client.core.add(['one', 'two', 'three'],
wrap_with_directory=True):
...
cids = [entry['Hash'] async for entry in client.add(dir_path)]
Entries yielded by the generator are as returned by the IPFS daemon, dictionaries with Name, Hash and Size keys.
Since kubo v0.16.0, you can import a file and link the resulting object inside the MFS in the same RPC call, by using the to_files string argument, which should be the path in the MFS for the link:
async for added in client.core.add('file1.txt', to_files='/file1.txt'):
print(added['Hash'])
Ignoring files with .gitignore or .ipfsignore¶
aioipfs supports the use of gitignore files to specify which files should not be imported in IPFS. Use the ignore_rules_path keyword argument to indicate the name of the file (relative to the directory you’re importing) containing the ignore rules:
async for added in client.core.add('directory', recursive=True,
ignore_rules_path='.ipfsignore'):
print(added['Hash'])
Adding bytes¶
Add some bytes with api.CoreAPI.add_bytes()
:
>>> entry = await client.core.add_bytes(b'ABCD')
{'Name': 'QmZ655k2oftYnsocBxqTWzDer3GNui2XQTtcA4ZUbhpz5N', 'Hash': 'QmZ655k2oftYnsocBxqTWzDer3GNui2XQTtcA4ZUbhpz5N', 'Size': '12'}
entry = await client.core.add_bytes('ABCD', to_files='/abcd')
Adding string data¶
Add a UTF-8 string with api.CoreAPI.add_str()
:
entry = await client.core.add_str('ABCD')
entry = await client.core.add_str('ABCD', to_files='/abcd')
Getting IPFS objects¶
Download IPFS objects with api.CoreAPI.get()
:
await client.core.get('QmRGqvWK44oWu8re5whp43P2M7j5XEDLHmPB3wncYFmCNg')
await client.core.get('QmRGqvWK44oWu8re5whp43P2M7j5XEDLHmPB3wncYFmCNg',
dstdir='/tmp')
Cat¶
Use api.CoreAPI.cat()
to get an object’s raw data:
bytes = await client.core.cat(cid)
Listing a path or CID¶
Use api.CoreAPI.ls()
for listing:
listing = await client.core.ls(path)
Node information¶
Get IPFS node information:
info = await client.core.id()
Block API¶
Bitswap API¶
- aioipfs.AsyncIPFS.bitswap¶
Gives access to the
BitswapAPI
Bootstrap API¶
- aioipfs.AsyncIPFS.bootstrap¶
Gives access to the
BootstrapAPI
Config API¶
CID API¶
DAG API¶
DHT API¶
Diag API¶
File API¶
Files API¶
Filestore API¶
- aioipfs.AsyncIPFS.filestore¶
Gives access to the
FilestoreAPI
Key API¶
Log API¶
Access the IPFS event log with:
import pprint
async for msg in client.log.tail():
print(pprint.pprint(msg))
Multibase API¶
- aioipfs.AsyncIPFS.multibase¶
Gives access to the
MultibaseAPI
Name API¶
Object API¶
P2P API¶
There’s an API to easily dial a P2P service through an async context manager:
async with client.p2p.dial_service(
'12D3KooWRd9Pt1Fri5F4W32uhGm8fBG4pvxEiFwgMru85zmajxcd',
'/x/myservice') as ctx:
if ctx.failed:
# Dialing failed
raise Exception('....')
# The multiaddr is available as 'ctx.maddr'
print(f'Multiaddr': {ctx.maddr}')
# The host/port can be retrieved via maddr_host and maddr_port
print(f'Host: {ctx.maddr_host}, port: {ctx.maddr_port}')
Example of dialing a remote http service (using ctx.httpUrl()):
async with client.p2p.dial_service(
'12D3KooWRd9Pt1Fri5F4W32uhGm8fBG4pvxEiFwgMru85zmajxcd',
'/x/http1') as ctx:
async with aiohttp.ClientSession() as sess:
async with sess.get(ctx.httpUrl('/')) as resp:
print(await resp.read())
Pin API¶
Pinning a CID or an IPFS path:
async for pinned in client.pin.add(cid):
print('Pin progress', pinned['Progress'])
Listing the pinned objects:
pinned = await client.pin.ls()
Unpin with:
await client.pin.rm(path)
Pin remote API¶
- aioipfs.AsyncIPFS.pin.remote¶
Gives access to the
PinRemoteAPI
Pubsub API¶
Refs API¶
Repo API¶
Routing API¶
- aioipfs.AsyncIPFS.routing¶
Gives access to the
RoutingAPI
Swarm API¶
Swarm Peering API¶
- aioipfs.AsyncIPFS.swarm.peering¶
Gives access to the
SwarmPeeringAPI