Create and ingest a drop
In this tutorial we will use create_drop and ingest_drop to transport data between two Stores via a Sideloading drop.
Prerequisites
A basic knowledge of the Rust programming language and executing commands in the terminal will be helpful for completing this tutorial. Some of the steps below also require cargo to be installed.
Additionally, knowledge of the Store API would be helpful. If you're not yet familiar, please see our dedicated tutorial for stores.
Setup
- Create a new directory on your filesystem and name it something like
drop. - Using your terminal, run
cargo initwithin the newly created directory. - After than, run
cargo add willow_25 willow-store-simple-sled sled smol ufotofu willow-sideload.
Create a store and ingest an entry
Open src/main.rs, delete its contents, and enter the following:
use willow_25::{
AccessMode, AuthorisationToken, AuthorisedEntry, Capability, Entry, NamespaceId25, Path,
PayloadDigest25, SubspaceId25,
data_model::{EntryIngestionSuccess, EntryOrigin, Store},
};
use willow_store_simple_sled::StoreSimpleSled;
fn main() {
smol::block_on(async {
// Instantiate a store
let namespace_id = NamespaceId25::new_communal();
let export_db = sled::open("import_db").unwrap();
let export_store = StoreSimpleSled::<
1024,
1024,
1024,
NamespaceId25,
SubspaceId25,
PayloadDigest25,
AuthorisationToken,
>::new(&namespace_id, export_db)
.unwrap();
println!("Instantiated the export store!");
// Create an entry
let (alfie_id, alfie_secret) = SubspaceId25::new();
let write_cap =
Capability::new_communal(namespace_id.clone(), alfie_id.clone(), AccessMode::Write)
.unwrap();
let path = Path::from_slices(&["ideas", "clock"]).unwrap();
let payload = b"An emoji clock";
let digest = PayloadDigest25::new_from_slice(payload);
let entry = Entry::new(
namespace_id.clone(),
alfie_id.clone(),
path.clone(),
100,
payload.len() as u64,
digest.clone(),
);
let token = write_cap.authorisation_token(&entry, alfie_secret).unwrap();
let authed_entry = AuthorisedEntry::new(entry, token).unwrap();
smol::block_on(async {
// Ingest the entry...
if let Ok(EntryIngestionSuccess::Success) = export_store
.ingest_entry(authed_entry, false, EntryOrigin::Local)
.await
{
println!("We ingested the entry!")
}
}
std::fs::remove_dir_all("my_db").unwrap();
}
}In your terminal, run cargo run, and you should see the following output:
Instantiated the export store!
We ingested the entry!Create a drop
Next, we'll create a drop using create_drop and store it in a Vec.
Add the following tosrc/main.rs:
use ufotofu::consumer::IntoVec;
use willow_25::{
AccessMode, Area, AuthorisationToken, AuthorisedEntry, Capability, Entry, NamespaceId25, Path,
PayloadDigest25, SubspaceId25, create_drop,
data_model::{EntryIngestionSuccess, EntryOrigin, Store},
};
use willow_store_simple_sled::StoreSimpleSled;
fn main() {
smol::block_on(async {
// Instantiate a store
let namespace_id = NamespaceId25::new_communal();
let export_db = sled::open("import_db").unwrap();
let export_store = StoreSimpleSled::<
1024,
1024,
1024,
NamespaceId25,
SubspaceId25,
PayloadDigest25,
AuthorisationToken,
>::new(&namespace_id, export_db)
.unwrap();
println!("Instantiated the export store!");
// Create an entry
let (alfie_id, alfie_secret) = SubspaceId25::new();
let write_cap =
Capability::new_communal(namespace_id.clone(), alfie_id.clone(), AccessMode::Write)
.unwrap();
let path = Path::from_slices(&["ideas", "clock"]).unwrap();
let payload = b"An emoji clock";
let digest = PayloadDigest25::new_from_slice(payload);
let entry = Entry::new(
namespace_id.clone(),
alfie_id.clone(),
path.clone(),
100,
payload.len() as u64,
digest.clone(),
);
let token = write_cap.authorisation_token(&entry, alfie_secret).unwrap();
let authed_entry = AuthorisedEntry::new(entry, token).unwrap();
smol::block_on(async {
// Ingest the entry...
if let Ok(EntryIngestionSuccess::Success) = export_store
.ingest_entry(authed_entry, false, EntryOrigin::Local)
.await
{
println!("We ingested the entry!")
}
// Encode a sideloading drop into a Vec<u8>
let full_area = Area::new_full();
let drop_destination = IntoVec::<u8>::new();
let intovec_with_drop = create_drop(
drop_destination,
namespace_id.clone(),
vec![full_area],
&export_store,
)
.await
.unwrap();
let drop_vec = intovec_with_drop.into_vec();
println!("We created the drop!");
std::fs::remove_dir_all("import_db").unwrap();
});
});
}
In your terminal, run cargo run, and you should see the following output:
Instantiated the export store!
We ingested the entry!
We created the drop!Ingest the drop
Finally, we'll create a new Store and ingest the drop into it using ingest_drop.
use ufotofu::{Producer, consumer::IntoVec, producer::FromSlice};
use willow_25::{
AccessMode, Area, AuthorisationToken, AuthorisedEntry, Capability, Entry, NamespaceId25, Path,
PayloadDigest25, SubspaceId25, create_drop,
data_model::{EntryIngestionSuccess, EntryOrigin, QueryIgnoreParams, Store},
ingest_drop,
};
use willow_store_simple_sled::StoreSimpleSled;
fn main() {
smol::block_on(async {
// Instantiate a store
let namespace_id = NamespaceId25::new_communal();
let export_db = sled::open("import_db").unwrap();
let export_store = StoreSimpleSled::<
1024,
1024,
1024,
NamespaceId25,
SubspaceId25,
PayloadDigest25,
AuthorisationToken,
>::new(&namespace_id, export_db)
.unwrap();
println!("Instantiated the export store!");
// Create an entry
let (alfie_id, alfie_secret) = SubspaceId25::new();
let write_cap =
Capability::new_communal(namespace_id.clone(), alfie_id.clone(), AccessMode::Write)
.unwrap();
let path = Path::from_slices(&["ideas", "clock"]).unwrap();
let payload = b"An emoji clock";
let digest = PayloadDigest25::new_from_slice(payload);
let entry = Entry::new(
namespace_id.clone(),
alfie_id.clone(),
path.clone(),
100,
payload.len() as u64,
digest.clone(),
);
let token = write_cap.authorisation_token(&entry, alfie_secret).unwrap();
let authed_entry = AuthorisedEntry::new(entry, token).unwrap();
smol::block_on(async {
// Ingest the entry...
if let Ok(EntryIngestionSuccess::Success) = export_store
.ingest_entry(authed_entry, false, EntryOrigin::Local)
.await
{
println!("We ingested the entry!")
}
// Encode a sideloading drop into a Vec<u8>
let full_area = Area::new_full();
let drop_destination = IntoVec::<u8>::new();
let intovec_with_drop = create_drop(
drop_destination,
namespace_id.clone(),
vec![full_area],
&export_store,
)
.await
.unwrap();
let drop_vec = intovec_with_drop.into_vec();
println!("We created the drop!");
// Create a new store and ingest the drop into it
let import_db = sled::open("import_db").unwrap();
let import_store = StoreSimpleSled::<
1024,
1024,
1024,
NamespaceId25,
SubspaceId25,
PayloadDigest25,
AuthorisationToken,
>::new(&namespace_id, import_db)
.unwrap();
let source_vec = FromSlice::new(&drop_vec);
ingest_drop(source_vec, &import_store).await.unwrap();
println!("We ingested the drop!");
// Check if the entries are in the store we just created.
let full_area = Area::new_full();
let mut entries = import_store
.query_area(&full_area, QueryIgnoreParams::default())
.await
.unwrap();
while let Ok(lengthy_authed_entry) = entries.produce_item().await {
println!("{lengthy_authed_entry:?}")
}
std::fs::remove_dir_all("import_db").unwrap();
});
});
}
In your terminal, run cargo run, and you should see the following output:
Instantiated the export store!
We ingested the entry!
We created the drop!
We ingested the drop!
TODO: NICE ENTRY PRINTING!Summary
In this tutorial we used sideloading to transport willow data between two Stores.