| Crates.io | colonylib |
| lib.rs | colonylib |
| version | 0.6.0 |
| created_at | 2025-05-27 11:35:46.048968+00 |
| updated_at | 2025-09-14 13:55:01.484861+00 |
| description | A library implementing the Colony metadata framework on Autonomi |
| homepage | |
| repository | https://github.com/zettawatt/colonylib |
| max_upload_size | |
| id | 1690951 |
| size | 703,367 |
A Rust library implementing the Colony metadata framework for the Autonomi decentralized network. This library provides the core infrastructure for creating, managing, and searching metadata about files stored on Autonomi using a semantic RDF-based approach.
Note: This is a library for developers. If you're looking for an end-user application to easily upload/download/search files from Autonomi, look at the following applications based on your needs:
- Colony(IN PROGRESS) - Cross platform GUI applications
- Colony Daemon and CLI - Command line interface and background daemon for headless servers
- Mutant - Rust GUI application
Pods are the fundamental building blocks of colonylib. A pod consists of:
This architecture enables:
Colonylib focuses on metadata management and semantic search. It does not handle actual file uploads/downloads - those operations use the standard Autonomi API. Think of colonylib as a sophisticated indexing and discovery layer on top of Autonomi's storage primitives.
Colonylib is organized into four core modules that work together to provide a complete metadata management system:
key.rs)Purpose: Cryptographic key management and derivation
data.rs)Purpose: Local file system operations and pod caching
~/.local/share/colony on Linux)graph.rs)Purpose: RDF semantic database and SPARQL query engine
pod.rs)Purpose: High-level pod operations and network coordination
The main entry point for colonylib is the PodManager struct, which provides a high-level interface for all pod operations. Here are the key methods:
// Add a new wallet key with a name
async fn add_wallet_key(&mut self, name: &str, wallet_key: &str) -> Result<(), Error>
// Retrieve a specific wallet key by name
async fn get_wallet_key(&self, name: &str) -> Result<String, Error>
// Retrieve all wallet keys
fn get_wallet_keys(&self) -> HashMap<String, String>
// Set the active wallet and persist to local storage
fn set_active_wallet(&mut self, name: &str) -> Result<(String, String), Error>
// Get the currently active wallet from local storage
fn get_active_wallet(&self) -> Result<(String, String), Error>
// Create a new pod with a given name
async fn add_pod(&mut self, pod_name: &str) -> Result<(String, String), Error>
// Remove a pod and all its associated data
async fn remove_pod(&mut self, pod_address: &str) -> Result<(), Error>
// Rename an existing pod
async fn rename_pod(&mut self, pod_address: &str, new_name: &str) -> Result<(), Error>
// Create a reference from one pod to another
fn add_pod_ref(&mut self, pod_address: &str, referenced_pod_address: &str) -> Result<(), Error>
// Add metadata for a specific subject (file/resource) to a pod using JSON-LD syntax
async fn put_subject_data(&mut self, pod_address: &str, subject_address: &str, metadata: &str) -> Result<(), Error>
// Get metadata for a specific subject and return a JSON string
async fn get_subject_data(&mut self, subject_address: &str) -> Result<String, Error>
// Upload all local changes to the Autonomi network
async fn upload_all(&mut self) -> Result<(), Error>
// Upload a specific pod to the Autonomi network
async fn upload_pod(&mut self, address: &str) -> Result<(), Error>
// Download updates for user-created pods
async fn refresh_cache(&mut self) -> Result<(), Error>
// Download referenced pods up to specified depth
async fn refresh_ref(&mut self, depth: u64) -> Result<(), Error>
// Get the current list of pods that need to be uploaded in JSON format
fn get_update_list(&self) -> Result<serde_json::Value, Error>
// List all pods owned by the user
fn list_my_pods(&self) -> Result<serde_json::Value, Error>
// List all subjects (resources) within a specific pod
fn list_pod_subjects(&self, pod_address: &str) -> Result<Vec<String>, Error>
// Search pods using various criteria (text, type, properties)
async fn search(&mut self, query: serde_json::Value) -> Result<serde_json::Value, Error>
// Create a new PodManager instance
async fn new(
client: Client, // Autonomi network client
wallet: &Wallet, // Payment wallet
data_store: &mut DataStore, // Local storage
key_store: &mut KeyStore, // Cryptographic keys
graph: &mut Graph, // RDF database
) -> Result<PodManager, Error>
Add colonylib to your Rust project:
[dependencies]
colonylib = "0.3.0"
autonomi = "0.4.6"
tokio = "1.44"
serde_json = "1.0"
Or use cargo:
cargo add colonylib autonomi tokio serde_json
The repository includes three comprehensive examples that demonstrate colonylib's capabilities. These examples are designed to be run in sequence and work on a local Autonomi testnet. Running on main or the Alpha network is possible, but requires code changes.
Before running the examples, you need:
Rust toolchain (1.70 or later)
Autonomi network access:
init_client function in each example)init_client function in each example)Wallet with tokens (for Alpha/Main network operations, creating the local testnet will handle this for you):
examples/setup.rs)Purpose: Initialize the colonylib environment and verify network connectivity.
This example:
Run it:
# For local testnet
cargo run --example setup
# The example uses these default settings:
# - Network: local testnet
# - Mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
# - Password: "password"
What it does:
~/.local/share/colony/ (Linux) or equivalent on other platformsexamples/add_pods.rs)Purpose: Create pods with sample metadata and upload them to the network.
This example demonstrates:
Run it:
cargo run --example add_pods
What it creates:
ant_girl.png)BegBlag.mp3)Each pod contains structured metadata using Schema.org vocabularies:
{
"@context": {"schema": "http://schema.org/"},
"@type": "schema:MediaObject",
"@id": "ant://[file-address]",
"schema:name": "filename.ext",
"schema:description": "File description",
"schema:contentSize": "2MB"
}
examples/search.rs)Purpose: Demonstrate various search capabilities across the pod network.
This example shows:
Run it:
cargo run --example search
Search types demonstrated:
Complete workflow:
# 1. Initialize the environment
cargo run --example setup
# 2. Create sample pods with metadata
cargo run --example add_pods
# 3. Search and query the pods
cargo run --example search
Network Configuration:
To use different networks, modify the environment variable in each example:
// Local testnet (default)
let environment = "local".to_string();
// Alpha testnet (needs test tokens)
let environment = "alpha".to_string();
// Main network (needs real tokens)
let environment = "autonomi".to_string();
Wallet Configuration:
The examples use a hardcoded private key for local testing. For production use:
LOCAL_PRIVATE_KEY constantData Persistence:
setup.rs to reset the environment if neededNOTE! This is a destructive operation. It will overwrite the local data directory and recreate it. If you have things you want to keep, make sure you have uploaded everything to Autonomi before running this.
use autonomi::{Client, Wallet};
use colonylib::{PodManager, DataStore, KeyStore, Graph};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Initialize components
let client = Client::init_local().await?;
let wallet = &Wallet::new_from_private_key(client.evm_network(), private_key)?;
let data_store = &mut DataStore::create()?;
// 2. Set up keystore
let key_store = &mut if keystore_exists {
KeyStore::from_file(&mut file, password)?
} else {
KeyStore::from_mnemonic(mnemonic)?
};
// 3. Initialize graph database
let graph = &mut Graph::open(&data_store.get_graph_path())?;
// 4. Create pod manager
let mut pod_manager = PodManager::new(client, wallet, data_store, key_store, graph).await?;
// 5. Create and populate pods
let (pod_addr, _) = pod_manager.add_pod("My Collection").await?;
let metadata = json!({
"@context": "http://schema.org/",
"@type": "Dataset",
"name": "Research Data",
"description": "Important research findings"
});
pod_manager.put_subject_data(&pod_addr, FILE_ADDRESS, metadata).await?;
// 6. Upload to network
pod_manager.upload_all().await?;
// 7. Search and query
let results = pod_manager.search(json!("research")).await?;
println!("Found: {}", results);
Ok(())
}
For more granular control over network operations, you can upload specific pods instead of all pending changes:
// Create and populate a pod
let (pod_addr, _) = pod_manager.add_pod("Research Data").await?;
let metadata = json!({
"@context": "http://schema.org/",
"@type": "Dataset",
"name": "Climate Research",
"description": "Temperature data from weather stations"
});
pod_manager.put_subject_data(&pod_addr, subject_address, &metadata.to_string()).await?;
// Upload only this specific pod
pod_manager.upload_pod(&pod_addr).await?;
List all your pods and explore their contents:
// Get all user pods
let pods_result = pod_manager.list_my_pods()?;
if let Some(bindings) = pods_result["results"]["bindings"].as_array() {
for pod in bindings {
let pod_address = pod["pod"]["value"].as_str().unwrap();
let pod_name = pod["name"]["value"].as_str().unwrap();
println!("Pod: {} ({})", pod_name, pod_address);
// List all subjects in this pod
let subjects = pod_manager.list_pod_subjects(pod_address)?;
println!(" Contains {} subjects:", subjects.len());
for subject_address in subjects {
// Get detailed metadata for each subject
let metadata = pod_manager.get_subject_data(&subject_address).await?;
let metadata_json: serde_json::Value = serde_json::from_str(&metadata)?;
// Extract subject name from metadata
if let Some(bindings) = metadata_json["results"]["bindings"].as_array() {
for binding in bindings {
if binding["predicate"]["value"].as_str() == Some("http://schema.org/name") {
if let Some(name) = binding["object"]["value"].as_str() {
println!(" - {} ({})", name, subject_address);
}
}
}
}
}
}
}
Create interconnected pod networks:
// Create related pods
let (main_pod, _) = pod_manager.add_pod("Research Collection").await?;
let (data_pod, _) = pod_manager.add_pod("Raw Data").await?;
let (analysis_pod, _) = pod_manager.add_pod("Analysis Results").await?;
// Create references between pods
pod_manager.add_pod_ref(&main_pod, &data_pod).await?;
pod_manager.add_pod_ref(&main_pod, &analysis_pod).await?;
// Upload all pods
pod_manager.upload_all().await?;
// Later, refresh with references to discover connected pods
pod_manager.refresh_ref(2).await?; // Depth 2 to include referenced pods
Rename and remove pods as needed:
// Create a pod with an initial name
let (pod_addr, _) = pod_manager.add_pod("Temporary Research").await?;
// Add some metadata
let metadata = json!({
"@context": {"schema": "http://schema.org/"},
"@type": "schema:SoftwareApplication",
"@id": "ant://cca4e991284bfd22005bd29884079154817c7f0c3ae09c1685ffa3764c6c1e83",
"schema:name": "colony-daemon",
"schema:description": "colony-daemon v0.1.2 x86_64 linux binary
"schema:operatingSystem": "Linux",
"schema:applicationCategory": "Application"
});
pod_manager.put_subject_data(&pod_addr, subject_address, &metadata.to_string()).await?;
// Rename the pod to be more descriptive
pod_manager.rename_pod(&pod_addr, "Climate Research Dataset").await?;
// Upload the changes
pod_manager.upload_all().await?;
// Later, if the pod is no longer needed, remove it
pod_manager.remove_pod(&pod_addr).await?;
// Upload the removal to the network
pod_manager.upload_all().await?;
Important Notes:
Colonylib supports offline usage - you can create, reference, and search pods without performing any Autonomi network write operations:
// Create pods locally
let (pod_addr, _) = pod_manager.add_pod("Offline Pod").await?;
pod_manager.put_subject_data(&pod_addr, subject, metadata).await?;
// Search works immediately
let results = pod_manager.search(json!("offline")).await?;
// Upload when ready (requires network + tokens)
pod_manager.upload_all().await?;
The caveat here is that the data is only stored on your computer. There is no way to recover it if you lose your computer. Uploading to the network is necessary to ensure data persistence, cross-device synchronization, and the ability to share your data with others.
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
git clone https://github.com/zettawatt/colonylib.git
cd colonylib
cargo build
cargo test
# Run all tests
cargo test
# Run specific module tests
cargo test key_tests
cargo test pod_tests
cargo test graph_tests
This project is licensed under the GPL-3.0-only License - see the LICENSE file for details.