Skip to content

Commit

Permalink
add key-value pairs and make inboxid a reference in most cases
Browse files Browse the repository at this point in the history
  • Loading branch information
insipx committed Nov 8, 2024
1 parent 402c91f commit 0a47a3d
Show file tree
Hide file tree
Showing 34 changed files with 637 additions and 256 deletions.
4 changes: 2 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ updates:
schedule:
interval: "weekly"
# Maintain dependencies for yarn
- package-ecosystem: "yarn"
- package-ecosystem: "npm"
directory: "/bindings_wasm"
schedule:
interval: "weekly"
# Maintain dependencies for yarn
- package-ecosystem: "yarn"
- package-ecosystem: "npm"
directory: "/bindings_node"
schedule:
interval: "weekly"
17 changes: 17 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ trait-variant = "0.1.2"
url = "2.5.0"
zeroize = "1.8"
bincode = "1.3"
console_error_panic_hook = "0.1"

# Internal Crate Dependencies
xmtp_cryptography = { path = "xmtp_cryptography" }
Expand Down
7 changes: 5 additions & 2 deletions bindings_ffi/src/mls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ pub struct FfiXmtpClient {
#[uniffi::export(async_runtime = "tokio")]
impl FfiXmtpClient {
pub fn inbox_id(&self) -> InboxId {
self.inner_client.inbox_id()
self.inner_client.inbox_id().to_string()
}

pub fn conversations(&self) -> Arc<FfiConversations> {
Expand Down Expand Up @@ -1258,7 +1258,10 @@ impl FfiConversation {
&self,
inbox_ids: Vec<String>,
) -> Result<(), GenericError> {
self.inner.remove_members_by_inbox_id(&inbox_ids).await?;
let ids = inbox_ids.iter().map(AsRef::as_ref).collect::<Vec<&str>>();
self.inner
.remove_members_by_inbox_id(ids.as_slice())
.await?;
Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion bindings_node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ napi = { version = "2.12.2", default-features = false, features = [
napi-derive = "2.12.2"
prost.workspace = true
tokio = { workspace = true, features = ["sync"] }
tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] }
tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "json", "chrono"] }
tracing.workspace = true
xmtp_api_grpc = { path = "../xmtp_api_grpc" }
xmtp_cryptography = { path = "../xmtp_cryptography" }
Expand Down
94 changes: 77 additions & 17 deletions bindings_node/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use napi::bindgen_prelude::{Error, Result, Uint8Array};
use napi_derive::napi;
use std::collections::HashMap;
use std::ops::Deref;
use std::sync::{Arc, Once};
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing_subscriber::{filter::EnvFilter, fmt, prelude::*};
use tracing_subscriber::{fmt, prelude::*};
pub use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient;
use xmtp_cryptography::signature::ed25519_public_key_to_address;
use xmtp_id::associations::builder::SignatureRequest;
Expand All @@ -20,7 +21,7 @@ use xmtp_mls::Client as MlsClient;
use xmtp_proto::xmtp::mls::message_contents::DeviceSyncKind;

pub type RustXmtpClient = MlsClient<TonicApiClient>;
static LOGGER_INIT: Once = Once::new();
static LOGGER_INIT: std::sync::OnceLock<Result<()>> = std::sync::OnceLock::new();

#[napi]
pub struct Client {
Expand All @@ -39,6 +40,76 @@ impl Client {
}
}

#[napi(string_enum)]
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub enum Level {
off,
error,
warn,
info,
debug,
trace,
}

impl std::fmt::Display for Level {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Level::*;
let s = match self {
off => "off",
error => "error",
warn => "warn",
info => "info",
debug => "debug",
trace => "trace",
};
write!(f, "{}", s)
}
}

/// Specify options for the logger
#[napi(object)]
#[derive(Default)]
pub struct LogOptions {
/// enable structured JSON logging to stdout.Useful for third-party log viewers
/// an option so that it does not require being specified in js object.
pub structured: Option<bool>,
/// Filter logs by level
pub level: Option<Level>,
}

fn init_logging(options: LogOptions) -> Result<()> {
LOGGER_INIT
.get_or_init(|| {
let filter = if let Some(f) = options.level {
tracing_subscriber::filter::LevelFilter::from_str(&f.to_string())
} else {
Ok(tracing_subscriber::filter::LevelFilter::INFO)
}
.map_err(ErrorWrapper::from)?;

if options.structured.unwrap_or_default() {
let fmt = tracing_subscriber::fmt::layer()
.json()
.flatten_event(true)
.with_level(true)
.with_timer(tracing_subscriber::fmt::time::ChronoLocal::rfc_3339())
.with_target(true);

tracing_subscriber::registry().with(filter).with(fmt).init();
} else {
tracing_subscriber::registry()
.with(fmt::layer())
.with(filter)
.init();
}
Ok(())
})
.clone()
.map_err(ErrorWrapper::from)?;
Ok(())
}

/**
* Create a client
*
Expand All @@ -56,20 +127,9 @@ pub async fn create_client(
account_address: String,
encryption_key: Option<Uint8Array>,
history_sync_url: Option<String>,
#[napi(ts_arg_type = "\"debug\" | \"info\" | \"warn\" | \"error\" | \"off\" | undefined | null")]
env_filter: Option<String>,
log_options: Option<LogOptions>,
) -> Result<Client> {
LOGGER_INIT.call_once(|| {
let filter = EnvFilter::builder()
.with_regex(false)
.with_default_directive(tracing::metadata::LevelFilter::INFO.into())
.parse_lossy(env_filter.unwrap_or_default());

tracing_subscriber::registry()
.with(fmt::layer())
.with(filter)
.init();
});
init_logging(log_options.unwrap_or_default())?;
let api_client = TonicApiClient::create(host.clone(), is_secure)
.await
.map_err(|_| Error::from_reason("Error creating Tonic API client"))?;
Expand Down Expand Up @@ -127,7 +187,7 @@ pub async fn create_client(
impl Client {
#[napi]
pub fn inbox_id(&self) -> String {
self.inner_client.inbox_id()
self.inner_client.inbox_id().to_string()
}

#[napi]
Expand Down
8 changes: 7 additions & 1 deletion bindings_node/src/conversation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,13 @@ impl Conversation {
);

group
.remove_members_by_inbox_id(&inbox_ids)
.remove_members_by_inbox_id(
inbox_ids
.iter()
.map(AsRef::as_ref)
.collect::<Vec<&str>>()
.as_slice(),
)
.await
.map_err(ErrorWrapper::from)?;

Expand Down
1 change: 1 addition & 0 deletions bindings_node/test/Client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,5 @@ describe('Client', () => {
user2.account.address.toLowerCase(),
])
})
it('should create client with structured logging', async () => {})
})
2 changes: 1 addition & 1 deletion bindings_node/test/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const createClient = async (user: User) => {
user.account.address,
undefined,
undefined,
'error'
{ level: 'info' }
)
}

Expand Down
4 changes: 4 additions & 0 deletions bindings_wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ xmtp_cryptography = { path = "../xmtp_cryptography" }
xmtp_id = { path = "../xmtp_id" }
xmtp_mls = { path = "../xmtp_mls", features = ["test-utils", "http-api"] }
xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] }
tracing-web = "0.1"
tracing.workspace = true
tracing-subscriber = { workspace = true, features = ["env-filter", "json"] }
console_error_panic_hook.workspace = true

[dev-dependencies]
wasm-bindgen-test.workspace = true
Expand Down
83 changes: 81 additions & 2 deletions bindings_wasm/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use js_sys::Uint8Array;
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{filter, fmt::format::Pretty};
use wasm_bindgen::prelude::{wasm_bindgen, JsError};
use wasm_bindgen::JsValue;
use xmtp_api_http::XmtpHttpApiClient;
Expand Down Expand Up @@ -36,6 +40,79 @@ impl Client {
}
}

static LOGGER_INIT: std::sync::OnceLock<Result<(), filter::LevelParseError>> =
std::sync::OnceLock::new();

#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub enum Level {
Off = "off",
Error = "error",
Warn = "warn",
Info = "info",
Debug = "debug",
Trace = "trace",
}

impl std::fmt::Display for Level {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}

/// Specify options for the logger
#[derive(Default)]
#[wasm_bindgen(getter_with_clone)]
pub struct LogOptions {
/// enable structured JSON logging to stdout.Useful for third-party log viewers
pub structured: bool,
/// enable performance metrics for libxmtp in the `performance` tab
pub performance: bool,
/// filter for logs
pub level: Option<Level>,
}

fn init_logging(options: LogOptions) -> Result<(), JsError> {
LOGGER_INIT
.get_or_init(|| {
console_error_panic_hook::set_once();
let filter = if let Some(f) = options.level {
tracing_subscriber::filter::LevelFilter::from_str(&f.to_string())
} else {
Ok(tracing_subscriber::filter::LevelFilter::INFO)
}?;

if options.structured {
let fmt = tracing_subscriber::fmt::layer()
.json()
.flatten_event(true)
.with_level(true)
.without_time() // need to test whether this would break browsers
.with_target(true);

tracing_subscriber::registry().with(filter).with(fmt).init();
} else {
let fmt = tracing_subscriber::fmt::layer()
.with_ansi(false) // not supported by all browsers
.without_time() // std::time break things, but chrono might work
.with_writer(tracing_web::MakeWebConsoleWriter::new());

let subscriber = tracing_subscriber::registry().with(fmt).with(filter);

if options.performance {
subscriber
.with(tracing_web::performance_layer().with_details_from_fields(Pretty::default()))
.init();
} else {
subscriber.init();
}
}
Ok(())
})
.clone()?;
Ok(())
}

#[wasm_bindgen(js_name = createClient)]
pub async fn create_client(
host: String,
Expand All @@ -44,8 +121,10 @@ pub async fn create_client(
db_path: String,
encryption_key: Option<Uint8Array>,
history_sync_url: Option<String>,
log_options: Option<LogOptions>,
) -> Result<Client, JsError> {
xmtp_mls::utils::wasm::init().await;
init_logging(log_options.unwrap_or_default())?;
xmtp_mls::storage::init_sqlite().await;
let api_client = XmtpHttpApiClient::new(host.clone()).unwrap();

let storage_option = StorageOption::Persistent(db_path);
Expand Down Expand Up @@ -105,7 +184,7 @@ impl Client {

#[wasm_bindgen(getter, js_name = inboxId)]
pub fn inbox_id(&self) -> String {
self.inner_client.inbox_id()
self.inner_client.inbox_id().to_string()
}

#[wasm_bindgen(getter, js_name = isRegistered)]
Expand Down
3 changes: 2 additions & 1 deletion bindings_wasm/src/conversation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,9 @@ impl Conversation {
pub async fn remove_members_by_inbox_id(&self, inbox_ids: Vec<String>) -> Result<(), JsError> {
let group = self.to_mls_group();

let ids = inbox_ids.iter().map(AsRef::as_ref).collect::<Vec<&str>>();
group
.remove_members_by_inbox_id(&inbox_ids)
.remove_members_by_inbox_id(ids.as_slice())
.await
.map_err(|e| JsError::new(&format!("{e}")))?;

Expand Down
Loading

0 comments on commit 0a47a3d

Please sign in to comment.