From 8548b6fc4a72be043eedc7c9eb850494c2c6aeec Mon Sep 17 00:00:00 2001 From: Kariy Date: Tue, 8 Aug 2023 07:47:44 +0800 Subject: [PATCH] add usage example --- Cargo.lock | 13 +++++++ Cargo.toml | 1 + examples/client/Cargo.toml | 15 ++++++++ examples/client/src/main.rs | 63 ++++++++++++++++++++++++++++++++++ examples/client/src/storage.rs | 49 ++++++++++++++++++++++++++ examples/ecs/src/systems.cairo | 8 ++--- 6 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 examples/client/Cargo.toml create mode 100644 examples/client/src/main.rs create mode 100644 examples/client/src/storage.rs diff --git a/Cargo.lock b/Cargo.lock index 8ff05e5dcf..ba8c76e909 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1458,6 +1458,19 @@ version = "0.5.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +[[package]] +name = "client" +version = "0.1.0" +dependencies = [ + "async-trait", + "dojo-client", + "starknet", + "tokio", + "tracing", + "tracing-subscriber", + "url", +] + [[package]] name = "clru" version = "0.6.1" diff --git a/Cargo.toml b/Cargo.toml index 7972be9b0a..ae34f02a0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "crates/katana/rpc", "crates/sozo", "crates/torii", + "examples/client", ] [workspace.package] diff --git a/examples/client/Cargo.toml b/examples/client/Cargo.toml new file mode 100644 index 0000000000..c8b9afa1fd --- /dev/null +++ b/examples/client/Cargo.toml @@ -0,0 +1,15 @@ +[package] +edition = "2021" +name = "client" +version = "0.1.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-trait.workspace = true +dojo-client = { path = "../../crates/dojo-client" } +starknet.workspace = true +tokio.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true +url = "2.2.2" diff --git a/examples/client/src/main.rs b/examples/client/src/main.rs new file mode 100644 index 0000000000..ede2a6c76b --- /dev/null +++ b/examples/client/src/main.rs @@ -0,0 +1,63 @@ +//! This example demonstrates how to use the `WorldPartialSyncer` to sync a single entity from the +//! world contract. The entity is synced to an in-memory storage, and then the storage is queried +//! for the entity's component. +//! +//! This uses the example project under `examples/ecs`. + +use std::sync::Arc; +use std::time::Duration; + +use dojo_client::contract::world::WorldContractReader; +use dojo_client::storage::EntityStorage; +use dojo_client::sync::{EntityComponentRequest, WorldPartialSyncer}; +use starknet::core::types::FieldElement; +use starknet::core::utils::cairo_short_string_to_felt; +use starknet::providers::jsonrpc::HttpTransport; +use starknet::providers::JsonRpcClient; +use storage::InMemoryStorage; +use tokio::sync::RwLock; +use url::Url; + +mod storage; + +#[tokio::main] +async fn main() { + let client = + JsonRpcClient::new(HttpTransport::new(Url::parse("http://localhost:5050").unwrap())); + + let world_address = FieldElement::from_hex_be( + "0x1e94df0369223154c60ed27db2a15677edcdb05e90cc4a54f091671fc399c90", + ) + .unwrap(); + let key = FieldElement::from_hex_be( + "0x3ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0", + ) + .unwrap(); + + let storage = Arc::new(RwLock::new(InMemoryStorage::new())); + let storage_clone = Arc::clone(&storage); + + tokio::task::spawn(async move { + loop { + // Read the entity's position directly from the storage. + let values = storage_clone + .read() + .await + .get(cairo_short_string_to_felt("Position").unwrap(), vec![key], 2) + .await; + + println!("Position x {:#x} y {:#x}", values[0], values[1]); + tokio::time::sleep(Duration::from_secs(2)).await; + } + }); + + let world_reader = WorldContractReader::new(world_address, &client); + + let mut partial_syncer = WorldPartialSyncer::new( + storage, + &world_reader, + vec![EntityComponentRequest { component: String::from("Position"), keys: vec![key] }], + ); + + partial_syncer.start().await; +} diff --git a/examples/client/src/storage.rs b/examples/client/src/storage.rs new file mode 100644 index 0000000000..a7fbf818ca --- /dev/null +++ b/examples/client/src/storage.rs @@ -0,0 +1,49 @@ +use std::collections::HashMap; + +use async_trait::async_trait; +use dojo_client::storage::{get_component_storage_base_address, EntityStorage}; +use starknet::core::types::FieldElement; + +/// Simple in memory implementation of [EntityStorage] +pub struct InMemoryStorage { + /// storage key -> Component value + pub inner: HashMap, +} + +impl InMemoryStorage { + pub fn new() -> Self { + Self { inner: HashMap::new() } + } +} + +// Example implementation of [EntityStorage] +#[async_trait] +impl EntityStorage for InMemoryStorage { + async fn set( + &mut self, + component: FieldElement, + keys: Vec, + values: Vec, + ) { + let base_address = get_component_storage_base_address(component, &keys); + for (offset, value) in values.into_iter().enumerate() { + self.inner.insert(base_address + offset.into(), value); + } + } + + async fn get( + &self, + component: FieldElement, + keys: Vec, + length: usize, + ) -> Vec { + let base_address = get_component_storage_base_address(component, &keys); + let mut values = Vec::with_capacity(length); + for i in 0..length { + let address = base_address + i.into(); + let value = self.inner.get(&address).cloned(); + values.push(value.unwrap_or(FieldElement::ZERO)); + } + values + } +} diff --git a/examples/ecs/src/systems.cairo b/examples/ecs/src/systems.cairo index ae5878cea5..51a34f71ee 100644 --- a/examples/ecs/src/systems.cairo +++ b/examples/ecs/src/systems.cairo @@ -9,13 +9,13 @@ mod spawn { use dojo_examples::components::Moves; fn execute(ctx: Context) { + let position = get !(ctx.world, ctx.origin, (Position)); + set !( ctx.world, ( - Moves { - player: ctx.origin, remaining: 10 - }, Position { - player: ctx.origin, x: 0, y: 0 + Position { + player: ctx.origin, x: position.x + 10, y: position.y + 10 }, ) );