Python client library for Spot messaging protocol
Project description
pyspotlib
Python client library for the Spot messaging protocol. This is a port of spotlib (Go) to Python.
Features
- Connect to Spot servers via WebSocket
- End-to-end encrypted messaging using pybottle
- Query/response pattern for RPC-style communication
- Encrypted blob storage
- ID card caching for efficient encryption
- Automatic connection management and reconnection
Installation
pip install pyspotlib
Or install from source:
git clone https://github.com/KarpelesLab/pyspotlib.git
cd pyspotlib
pip install -e .
Quick Start
import asyncio
from pyspotlib import new_client
async def main():
# Create and connect a client
client = await new_client()
await client.wait_online()
print(f"Connected! Target ID: {client.target_id}")
# Get server time
server_time = await client.get_time()
print(f"Server time: {server_time}")
# Store and retrieve encrypted data
await client.store_blob("my_key", b"secret data")
data = await client.fetch_blob("my_key")
await client.close()
asyncio.run(main())
API Reference
Creating a Client
from pyspotlib import new_client, Client, DiskStore
# Simple ephemeral client (generates new key each time)
client = await new_client()
# Client with persistent key storage
store = DiskStore("/path/to/keys")
client = await new_client(store=store)
# Client without auto-start
client = Client()
await client.start()
Client Properties
client.target_id- The client's address ink.<hash>formatclient.idcard- The client's identity cardclient.idcard_bin- The client's signed identity card as bytes
Querying Endpoints
# Query a system endpoint
result = await client.query("@/time", b"")
# Query another client's endpoint
result = await client.query("k.<hash>/endpoint", payload)
# With custom timeout
result = await client.query("@/time", b"", timeout=60.0)
Sending Messages
# Send without waiting for response
await client.send_to("k.<hash>/endpoint", payload)
# With custom sender address
await client.send_to("k.<hash>/endpoint", payload, sender="/my-sender")
Blob Storage
# Store encrypted blob (only you can decrypt it)
await client.store_blob("key", b"data")
# Fetch blob
data = await client.fetch_blob("key")
# Delete blob
await client.store_blob("key", b"")
Message Handlers
# Set a handler for incoming messages
async def my_handler(msg):
# Process message
return response_bytes, None # (response, error)
client.set_handler("my_endpoint", my_handler)
# Remove handler
client.set_handler("my_endpoint", None)
Built-in Handlers
The client automatically responds to these endpoints:
ping- Echo back the message (up to 128 bytes)version- Return library version infofinger- Return the client's signed ID cardcheck_update- Logs update check requestidcard_update- Updates ID card cache from server notifications
PacketConn (Packet-based Messaging)
For easy packet-based communication:
# Create a packet connection
conn = client.listen_packet("my_endpoint")
# Receive packets
data, addr = await conn.read_from(timeout=10.0)
print(f"Received {len(data)} bytes from {addr}")
# Send packets
await conn.write_to(b"response data", addr)
# Get local address
print(f"Listening on: {conn.local_addr()}")
# Clean up
await conn.close()
Utility Methods
# Get server time
time = await client.get_time()
# Get ID card for a recipient
idcard = await client.get_idcard(hash_bytes)
idcard = await client.get_idcard_for_recipient("k.<hash>/endpoint")
# Get raw ID card bytes
idcard_bytes = await client.get_idcard_bin(hash_bytes)
# Get group members
members = await client.get_group_members(group_key_bytes)
# Check connection status
total, online = client.connection_count()
# Wait for connection
connected = await client.wait_online(timeout=30.0)
# Query with explicit timeout (alternative syntax)
result = await client.query_timeout(30.0, "@/time", b"")
Address Formats
| Format | Description |
|---|---|
k.<hash> |
Key-based address (SHA-256 hash of public key, base64url) |
k.<hash>/endpoint |
Key-based with endpoint |
@/endpoint |
System endpoint |
Protocol
pyspotlib implements the Spot protocol as defined in spotproto. Messages are encrypted end-to-end using the Bottle format from pybottle.
Message Flags
MsgFlagResponse(0x01) - Response messageMsgFlagError(0x02) - Error responseMsgFlagNotBottle(0x04) - Unencrypted body
Dependencies
- pybottle >= 0.1.1 - Cryptographic message containers
- websockets >= 12.0 - WebSocket client
- cbor2 >= 5.6.0 - CBOR encoding
- httpx >= 0.27.0 - HTTP client
License
MIT License - see LICENSE file for details.
Related Projects
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyspotlib-0.1.0.tar.gz.
File metadata
- Download URL: pyspotlib-0.1.0.tar.gz
- Upload date:
- Size: 19.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e982b839774fe82f071565039f8c55633d742e29fa8f9f531d5ae81f494284b
|
|
| MD5 |
9843c22bed20a0aa3caf048a0ae5cc16
|
|
| BLAKE2b-256 |
1329fb6a9283071c8ed4e39eb3fff30f7c8bbaa3874d4f3de354125855415ab3
|
File details
Details for the file pyspotlib-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pyspotlib-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12ac3c2c8eca3efdbf74a78ef16eb13f9f8dc101b9234b940c66d6c83c8b8478
|
|
| MD5 |
a6d08ccc8adae1b7102ad3340f4b3524
|
|
| BLAKE2b-256 |
1f4d3acf9196af85e90fe0cbb1e6c35618ed344c1146d755dfa49349bb751492
|