diff --git a/bindings/web5_c/Cargo.toml b/bindings/web5_c/Cargo.toml index 4a05a899..574fb0b7 100644 --- a/bindings/web5_c/Cargo.toml +++ b/bindings/web5_c/Cargo.toml @@ -8,6 +8,9 @@ license-file.workspace = true [dependencies] lazy_static = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { version = "1.38.0", features = ["full"] } web5 = { path = "../../crates/web5" } [lib] diff --git a/bindings/web5_c/src/c.rs b/bindings/web5_c/src/c.rs index 24194377..fa61cce0 100644 --- a/bindings/web5_c/src/c.rs +++ b/bindings/web5_c/src/c.rs @@ -10,6 +10,52 @@ pub extern "C" fn free_string(s: *mut c_char) { } } +use tokio::runtime::Runtime; +use web5::errors::Result; +use web5::errors::Web5Error; + +pub fn get_rt() -> Result { + let rt = Runtime::new() + .map_err(|e| Web5Error::Unknown(format!("unable to instantiate tokio runtime {}", e)))?; + Ok(rt) +} + +use serde_json; +use std::ptr; +use web5::dids::methods::did_dht; + +#[no_mangle] +pub extern "C" fn did_dht_resolve(uri: *const c_char, gateway_url: *const c_char) -> *mut c_char { + let uri = match unsafe { CStr::from_ptr(uri).to_str() } { + Ok(s) => s, + Err(_) => return ptr::null_mut(), + }; + + let gateway_url = if gateway_url.is_null() { + None + } else { + match unsafe { CStr::from_ptr(gateway_url).to_str() } { + Ok(s) => Some(s.to_string()), + Err(_) => return ptr::null_mut(), + } + }; + + let rt = match get_rt() { + Ok(rt) => rt, + Err(_) => return ptr::null_mut(), + }; + + let resolution_result = rt.block_on(did_dht::DidDht::resolve(uri, gateway_url)); + + match serde_json::to_string(&resolution_result) { + Ok(json_string) => match CString::new(json_string) { + Ok(c_str) => c_str.into_raw(), + Err(_) => ptr::null_mut(), + }, + Err(_) => ptr::null_mut(), + } +} + pub fn free_bytes(ptr: *mut u8) { if !ptr.is_null() { unsafe { diff --git a/bindings/web5_c/web5_c.h b/bindings/web5_c/web5_c.h index 9dcdf76b..cd611754 100644 --- a/bindings/web5_c/web5_c.h +++ b/bindings/web5_c/web5_c.h @@ -53,4 +53,9 @@ void poc_key_manager_from_foreign(const CKeyManager *manager); CKeyManager *new_in_memory_key_manager(); /** --- */ +/** did dht */ +char *did_dht_resolve(const char *uri, const char *gateway_url); + +/** --- */ + #endif // WEB5_C_H \ No newline at end of file diff --git a/examples/CExample/.gitignore b/examples/CExample/.gitignore new file mode 100644 index 00000000..567609b1 --- /dev/null +++ b/examples/CExample/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/examples/CExample/Justfile b/examples/CExample/Justfile new file mode 100644 index 00000000..06f4617f --- /dev/null +++ b/examples/CExample/Justfile @@ -0,0 +1,9 @@ +compile: + mkdir -p build + gcc -o build/web5_c_example web5_c.c -L../../target/release -lweb5_c -I../../bindings/web5_c + +clean: + rm -rf build + +run: compile + ./build/web5_c_example \ No newline at end of file diff --git a/examples/CExample/README.md b/examples/CExample/README.md new file mode 100644 index 00000000..9027eec9 --- /dev/null +++ b/examples/CExample/README.md @@ -0,0 +1,66 @@ +## Example Description + +This C example demonstrates basic usage of the Web5 SDK functions through the C bindings. Specifically, it showcases: + +1. Resolving a `did:dht` identifier +2. Printing the resolved DID document or an error message + +This example demonstrates how to resolve a DHT-based DID using the Web5 SDK in C. It uses the `did_dht_resolve` function with a hardcoded DID URI and the default gateway. The program then prints either the resolved DID document or an error message to the console. + +## Running the Example + +To run this C example: + +1. Ensure you have a C compiler installed (e.g. GCC). + +2. Navigate to the root directory of the project (where you cloned the git repository). It's the same location this [Justfile](../../Justfile) is located. + +3. Generate the C dynamic library by running: + + ```shell + just bindc + ``` + + This command will build the necessary C bindings for the Web5 SDK. + +4. Navigate to the `examples/CExample` directory: + + ```shell + cd examples/CExample + ``` + +5. Compile the example using the Justfile recipe: + + ```shell + just compile + ``` + + This command will create a `build` directory and compile the C example using GCC with the appropriate flags and library paths. + +6. Run the compiled example: + + ```shell + just run + ``` + + This will compile (if not already done) and execute the example program, demonstrating the usage of Web5 SDK functions in C. + +7. To clean up the build artifacts: + + ```shell + just clean + ``` + + This will remove the `build` directory. + +## Available Justfile Recipes + +Before running any of the recipes below, ensure you have executed the following command from the root directory of the project. + +The recipes available for this example are: + +| Recipe | Description | +|----------|-----------------------------------------------------------------------| +| compile | Compiles the C example, creating a `build` directory with the binary | +| run | Compiles (if needed) and runs the example program | +| clean | Removes the `build` directory, cleaning up all build artifacts | \ No newline at end of file diff --git a/examples/CExample/web5_c.c b/examples/CExample/web5_c.c new file mode 100644 index 00000000..a3d8ae8f --- /dev/null +++ b/examples/CExample/web5_c.c @@ -0,0 +1,19 @@ +#include +#include +#include "web5_c.h" + +int main() { + const char* did_uri = "did:dht:qgmmpyjw5hwnqfgzn7wmrm33ady8gb8z9ideib6m9gj4ys6wny8y"; + const char* gateway_url = NULL; // Using the default gateway + + char* result = did_dht_resolve(did_uri, gateway_url); + + if (result != NULL) { + printf("%s", result); + free_string(result); + } else { + printf("Failed to resolve DID\n"); + } + + return 0; +} \ No newline at end of file