Skip to content

Commit

Permalink
c: rename nostr-sdk-cpp to nostr-sdk-c
Browse files Browse the repository at this point in the history
* Support both for C and C++
* Use `cbindgen` instead of `cxx`

Signed-off-by: Yuki Kishimoto <[email protected]>
  • Loading branch information
yukibtc committed Nov 4, 2024
1 parent c3f4b6d commit c0b0eb0
Show file tree
Hide file tree
Showing 26 changed files with 278 additions and 350 deletions.
95 changes: 21 additions & 74 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
members = [
"bindings/nostr-sdk-cpp",
"bindings/nostr-sdk-c",
"bindings/nostr-sdk-ffi",
"bindings/nostr-sdk-js",
"bindings/uniffi-bindgen",
Expand Down
4 changes: 2 additions & 2 deletions bindings/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* [nostr-sdk-ffi](./nostr-sdk-ffi): UniFFI bindings of the [nostr] and [nostr-sdk] crates
- JavaScript:
* [nostr-sdk-js](./nostr-sdk-js): JavaScript bindings of the [nostr] and [nostr-sdk] crates
- C++:
* [nostr-sdk-cpp](./nostr-sdk-cpp): C++ bindings of the [nostr] and [nostr-sdk] crates
- C/C++:
* [nostr-sdk-c](./nostr-sdk-c): C/C++ bindings of the [nostr] and [nostr-sdk] crates

[nostr]: ../crates/nostr/
[nostr-sdk]: ../crates/nostr-sdk/
3 changes: 3 additions & 0 deletions bindings/nostr-sdk-c/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
bin/
build/
include/*.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "nostr-sdk-cpp"
name = "nostr-sdk-c"
version = "0.1.0"
edition = "2021"
publish = false
Expand All @@ -8,13 +8,10 @@ publish = false
crate-type = ["staticlib"]

[dependencies]
anyhow = "1.0"
cxx = "1.0"
nostr-sdk = { workspace = true, features = ["all-nips"] }
tokio = { workspace = true, features = ["full"] }
tracing = { workspace = true, features = ["std"] }
tracing-subscriber.workspace = true

[build-dependencies]
cxx-build = "1.0"
glob = "0.3"
cbindgen = "0.27"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Nostr SDK for C++
# C/C++ bindings for Nostr SDK

## Supported NIPs

Expand Down
37 changes: 37 additions & 0 deletions bindings/nostr-sdk-c/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) 2022-2023 Yuki Kishimoto
// Copyright (c) 2023-2024 Rust Nostr Developers
// Distributed under the MIT software license

use std::env;
use std::process::Command;

use cbindgen::{Config, Error, Language};

fn main() {
if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() {
if let Ok(git_hash) = String::from_utf8(output.stdout) {
println!("cargo:rerun-if-changed={git_hash}");
println!("cargo:rustc-env=GIT_HASH={git_hash}");
}
}

let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let config: Config = config();
cbindgen::generate_with_config(&crate_dir, config).map_or_else(
|error| match error {
Error::ParseSyntaxError { .. } => {}
e => panic!("{:?}", e),
},
|bindings| {
bindings.write_to_file("include/nostr_sdk.h");
},
);
}

fn config() -> Config {
let mut config: Config = Config::default();
config.language = Language::C;
config.cpp_compat = true;
config.documentation = true;
config
}
25 changes: 25 additions & 0 deletions bindings/nostr-sdk-c/examples/client.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <stdio.h>
#include <string.h>

#include <nostr_sdk.h>

int main() {
// Init logger
enum LogLevel level = Debug;
init_logger(level);

// New client without signer
const Client* client = client_without_signer();

// Add relays
client_add_relay(client, "wss://relay.damus.io");

// Connect
client_connect(client);

// Send event
const char* json = "{\"content\":\"Think about this.\\n\\nThe most powerful centralized institutions in the world have been replaced by a protocol that protects the individual. #bitcoin\\n\\nDo you doubt that we can replace everything else?\\n\\nBullish on the future of humanity\\nnostr:nevent1qqs9ljegkuk2m2ewfjlhxy054n6ld5dfngwzuep0ddhs64gc49q0nmqpzdmhxue69uhhyetvv9ukzcnvv5hx7un8qgsw3mfhnrr0l6ll5zzsrtpeufckv2lazc8k3ru5c3wkjtv8vlwngksrqsqqqqqpttgr27\",\"created_at\":1703184271,\"id\":\"38acf9b08d06859e49237688a9fd6558c448766f47457236c2331f93538992c6\",\"kind\":1,\"pubkey\":\"e8ed3798c6ffebffa08501ac39e271662bfd160f688f94c45d692d8767dd345a\",\"sig\":\"f76d5ecc8e7de688ac12b9d19edaacdcffb8f0c8fa2a44c00767363af3f04dbc069542ddc5d2f63c94cb5e6ce701589d538cf2db3b1f1211a96596fabb6ecafe\",\"tags\":[[\"e\",\"5fcb28b72cadab2e4cbf7311f4acf5f6d1a99a1c2e642f6b6f0d5518a940f9ec\",\"\",\"mention\"],[\"p\",\"e8ed3798c6ffebffa08501ac39e271662bfd160f688f94c45d692d8767dd345a\",\"\",\"mention\"],[\"t\",\"bitcoin\"],[\"t\",\"bitcoin\"]]}";
client_send_event(client, json);

return 0;
}
15 changes: 15 additions & 0 deletions bindings/nostr-sdk-c/examples/keys.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <stdio.h>
#include <string.h>

#include <nostr_sdk.h>

int main() {
// Generate keys
const Keys* keys = keys_generate();
printf("Keys generated.\n");

const char* public_key = keys_public_key(keys);
printf("Public key: %s\n", public_key);

return 0;
}
File renamed without changes.
10 changes: 10 additions & 0 deletions bindings/nostr-sdk-c/justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env just --justfile

build:
cargo build --release

examples: build
mkdir -p bin/
gcc examples/keys.c -o bin/keys -I include/ -L ../../target/release/ -lnostr_sdk_c -lpthread -ldl -lm -lrt
gcc examples/client.c -o bin/client -I include/ -L ../../target/release/ -lnostr_sdk_c -lpthread -ldl -lm -lrt

43 changes: 43 additions & 0 deletions bindings/nostr-sdk-c/src/client/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2022-2023 Yuki Kishimoto
// Copyright (c) 2023-2024 Rust Nostr Developers
// Distributed under the MIT software license

use std::ffi::{c_char, CStr};

use nostr_sdk::client;
use nostr_sdk::nostr::{Event, JsonUtil};

use crate::RUNTIME;

pub struct Client {
inner: client::Client,
}

#[no_mangle]
pub extern "C" fn client_without_signer() -> *const Client {
Box::into_raw(Box::new(Client {
inner: client::Client::default(),
}))
}

#[no_mangle]
pub unsafe extern "C" fn client_add_relay(client: &Client, url: *const c_char) -> bool {
RUNTIME.block_on(async {
let url: &str = CStr::from_ptr(url).to_str().unwrap();
client.inner.add_relay(url).await.unwrap()
})
}

#[no_mangle]
pub unsafe extern "C" fn client_connect(client: &Client) {
RUNTIME.block_on(async { client.inner.connect().await })
}

#[no_mangle]
pub unsafe extern "C" fn client_send_event(client: &Client, json: *const c_char) {
RUNTIME.block_on(async {
let json: &str = CStr::from_ptr(json).to_str().unwrap();
let event = Event::from_json(json).unwrap();
client.inner.send_event(event).await.unwrap();
})
}
26 changes: 26 additions & 0 deletions bindings/nostr-sdk-c/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2022-2023 Yuki Kishimoto
// Copyright (c) 2023-2024 Rust Nostr Developers
// Distributed under the MIT software license

// pub enum CResult {
// code: i32,
// message: *const c_char,
// value: *const c_char, // Change type as needed for different results
// }

#[repr(C)]
pub struct CError {
message: String,
}

pub type Result<T> = core::result::Result<T, CError>;

#[inline(always)]
pub fn into_err<E>(error: E) -> CError
where
E: std::error::Error,
{
CError {
message: error.to_string(),
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,27 @@
// Copyright (c) 2023-2024 Rust Nostr Developers
// Distributed under the MIT software license

use std::ffi::{c_char, CString};
use std::sync::LazyLock;

use tokio::runtime::Runtime;

pub mod client;
pub mod error;
pub mod logger;
pub mod protocol;

static RUNTIME: LazyLock<Runtime> =
LazyLock::new(|| Runtime::new().expect("failed to create tokio runtime"));

pub fn git_hash_version() -> String {
option_env!("GIT_HASH").unwrap_or_default().to_owned()
#[inline]
fn get_git_hash() -> &'static str {
option_env!("GIT_HASH").unwrap_or_default()
}

#[cxx::bridge]
mod ffi {
extern "Rust" {
fn git_hash_version() -> String;
}
#[no_mangle]
pub extern "C" fn git_hash_version() -> *const c_char {
let hash: &str = get_git_hash();
let c_string = CString::new(hash).unwrap();
c_string.into_raw()
}
Loading

0 comments on commit c0b0eb0

Please sign in to comment.