OpenDHT
OpenDHT is a lightweight Distributed Hash Table implementation providing an easy to use distributed in-memory data store.
Key Features
- Lightweight and scalable, designed for large networks and small devices
- High resilience to network disruption
- Public key cryptography layer providing optional data signature and encryption
- IPv4 and IPv6 support
- Python 3 bindings
- REST API with optional HTTP client+server with push notification support
Every node in the network can read and write values to the store. Values are distributed over the network with redundancy.
Installation
Install on Linux, macOS and Windows with:
pip install opendht
Quick Example
Using the simple, blocking API:
import opendht as dht
node = dht.DhtRunner()
node.run()
# Join the DHT network through any running node,
# here using a known bootstrap node.
node.bootstrap("bootstrap.jami.net", "4222")
# blocking call (provide callback arguments to make the call non-blocking)
node.put(dht.InfoHash.get("unique_key"), dht.Value(b'some binary data'))
results = node.get(dht.InfoHash.get("unique_key"))
for value in results:
print(value)
Or using asyncio:
import asyncio
import opendht.aio as dht
async def dht_async_demo(key_str: str):
# Start a new node using an async context manager.
# It is also possible to call run()/await shutdown() manually.
async with dht.DhtRunner(
bootstrap=(("bootstrap.jami.net", "4222"),)
) as node:
# compute key hash
key = dht.InfoHash.get(key_str)
# put data, waiting for completion
await node.put(key, dht.Value(b'tata data'))
# get all values at key
results = await node.getAll(key)
for value in results:
print(value)
# same operation, but stream values as they come from the network
with node.get(key) as results:
async for value in results:
print(value)
# listen for change of values at key
with node.listen(key) as values:
async for value, expired in values:
print(value)
if value.data == b'tata data':
break
asyncio.run(dht_async_demo("unique_key"))
Node State Persistence
Set the state file path before starting a node:
import threading
import opendht as dht
config = dht.DhtConfig()
config.setPersistPath("dht-state.msgpack")
node = dht.DhtRunner()
node.run(config=config)
stopped = threading.Event()
node.shutdown(stopped.set)
stopped.wait()
node.join()
The node loads its saved DHT node ID, known peers, and stored values on startup,
and saves state during shutdown(). Wait for the shutdown callback before
calling join() or reusing the state path; join() alone does not save state.
Port hints are
stored in a sibling file named <path>_port.txt; saved ports are reused when
available. The parent directory must already exist and be writable. Use a
different state path for each node.
Persistence is disabled by default. config.setPersistPath("") disables it
explicitly. This state does not include private keys or certificates; persist
cryptographic identities separately as described below.
Identity Persistence
Keys can be imported from PEM or DER bytes. Private keys export PKCS#8 PEM; public keys export DER. Certificates export their complete PEM chain.
import opendht as dht
identity = dht.Identity.generate("my-node")
private_key_pem = identity.key.serialize(password)
certificate_pem = bytes(identity.certificate)
public_key_der = bytes(identity.publickey)
restored = dht.Identity(
dht.PrivateKey(private_key_pem, password),
dht.Certificate(certificate_pem),
)
public_key = dht.PublicKey(public_key_der)
node = dht.DhtRunner()
node.run(id=restored)
Here password is an application-supplied string. Save the exported bytes using
your application's storage, protect private key files, and keep the password
separate from the key. bytes(private_key) and private_key.serialize() without
a password export unencrypted private keys. Empty or malformed key data,
incorrect passwords, and passwords containing NUL characters raise exceptions.
Exporting an uninitialized key raises ValueError.
Value Metadata
The following properties are readable and writable on Value, including values
returned by get() and listen():
| Property | Type | Meaning |
|---|---|---|
type |
unsigned 16-bit integer | Native value type identifier |
seq |
unsigned 16-bit integer | Sequence number for signed value updates |
priority |
unsigned integer | Push priority: 0 high, 1 normal |
pushType |
string | Push notification type, such as audioCall |
value = dht.Value(b"some binary data")
value.type = 42
value.seq = 1
value.priority = 1
value.pushType = "audioCall"
Set metadata before publishing the value. Numeric values outside the native
integer range raise OverflowError.
value.isSigned() reports whether a public key and signature are present;
it does not verify the signature. value.isEncrypted() reports whether the
value currently contains ciphertext. Values delivered by get() and listen()
are transparently decrypted when possible, so decrypted values return False
from isEncrypted(), even if they were published using putEncrypted().
An uninitialized PublicKey() cannot be used as an encryption recipient and
raises ValueError.
Register custom ValueType instances after run() and before join().
registerType() raises RuntimeError when the runner is stopped, TypeError
for None, and ValueError for an uninitialized type.
Observability
getNodeInfo() returns a read-only NodeInfo snapshot with node identifiers,
IPv4/IPv6 routing statistics, bound ports, pending-operation count, and local
and remote storage counters. getNodesStats(socket.AF_INET) and
getNodesStats(socket.AF_INET6) return NodeStats snapshots. Snapshots remain
valid after the runner stops. getPublicAddress() returns known public
SockAddr objects; pass an address family to restrict the results, or use
getPublicAddressStr() for strings. These lists may be empty before discovery.
getNodeMessageStats(incoming=True) selects incoming message counters.
info = node.getNodeInfo()
print(info.node_id, info.bound4, info.ipv4.good_nodes, info.storage_size)
print(node.getPublicAddressStr())
node.setOnStatusChanged(lambda ipv4, ipv6: print(ipv4.name, ipv6.name))
node.setOnStatusChanged(None)
The status callback receives two NodeStatus values: Disconnected,
Connecting, or Connected. Registration replaces the previous callback and
persists across restarts; None disables it. Core callbacks run on the DHT
thread while native locks are held: do not call snapshot getters, type
registration, logging controls, run(), blocking operations, or join() from
them. The asyncio wrapper schedules status callbacks on its event-loop thread,
where snapshot getters are safe to use.
Call node.connectivityChanged() after a network-interface or IP-address
change. It queues native connectivity recovery, including recontacting peers
and renewing subscriptions. It is also available on the asyncio runner as a
synchronous, nonblocking method.
Queries And Filtered Listeners
query() retrieves metadata rather than complete value payloads. Each row is
a dictionary keyed by ValueField. Network projections support Id,
ValueType, OwnerPk, and UserType; values are integers, an InfoHash owner
fingerprint, or a UTF-8 string respectively. Explicit sequence-number
projections are not supported by the native wire format.
selection = dht.Select().field(dht.ValueField.Id).field(dht.ValueField.UserType)
query = dht.Query()
query.buildFrom(selection, dht.Where().userType("record"))
rows = node.query(key, query=query)
query = dht.Query("SELECT id,user_type WHERE user_type=record")
node.query(key, query_cb=lambda row: print(row) or True,
done_cb=lambda ok, nodes: print(ok), query=query)
Without an explicit query, all four supported metadata fields are selected.
Supplying query_cb makes the core call nonblocking; returning False stops
delivery. The blocking core API returns the collected rows, as get() does.
The asyncio API offers query() as a context-managed async iterator and
await queryAll() as a collector; these raise RuntimeError on failure.
rows = await node.queryAll(key, query=query)
with node.query(key, query=query) as results:
async for row in results:
print(row[dht.ValueField.Id])
Both core and asyncio listen() accept optional where and filter arguments.
Where is sent to the DHT to narrow the subscription; the Python predicate
runs locally. Existing two-argument core listeners are unchanged.
token = node.listen(key, lambda value, expired: True,
where=dht.Where().userType("record"),
filter=lambda value: len(value.data) < 1024)
node.cancelListen(token)
Documentation
For more information, examples and documentation, or to repport issues, visit: https://opendht.net
License
Copyright (c) 2014-2026 Savoir-faire Linux Inc.
OpenDHT is released under the MIT License. See LICENSE for details.
Metadata
Release files for opendht 4.4.99
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 110.0 MB
Release files / opendht-4.4.99-cp315-cp315-win_amd64.whl
| Download URL | opendht-4.4.99-cp315-cp315-win_amd64.whl |
|---|---|
| Size | 5.7 MB |
| Tags | CPython 3.15 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
d90875c7e9129ea04559cdcc6496dccb577903716da5e4d30c4c5672e3ce3a47
|
|
BLAKE2b-256 checksum How to use checksums |
58a6646b3f1ffd7e7add18d8a5130371e0e72e85b767a25f0acc33bae4d6737e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp315-cp315-manylinux_2_34_x86_64.whl
| Download URL | opendht-4.4.99-cp315-cp315-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 6.5 MB |
| Tags | CPython 3.15 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
699a7afed6c5f42a2c104c233609c017dcbf25947437a5d9161f869a8eac92ec
|
|
BLAKE2b-256 checksum How to use checksums |
d1cdbf51cf294cea42c7d86bbc1c9e963bdfd37401c4a28ab609c5ed881bf20e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp315-cp315-manylinux_2_34_aarch64.whl
| Download URL | opendht-4.4.99-cp315-cp315-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 6.2 MB |
| Tags | CPython 3.15 Linux glibc 2.34+ ARM64 |
|
SHA-256 checksum How to use checksums |
1cad339e78736dc481e838b42d433d249efec6b22a3ecaf686648cde806c20af
|
|
BLAKE2b-256 checksum How to use checksums |
69f42093a77507826d3fc3b33acb18016efba0179912017116616b98bfffd686
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp315-cp315-macosx_15_0_arm64.whl
| Download URL | opendht-4.4.99-cp315-cp315-macosx_15_0_arm64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.15 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
da41b8f4d7b519c486e06651f34e428782a5d3f882baa126b2b535c42284abac
|
|
BLAKE2b-256 checksum How to use checksums |
030fef146878ea4c4305d52b85254c1a8188a9b216286e8d8f30e90668849c11
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp314-cp314-win_amd64.whl
| Download URL | opendht-4.4.99-cp314-cp314-win_amd64.whl |
|---|---|
| Size | 5.7 MB |
| Tags | CPython 3.14 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
ffd11236faf53227247ecd2919dc8a306983db6ed40fb8d0a527dc3bbcf01174
|
|
BLAKE2b-256 checksum How to use checksums |
76a344604c0dff358392bac23d345b37cd3f55645cc83b0ccff9802f58721148
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp314-cp314-manylinux_2_34_x86_64.whl
| Download URL | opendht-4.4.99-cp314-cp314-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 6.5 MB |
| Tags | CPython 3.14 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
ee49abd66dd856303abc007bc25471428028bf1a6207fd5e1706ff85c62d08ae
|
|
BLAKE2b-256 checksum How to use checksums |
b7d3682d411089919d4f4405eea0f43659ab954b90c617e7b2063c2972026a88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp314-cp314-manylinux_2_34_aarch64.whl
| Download URL | opendht-4.4.99-cp314-cp314-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 6.2 MB |
| Tags | CPython 3.14 Linux glibc 2.34+ ARM64 |
|
SHA-256 checksum How to use checksums |
d5c622f8739d8fe38567b58ce71fff59f705e604f987108b014676439418662d
|
|
BLAKE2b-256 checksum How to use checksums |
b3449c331a4277bc9b15d6b85a1b65b948370f8d38247785c782253e863ae3d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp314-cp314-macosx_15_0_arm64.whl
| Download URL | opendht-4.4.99-cp314-cp314-macosx_15_0_arm64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.14 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
39c101a054ef9f93558c72920d59ffcc25ebbe3becbc184c5524b302dfbc9eb9
|
|
BLAKE2b-256 checksum How to use checksums |
ec8f0ce2f34e8edd4e175704321ed3d88e5f0d91ebeee5cd258d200ab8a028cb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp313-cp313-win_amd64.whl
| Download URL | opendht-4.4.99-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 5.5 MB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
efe55498311bfaddc5fcac59ef04f4f8c53a14cdf645bdb823be43cf49c297fb
|
|
BLAKE2b-256 checksum How to use checksums |
caebfa185b44cfc1aa81dabfffd4019af3c669e090792abba9e72230bcd88b2f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp313-cp313-manylinux_2_34_x86_64.whl
| Download URL | opendht-4.4.99-cp313-cp313-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 6.5 MB |
| Tags | CPython 3.13 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
60b155fa361884cee85a58a3fe78707b5948d4d7c0cf96d398305a85bfbc3583
|
|
BLAKE2b-256 checksum How to use checksums |
c858eee43b51cb0ed9a8835a2ec4cc1afc6d0921d174b761135d303827bf0f28
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp313-cp313-manylinux_2_34_aarch64.whl
| Download URL | opendht-4.4.99-cp313-cp313-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 6.2 MB |
| Tags | CPython 3.13 Linux glibc 2.34+ ARM64 |
|
SHA-256 checksum How to use checksums |
834133620a8d9a996aa7c6e45343ea44cae28b5fb963e1fd734aa8defa4f949d
|
|
BLAKE2b-256 checksum How to use checksums |
b4f3f8a60280ed135d6db87f261284581338065f5c8b3452851af73cf568e17c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp313-cp313-macosx_15_0_arm64.whl
| Download URL | opendht-4.4.99-cp313-cp313-macosx_15_0_arm64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.13 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
8976ffb97b6ac11327e75493c00a43dc24575ffdba6068841d8d8c5753558bb5
|
|
BLAKE2b-256 checksum How to use checksums |
cc6f6ef32521d4be83c2f262d0e6b9510bfdf030283f12ec879e5ac50c14fc28
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp312-cp312-win_amd64.whl
| Download URL | opendht-4.4.99-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 5.5 MB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
1e35db44046d0431d0558c820aebfdb205e69329e222af42769da4e5f5a0f82c
|
|
BLAKE2b-256 checksum How to use checksums |
026c1bb48f2d31075303631f54b6305645e8a45268ead506f0d6a159fae7fe73
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp312-cp312-manylinux_2_34_x86_64.whl
| Download URL | opendht-4.4.99-cp312-cp312-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 6.6 MB |
| Tags | CPython 3.12 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
91c3b1aca2cf9f85cef5dc8daf8ceb6e6a9a47ed3bf372a17d756aa7b200a928
|
|
BLAKE2b-256 checksum How to use checksums |
1638afd6638b77f880db6a53a632efd7d1f7e109e7ae6946d1b41dc6b3ddb8e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp312-cp312-manylinux_2_34_aarch64.whl
| Download URL | opendht-4.4.99-cp312-cp312-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 6.2 MB |
| Tags | CPython 3.12 Linux glibc 2.34+ ARM64 |
|
SHA-256 checksum How to use checksums |
40d2ee087bfd2ca3a4adfb30091cc0998d396b33d2045f07cca67d5dd12afed0
|
|
BLAKE2b-256 checksum How to use checksums |
db55f358477ffd8d72e4a4b83101260454f7658280c06266cce1f32a101118f7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp312-cp312-macosx_15_0_arm64.whl
| Download URL | opendht-4.4.99-cp312-cp312-macosx_15_0_arm64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.12 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
dc934a944215a08af0d551adbbba35ca057c7d286cc0f91cd3d45586a789b2f1
|
|
BLAKE2b-256 checksum How to use checksums |
e24d781378f43f81b81b6809f135fc8c1b4219e5d4e5ddacc848a5de76d050b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp311-cp311-win_amd64.whl
| Download URL | opendht-4.4.99-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 5.5 MB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
ea2696410daea0da6caa78cb70d558ec44dc06a13ad308121718d6a0da977b17
|
|
BLAKE2b-256 checksum How to use checksums |
7adc29972ed92e4f3b2fc2fc3631f54e2be2dd2bf1bda582a79f61c170bf9553
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp311-cp311-manylinux_2_34_x86_64.whl
| Download URL | opendht-4.4.99-cp311-cp311-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 6.6 MB |
| Tags | CPython 3.11 Linux glibc 2.34+ x86-64 |
|
SHA-256 checksum How to use checksums |
dce7883ab74db5e0518a4a66296eead8e08e67272f88b02abbe3a149b37828ee
|
|
BLAKE2b-256 checksum How to use checksums |
485c75a3cdb36dcac4518dc296e8eaeb2dbed84b769a5820d10dd43a48fe4e84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp311-cp311-manylinux_2_34_aarch64.whl
| Download URL | opendht-4.4.99-cp311-cp311-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 6.2 MB |
| Tags | CPython 3.11 Linux glibc 2.34+ ARM64 |
|
SHA-256 checksum How to use checksums |
2ee4ca19c6f634c1db645810e166eabce5a862be460a4a2dd3df7844f2a6deda
|
|
BLAKE2b-256 checksum How to use checksums |
693d749ab20c86240ca758b4bea69688cbbd217b3317fa1f280fcd5e59473a95
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / opendht-4.4.99-cp311-cp311-macosx_15_0_arm64.whl
| Download URL | opendht-4.4.99-cp311-cp311-macosx_15_0_arm64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.11 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
5258367083c0df7993ba0ed090e1655b2ef0040470b18e90c5b70deed48ef454
|
|
BLAKE2b-256 checksum How to use checksums |
735850009a5356c8d214ddf9f1e217858f2003b6d5f7b36362be305da19fc308
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Security for opendht 4.4.99
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.