diff --git a/Cargo.lock b/Cargo.lock index f36db910d..435469007 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2977,7 +2977,7 @@ dependencies = [ [[package]] name = "mls_validation_service" -version = "0.1.0" +version = "0.0.0" dependencies = [ "anyhow", "clap", @@ -6244,7 +6244,7 @@ dependencies = [ [[package]] name = "xmtp_api_grpc" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-stream", "base64 0.22.1", @@ -6265,7 +6265,7 @@ dependencies = [ [[package]] name = "xmtp_api_http" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-stream", "async-trait", @@ -6311,7 +6311,7 @@ dependencies = [ [[package]] name = "xmtp_cryptography" -version = "0.1.0" +version = "0.0.0" dependencies = [ "curve25519-dalek", "ecdsa 0.15.1", @@ -6332,7 +6332,7 @@ dependencies = [ [[package]] name = "xmtp_id" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-trait", "chrono", @@ -6365,7 +6365,7 @@ dependencies = [ [[package]] name = "xmtp_mls" -version = "0.1.0" +version = "0.0.0" dependencies = [ "aes-gcm", "anyhow", @@ -6423,7 +6423,7 @@ dependencies = [ [[package]] name = "xmtp_proto" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-trait", "futures", @@ -6440,7 +6440,7 @@ dependencies = [ [[package]] name = "xmtp_user_preferences" -version = "0.1.0" +version = "0.0.0" dependencies = [ "base64 0.21.7", "libsecp256k1", @@ -6453,7 +6453,7 @@ dependencies = [ [[package]] name = "xmtp_v2" -version = "0.1.0" +version = "0.0.0" dependencies = [ "aes-gcm", "ecdsa 0.15.1", diff --git a/Cargo.toml b/Cargo.toml index 4048b2f7b..396c32588 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,9 @@ exclude = [ # See https://doc.rust-lang.org/edition-guide/rust-2021/default-cargo-resolver.html#details resolver = "2" +[workspace.package] +version = "0.0.1" + [workspace.dependencies] anyhow = "1.0" async-stream = "0.3" diff --git a/bindings_ffi/Cargo.lock b/bindings_ffi/Cargo.lock index 3b90b6591..f42968132 100644 --- a/bindings_ffi/Cargo.lock +++ b/bindings_ffi/Cargo.lock @@ -5735,7 +5735,7 @@ dependencies = [ [[package]] name = "xmtp_api_grpc" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-stream", "base64 0.22.1", @@ -5755,7 +5755,7 @@ dependencies = [ [[package]] name = "xmtp_cryptography" -version = "0.1.0" +version = "0.0.0" dependencies = [ "curve25519-dalek", "ecdsa 0.15.1", @@ -5775,7 +5775,7 @@ dependencies = [ [[package]] name = "xmtp_id" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-trait", "chrono", @@ -5806,7 +5806,7 @@ dependencies = [ [[package]] name = "xmtp_mls" -version = "0.1.0" +version = "0.0.0" dependencies = [ "aes-gcm", "async-stream", @@ -5848,7 +5848,7 @@ dependencies = [ [[package]] name = "xmtp_proto" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-trait", "futures", @@ -5865,7 +5865,7 @@ dependencies = [ [[package]] name = "xmtp_user_preferences" -version = "0.1.0" +version = "0.0.0" dependencies = [ "base64 0.21.7", "once_cell", @@ -5876,7 +5876,7 @@ dependencies = [ [[package]] name = "xmtp_v2" -version = "0.1.0" +version = "0.0.0" dependencies = [ "aes-gcm", "ecdsa 0.15.1", diff --git a/bindings_node/Cargo.lock b/bindings_node/Cargo.lock index 3bbecf7f4..03cb93889 100644 --- a/bindings_node/Cargo.lock +++ b/bindings_node/Cargo.lock @@ -5192,7 +5192,7 @@ dependencies = [ [[package]] name = "xmtp_api_grpc" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-stream", "base64 0.22.1", @@ -5212,7 +5212,7 @@ dependencies = [ [[package]] name = "xmtp_cryptography" -version = "0.1.0" +version = "0.0.0" dependencies = [ "curve25519-dalek", "ecdsa 0.15.1", @@ -5232,7 +5232,7 @@ dependencies = [ [[package]] name = "xmtp_id" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-trait", "chrono", @@ -5263,7 +5263,7 @@ dependencies = [ [[package]] name = "xmtp_mls" -version = "0.1.0" +version = "0.0.0" dependencies = [ "aes-gcm", "async-stream", @@ -5305,7 +5305,7 @@ dependencies = [ [[package]] name = "xmtp_proto" -version = "0.1.0" +version = "0.0.0" dependencies = [ "async-trait", "futures", @@ -5322,7 +5322,7 @@ dependencies = [ [[package]] name = "xmtp_v2" -version = "0.1.0" +version = "0.0.0" dependencies = [ "aes-gcm", "ecdsa 0.15.1", diff --git a/mls_validation_service/Cargo.toml b/mls_validation_service/Cargo.toml index e2b580a13..d6fac06bf 100644 --- a/mls_validation_service/Cargo.toml +++ b/mls_validation_service/Cargo.toml @@ -1,7 +1,6 @@ [package] edition = "2021" name = "mls_validation_service" -version = "0.1.0" [[bin]] # Bin to run the Validation Service name = "mls-validation-service" @@ -11,8 +10,8 @@ path = "src/main.rs" clap = { version = "4.4.6", features = ["derive"] } ed25519-dalek = { workspace = true, features = ["digest"] } env_logger = "0.11" -hex = { workspace = true } futures = { workspace = true } +hex = { workspace = true } log = { workspace = true } openmls = { workspace = true } openmls_rust_crypto = { workspace = true } @@ -24,7 +23,7 @@ tokio = { workspace = true, features = ["full"] } tonic = { workspace = true } warp = "0.3.6" xmtp_id.workspace = true -xmtp_mls.workspace = true +xmtp_mls.workspace = true xmtp_proto = { path = "../xmtp_proto", features = [ "proto_full", "grpc", @@ -34,9 +33,8 @@ xmtp_proto = { path = "../xmtp_proto", features = [ [dev-dependencies] anyhow.workspace = true -ethers.workspace = true +ethers.workspace = true openmls_basic_credential = { workspace = true, features = ["test-utils"] } rand = { workspace = true } sha2.workspace = true -xmtp_id = { workspace = true, features = ["test-utils"]} - +xmtp_id = { workspace = true, features = ["test-utils"] } diff --git a/xmtp_api_grpc/Cargo.toml b/xmtp_api_grpc/Cargo.toml index 32a3f353a..6bc0c2223 100644 --- a/xmtp_api_grpc/Cargo.toml +++ b/xmtp_api_grpc/Cargo.toml @@ -1,7 +1,6 @@ [package] edition = "2021" name = "xmtp_api_grpc" -version = "0.1.0" [dependencies] async-stream.workspace = true @@ -9,8 +8,8 @@ base64 = "0.22" futures.workspace = true hex.workspace = true log = { workspace = true, features = ["std"] } +pbjson-types.workspace = true pbjson.workspace = true -pbjson-types.workspace = true prost = { workspace = true, features = ["prost-derive"] } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } @@ -19,9 +18,9 @@ tonic = { workspace = true, features = [ "tls-roots", "tls-webpki-roots", ] } +tracing.workspace = true xmtp_proto = { path = "../xmtp_proto", features = ["proto_full", "grpc"] } xmtp_v2 = { path = "../xmtp_v2" } -tracing.workspace = true [dev-dependencies] uuid = { version = "1.3.1", features = ["v4"] } diff --git a/xmtp_api_grpc/src/grpc_api_helper.rs b/xmtp_api_grpc/src/grpc_api_helper.rs index de1523b50..06683fa62 100644 --- a/xmtp_api_grpc/src/grpc_api_helper.rs +++ b/xmtp_api_grpc/src/grpc_api_helper.rs @@ -9,6 +9,7 @@ use tokio::sync::oneshot; use tonic::transport::ClientTlsConfig; use tonic::{async_trait, metadata::MetadataValue, transport::Channel, Request, Streaming}; +use xmtp_proto::api_client::ClientWithMetadata; use xmtp_proto::{ api_client::{ Error, ErrorKind, GroupMessageStream, MutableApiSubscription, WelcomeMessageStream, @@ -70,43 +71,63 @@ pub struct Client { pub(crate) mls_client: ProtoMlsApiClient, pub(crate) identity_client: ProtoIdentityApiClient, pub(crate) app_version: MetadataValue, + pub(crate) libxmtp_version: MetadataValue, } impl Client { pub async fn create(host: String, is_secure: bool) -> Result { let host = host.to_string(); - let app_version = MetadataValue::try_from(&String::from("0.0.0")).unwrap(); - if is_secure { - let channel = create_tls_channel(host).await?; - - let client = MessageApiClient::new(channel.clone()); - let mls_client = ProtoMlsApiClient::new(channel.clone()); - let identity_client = ProtoIdentityApiClient::new(channel); - - Ok(Self { - client, - mls_client, - app_version, - identity_client, - }) - } else { - let channel = Channel::from_shared(host) + let app_version = MetadataValue::try_from(&String::from("0.0.0")) + .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; + let libxmtp_version = MetadataValue::try_from(&String::from("0.0.0")) + .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; + + let channel = match is_secure { + true => create_tls_channel(host).await?, + false => Channel::from_shared(host) .map_err(|e| Error::new(ErrorKind::SetupCreateChannelError).with(e))? .connect() .await - .map_err(|e| Error::new(ErrorKind::SetupConnectionError).with(e))?; - - let client = MessageApiClient::new(channel.clone()); - let mls_client = ProtoMlsApiClient::new(channel.clone()); - let identity_client = ProtoIdentityApiClient::new(channel); - - Ok(Self { - client, - mls_client, - identity_client, - app_version, - }) - } + .map_err(|e| Error::new(ErrorKind::SetupConnectionError).with(e))?, + }; + + let client = MessageApiClient::new(channel.clone()); + let mls_client = ProtoMlsApiClient::new(channel.clone()); + let identity_client = ProtoIdentityApiClient::new(channel); + + Ok(Self { + client, + mls_client, + app_version, + libxmtp_version, + identity_client, + }) + } + + pub fn build_request(&self, request: RequestType) -> Request { + let mut req = Request::new(request); + req.metadata_mut() + .insert("x-app-version", self.app_version.clone()); + req.metadata_mut() + .insert("x-libxmtp-version", self.libxmtp_version.clone()); + + req + } +} + +impl ClientWithMetadata for Client { + fn set_libxmtp_version(&mut self, version: String) -> Result<(), Error> { + self.libxmtp_version = MetadataValue::try_from(&version) + .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; + + Ok(()) + } + + fn set_app_version(&mut self, version: String) -> Result<(), Error> { + self.app_version = MetadataValue::try_from(&version) + .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; + + Ok(()) } } @@ -115,10 +136,6 @@ impl XmtpApiClient for Client { type Subscription = Subscription; type MutableSubscription = GrpcMutableSubscription; - fn set_app_version(&mut self, version: String) { - self.app_version = MetadataValue::try_from(&version).unwrap(); - } - async fn publish( &self, token: String, @@ -129,11 +146,8 @@ impl XmtpApiClient for Client { .parse() .map_err(|e| Error::new(ErrorKind::PublishError).with(e))?; - let mut tonic_request = Request::new(request); + let mut tonic_request = self.build_request(request); tonic_request.metadata_mut().insert("authorization", token); - tonic_request - .metadata_mut() - .insert("x-app-version", self.app_version.clone()); let client = &mut self.client.clone(); client @@ -144,14 +158,9 @@ impl XmtpApiClient for Client { } async fn subscribe(&self, request: SubscribeRequest) -> Result { - let mut tonic_request = Request::new(request); - tonic_request - .metadata_mut() - .insert("x-app-version", self.app_version.clone()); - let client = &mut self.client.clone(); let stream = client - .subscribe(tonic_request) + .subscribe(self.build_request(request)) .await .map_err(|e| Error::new(ErrorKind::SubscribeError).with(e))? .into_inner(); @@ -174,16 +183,10 @@ impl XmtpApiClient for Client { } }; - let mut tonic_request = Request::new(input_stream); - - tonic_request - .metadata_mut() - .insert("x-app-version", self.app_version.clone()); - let client = &mut self.client.clone(); let stream = client - .subscribe2(tonic_request) + .subscribe2(self.build_request(input_stream)) .await .map_err(|e| Error::new(ErrorKind::SubscribeError).with(e))? .into_inner(); @@ -195,13 +198,9 @@ impl XmtpApiClient for Client { } async fn query(&self, request: QueryRequest) -> Result { - let mut tonic_request = Request::new(request); - tonic_request - .metadata_mut() - .insert("x-app-version", self.app_version.clone()); let client = &mut self.client.clone(); - let res = client.query(tonic_request).await; + let res = client.query(self.build_request(request)).await; match res { Ok(response) => Ok(response.into_inner()), @@ -210,13 +209,8 @@ impl XmtpApiClient for Client { } async fn batch_query(&self, request: BatchQueryRequest) -> Result { - let mut tonic_request = Request::new(request); - tonic_request - .metadata_mut() - .insert("x-app-version", self.app_version.clone()); - let client = &mut self.client.clone(); - let res = client.batch_query(tonic_request).await; + let res = client.batch_query(self.build_request(request)).await; match res { Ok(response) => Ok(response.into_inner()), @@ -346,7 +340,8 @@ impl XmtpMlsClient for Client { #[tracing::instrument(level = "trace", skip_all)] async fn upload_key_package(&self, req: UploadKeyPackageRequest) -> Result<(), Error> { let client = &mut self.mls_client.clone(); - let res = client.upload_key_package(req).await; + + let res = client.upload_key_package(self.build_request(req)).await; match res { Ok(_) => Ok(()), Err(e) => Err(Error::new(ErrorKind::MlsError).with(e)), @@ -359,7 +354,7 @@ impl XmtpMlsClient for Client { req: FetchKeyPackagesRequest, ) -> Result { let client = &mut self.mls_client.clone(); - let res = client.fetch_key_packages(req).await; + let res = client.fetch_key_packages(self.build_request(req)).await; res.map(|r| r.into_inner()) .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) @@ -368,7 +363,7 @@ impl XmtpMlsClient for Client { #[tracing::instrument(level = "trace", skip_all)] async fn send_group_messages(&self, req: SendGroupMessagesRequest) -> Result<(), Error> { let client = &mut self.mls_client.clone(); - let res = client.send_group_messages(req).await; + let res = client.send_group_messages(self.build_request(req)).await; match res { Ok(_) => Ok(()), @@ -379,7 +374,7 @@ impl XmtpMlsClient for Client { #[tracing::instrument(level = "trace", skip_all)] async fn send_welcome_messages(&self, req: SendWelcomeMessagesRequest) -> Result<(), Error> { let client = &mut self.mls_client.clone(); - let res = client.send_welcome_messages(req).await; + let res = client.send_welcome_messages(self.build_request(req)).await; match res { Ok(_) => Ok(()), @@ -393,7 +388,7 @@ impl XmtpMlsClient for Client { req: QueryGroupMessagesRequest, ) -> Result { let client = &mut self.mls_client.clone(); - let res = client.query_group_messages(req).await; + let res = client.query_group_messages(self.build_request(req)).await; res.map(|r| r.into_inner()) .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) @@ -405,7 +400,7 @@ impl XmtpMlsClient for Client { req: QueryWelcomeMessagesRequest, ) -> Result { let client = &mut self.mls_client.clone(); - let res = client.query_welcome_messages(req).await; + let res = client.query_welcome_messages(self.build_request(req)).await; res.map(|r| r.into_inner()) .map_err(|e| Error::new(ErrorKind::MlsError).with(e)) @@ -417,7 +412,7 @@ impl XmtpMlsClient for Client { ) -> Result { let client = &mut self.mls_client.clone(); let res = client - .subscribe_group_messages(req) + .subscribe_group_messages(self.build_request(req)) .await .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; @@ -434,7 +429,7 @@ impl XmtpMlsClient for Client { ) -> Result { let client = &mut self.mls_client.clone(); let res = client - .subscribe_welcome_messages(req) + .subscribe_welcome_messages(self.build_request(req)) .await .map_err(|e| Error::new(ErrorKind::MlsError).with(e))?; diff --git a/xmtp_api_grpc/src/identity.rs b/xmtp_api_grpc/src/identity.rs index 5b635ef77..0fbb27e6d 100644 --- a/xmtp_api_grpc/src/identity.rs +++ b/xmtp_api_grpc/src/identity.rs @@ -1,4 +1,4 @@ -use tonic::{async_trait, Request}; +use tonic::async_trait; use xmtp_proto::{ api_client::{Error, ErrorKind, XmtpIdentityClient}, xmtp::identity::api::v1::{ @@ -17,13 +17,11 @@ impl XmtpIdentityClient for Client { &self, request: PublishIdentityUpdateRequest, ) -> Result { - let mut tonic_request = Request::new(request); - tonic_request - .metadata_mut() - .insert("x-app-version", self.app_version.clone()); let client = &mut self.identity_client.clone(); - let res = client.publish_identity_update(tonic_request).await; + let res = client + .publish_identity_update(self.build_request(request)) + .await; res.map(|response| response.into_inner()) .map_err(|err| Error::new(ErrorKind::IdentityError).with(err)) @@ -34,13 +32,9 @@ impl XmtpIdentityClient for Client { &self, request: GetInboxIdsRequest, ) -> Result { - let mut tonic_request = Request::new(request); - tonic_request - .metadata_mut() - .insert("x-app-version", self.app_version.clone()); let client = &mut self.identity_client.clone(); - let res = client.get_inbox_ids(tonic_request).await; + let res = client.get_inbox_ids(self.build_request(request)).await; res.map(|response| response.into_inner()) .map_err(|err| Error::new(ErrorKind::IdentityError).with(err)) @@ -51,13 +45,11 @@ impl XmtpIdentityClient for Client { &self, request: GetIdentityUpdatesV2Request, ) -> Result { - let mut tonic_request = Request::new(request); - tonic_request - .metadata_mut() - .insert("x-app-version", self.app_version.clone()); let client = &mut self.identity_client.clone(); - let res = client.get_identity_updates(tonic_request).await; + let res = client + .get_identity_updates(self.build_request(request)) + .await; res.map(|response| response.into_inner()) .map_err(|err| Error::new(ErrorKind::IdentityError).with(err)) diff --git a/xmtp_api_grpc/src/lib.rs b/xmtp_api_grpc/src/lib.rs index 9cc8bf750..10472c2a8 100644 --- a/xmtp_api_grpc/src/lib.rs +++ b/xmtp_api_grpc/src/lib.rs @@ -15,6 +15,7 @@ mod tests { use super::*; use futures::StreamExt; + use xmtp_proto::api_client::ClientWithMetadata; use xmtp_proto::{ api_client::{MutableApiSubscription, XmtpApiClient, XmtpApiSubscription}, xmtp::message_api::v1::{ @@ -52,7 +53,9 @@ mod tests { .await .unwrap(); - client.set_app_version("test/0.1.0".to_string()); + client + .set_app_version("test/0.1.0".to_string()) + .expect("failed to set app version"); let result = client .query(QueryRequest { @@ -301,4 +304,37 @@ mod tests { .await .expect("Timed out"); } + + #[tokio::test] + async fn metadata_test() { + let mut client = Client::create(DEV_ADDRESS.to_string(), true).await.unwrap(); + let app_version = "test/1.0.0".to_string(); + let libxmtp_version = "0.0.1".to_string(); + + client.set_app_version(app_version.clone()).unwrap(); + client.set_libxmtp_version(libxmtp_version.clone()).unwrap(); + + let request = client.build_request(PublishRequest { envelopes: vec![] }); + + assert_eq!( + request + .metadata() + .get("x-app-version") + .unwrap() + .to_str() + .unwrap() + .to_string(), + app_version + ); + assert_eq!( + request + .metadata() + .get("x-libxmtp-version") + .unwrap() + .to_str() + .unwrap() + .to_string(), + libxmtp_version + ); + } } diff --git a/xmtp_api_grpc_gateway/Cargo.toml b/xmtp_api_grpc_gateway/Cargo.toml index 3fb0db72f..a55827021 100644 --- a/xmtp_api_grpc_gateway/Cargo.toml +++ b/xmtp_api_grpc_gateway/Cargo.toml @@ -1,7 +1,7 @@ [package] +edition = "2021" name = "xmtp_api_grpc_gateway" version = "0.1.0" -edition = "2021" [lib] crate-type = ["cdylib", "rlib"] diff --git a/xmtp_api_http/Cargo.toml b/xmtp_api_http/Cargo.toml index 381f160c8..08e04175b 100644 --- a/xmtp_api_http/Cargo.toml +++ b/xmtp_api_http/Cargo.toml @@ -1,25 +1,24 @@ [package] edition = "2021" name = "xmtp_api_http" -version = "0.1.0" [lib] crate-type = ["cdylib", "rlib"] [dependencies] -log.workspace = true -tracing.workspace = true +async-stream.workspace = true async-trait = { workspace = true } +bytes = "1.7" futures = { workspace = true } +log.workspace = true reqwest = { version = "0.12.5", features = ["json", "stream"] } serde = { workspace = true } serde_json = { workspace = true } -xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } +thiserror = "1.0" tokio = { workspace = true, features = ["sync", "rt", "macros"] } tokio-stream = { version = "0.1", default-features = false } -async-stream.workspace = true -bytes = "1.7" -thiserror = "1.0" +tracing.workspace = true +xmtp_proto = { path = "../xmtp_proto", features = ["proto_full"] } [dev-dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } diff --git a/xmtp_api_http/src/lib.rs b/xmtp_api_http/src/lib.rs index e4708371d..bdda525aa 100644 --- a/xmtp_api_http/src/lib.rs +++ b/xmtp_api_http/src/lib.rs @@ -2,8 +2,9 @@ pub mod constants; mod util; use async_trait::async_trait; +use reqwest::header; use util::{create_grpc_stream, handle_error}; -use xmtp_proto::api_client::{Error, ErrorKind, XmtpIdentityClient}; +use xmtp_proto::api_client::{ClientWithMetadata, Error, ErrorKind, XmtpIdentityClient}; use xmtp_proto::xmtp::identity::api::v1::{ GetIdentityUpdatesRequest as GetIdentityUpdatesV2Request, GetIdentityUpdatesResponse as GetIdentityUpdatesV2Response, GetInboxIdsRequest, @@ -31,6 +32,8 @@ pub enum HttpClientError { pub struct XmtpHttpApiClient { http_client: reqwest::Client, host_url: String, + app_version: Option, + libxmtp_version: Option, } impl XmtpHttpApiClient { @@ -42,6 +45,8 @@ impl XmtpHttpApiClient { Ok(XmtpHttpApiClient { http_client: client, host_url, + app_version: None, + libxmtp_version: None, }) } @@ -50,6 +55,43 @@ impl XmtpHttpApiClient { } } +impl ClientWithMetadata for XmtpHttpApiClient { + fn set_app_version(&mut self, version: String) -> Result<(), Error> { + self.app_version = Some(version); + + let mut headers = header::HeaderMap::new(); + if let Some(app_version) = &self.app_version { + headers.insert("x-app-version", app_version.parse().unwrap()); + } + if let Some(libxmtp_version) = &self.libxmtp_version { + headers.insert("x-libxmtp-version", libxmtp_version.parse().unwrap()); + } + self.http_client = reqwest::Client::builder() + .connection_verbose(true) + .default_headers(headers) + .build() + .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; + Ok(()) + } + fn set_libxmtp_version(&mut self, version: String) -> Result<(), Error> { + self.libxmtp_version = Some(version); + + let mut headers = header::HeaderMap::new(); + if let Some(app_version) = &self.app_version { + headers.insert("x-app-version", app_version.parse().unwrap()); + } + if let Some(libxmtp_version) = &self.libxmtp_version { + headers.insert("x-libxmtp-version", libxmtp_version.parse().unwrap()); + } + self.http_client = reqwest::Client::builder() + .connection_verbose(true) + .default_headers(headers) + .build() + .map_err(|e| Error::new(ErrorKind::MetadataError).with(e))?; + Ok(()) + } +} + #[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl XmtpMlsClient for XmtpHttpApiClient { diff --git a/xmtp_cryptography/Cargo.toml b/xmtp_cryptography/Cargo.toml index 3b59b57be..f5509e030 100644 --- a/xmtp_cryptography/Cargo.toml +++ b/xmtp_cryptography/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "xmtp_cryptography" -version = "0.1.0" edition = "2021" +name = "xmtp_cryptography" rust-version = "1.64" [dependencies] diff --git a/xmtp_id/Cargo.toml b/xmtp_id/Cargo.toml index 74b65298c..50c01b6d8 100644 --- a/xmtp_id/Cargo.toml +++ b/xmtp_id/Cargo.toml @@ -1,15 +1,14 @@ [package] edition = "2021" name = "xmtp_id" -version = "0.1.0" [dependencies] async-trait.workspace = true chrono.workspace = true ed25519-dalek = { workspace = true, features = ["digest"] } ed25519.workspace = true -ethers.workspace = true ethers-core.workspace = true +ethers.workspace = true futures.workspace = true hex.workspace = true log.workspace = true diff --git a/xmtp_mls/Cargo.toml b/xmtp_mls/Cargo.toml index a3f34cd63..b802ec996 100644 --- a/xmtp_mls/Cargo.toml +++ b/xmtp_mls/Cargo.toml @@ -1,7 +1,6 @@ [package] edition = "2021" name = "xmtp_mls" -version = "0.1.0" [[bin]] doc = false diff --git a/xmtp_mls/src/api/test_utils.rs b/xmtp_mls/src/api/test_utils.rs index b263c9400..973ab17b4 100644 --- a/xmtp_mls/src/api/test_utils.rs +++ b/xmtp_mls/src/api/test_utils.rs @@ -2,7 +2,8 @@ use async_trait::async_trait; use mockall::mock; use xmtp_proto::{ api_client::{ - Error, GroupMessageStream, WelcomeMessageStream, XmtpIdentityClient, XmtpMlsClient, + ClientWithMetadata, Error, GroupMessageStream, WelcomeMessageStream, XmtpIdentityClient, + XmtpMlsClient, }, xmtp::identity::api::v1::{ GetIdentityUpdatesRequest as GetIdentityUpdatesV2Request, @@ -40,6 +41,11 @@ pub fn build_group_messages(num_messages: usize, group_id: Vec) -> Vec Result<(), Error>; + fn set_app_version(&mut self, version: String) -> Result<(), Error>; + } + #[async_trait] impl XmtpMlsClient for ApiClient { async fn upload_key_package(&self, request: UploadKeyPackageRequest) -> Result<(), Error>; diff --git a/xmtp_mls/src/builder.rs b/xmtp_mls/src/builder.rs index bd568a423..dce196d84 100644 --- a/xmtp_mls/src/builder.rs +++ b/xmtp_mls/src/builder.rs @@ -40,6 +40,8 @@ pub enum ClientBuilderError { WrappedApiError(#[from] crate::api::WrappedApiError), #[error(transparent)] GroupError(#[from] crate::groups::GroupError), + #[error(transparent)] + ApiError(#[from] xmtp_proto::api_client::Error), } pub struct ClientBuilder { @@ -48,6 +50,7 @@ pub struct ClientBuilder { store: Option, identity_strategy: IdentityStrategy, history_sync_url: Option, + app_version: Option, } impl ClientBuilder @@ -61,6 +64,7 @@ where store: None, identity_strategy: strategy, history_sync_url: None, + app_version: None, } } @@ -84,14 +88,24 @@ where self } + pub fn app_version(mut self, version: String) -> Self { + self.app_version = Some(version); + self + } + pub async fn build(mut self) -> Result, ClientBuilderError> { debug!("Building client"); - let api_client = self - .api_client - .take() - .ok_or(ClientBuilderError::MissingParameter { - parameter: "api_client", - })?; + let mut api_client = + self.api_client + .take() + .ok_or(ClientBuilderError::MissingParameter { + parameter: "api_client", + })?; + api_client.set_libxmtp_version(env!("CARGO_PKG_VERSION").to_string())?; + if let Some(app_version) = self.app_version { + api_client.set_app_version(app_version)?; + } + let api_client_wrapper = ApiClientWrapper::new(api_client, Retry::default()); let store = self .store diff --git a/xmtp_mls/src/lib.rs b/xmtp_mls/src/lib.rs index 0257ddedf..c6bc4f060 100644 --- a/xmtp_mls/src/lib.rs +++ b/xmtp_mls/src/lib.rs @@ -25,28 +25,31 @@ mod xmtp_openmls_provider; pub use client::{Client, Network}; use storage::StorageError; use xmtp_cryptography::signature::{RecoverableSignature, SignatureError}; -use xmtp_proto::api_client::{XmtpIdentityClient, XmtpMlsClient}; +use xmtp_proto::api_client::{ClientWithMetadata, XmtpIdentityClient, XmtpMlsClient}; /// XMTP Api Super Trait /// Implements all Trait Network APIs for convenience. #[cfg(not(test))] pub trait XmtpApi where - Self: XmtpMlsClient + XmtpIdentityClient, + Self: XmtpMlsClient + XmtpIdentityClient + ClientWithMetadata, { } #[cfg(not(test))] -impl XmtpApi for T where T: XmtpMlsClient + XmtpIdentityClient + ?Sized {} +impl XmtpApi for T where T: XmtpMlsClient + XmtpIdentityClient + ClientWithMetadata + ?Sized {} #[cfg(test)] pub trait XmtpApi where - Self: XmtpMlsClient + XmtpIdentityClient + XmtpTestClient, + Self: XmtpMlsClient + XmtpIdentityClient + XmtpTestClient + ClientWithMetadata, { } #[cfg(test)] -impl XmtpApi for T where T: XmtpMlsClient + XmtpIdentityClient + XmtpTestClient + ?Sized {} +impl XmtpApi for T where + T: XmtpMlsClient + XmtpIdentityClient + XmtpTestClient + ClientWithMetadata + ?Sized +{ +} #[cfg(any(test, feature = "test-utils", feature = "bench"))] #[async_trait::async_trait] diff --git a/xmtp_proto/Cargo.toml b/xmtp_proto/Cargo.toml index 06d717760..ee420ec7c 100644 --- a/xmtp_proto/Cargo.toml +++ b/xmtp_proto/Cargo.toml @@ -1,33 +1,44 @@ [package] -name = "xmtp_proto" -version = "0.1.0" edition = "2021" +name = "xmtp_proto" [dependencies] async-trait = { workspace = true } futures = { workspace = true } futures-core = { workspace = true } -pbjson.workspace = true pbjson-types.workspace = true +pbjson.workspace = true prost = { workspace = true, features = ["prost-derive"] } # Only necessary if using Protobuf well-known types: +openmls = { workspace = true, optional = true } +openmls_basic_credential = { workspace = true, optional = true } prost-types = { workspace = true } serde = { workspace = true } tonic = { workspace = true, optional = true } -openmls_basic_credential = { workspace = true, optional = true } -openmls = { workspace = true, optional = true } [features] -default = [] convert = ["openmls_basic_credential", "openmls", "proto_full"] +default = [] grpc = ["tonic"] # @@protoc_deletion_point(features) # This section is automatically generated by protoc-gen-prost-crate. # Changes in this area may be lost on regeneration. -proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations","xmtp-keystore_api-v1","xmtp-message_api-v1","xmtp-message_contents","xmtp-mls-api-v1","xmtp-mls-database","xmtp-mls-message_contents","xmtp-mls_validation-v1","xmtp-xmtpv4"] +proto_full = [ + "xmtp-identity", + "xmtp-identity-api-v1", + "xmtp-identity-associations", + "xmtp-keystore_api-v1", + "xmtp-message_api-v1", + "xmtp-message_contents", + "xmtp-mls-api-v1", + "xmtp-mls-database", + "xmtp-mls-message_contents", + "xmtp-mls_validation-v1", + "xmtp-xmtpv4", +] "xmtp-identity" = [] -"xmtp-identity-api-v1" = ["xmtp-identity","xmtp-identity-associations"] -"xmtp-identity-associations" = ["xmtp-identity","xmtp-message_contents"] +"xmtp-identity-api-v1" = ["xmtp-identity", "xmtp-identity-associations"] +"xmtp-identity-associations" = ["xmtp-identity", "xmtp-message_contents"] "xmtp-keystore_api-v1" = ["xmtp-message_contents"] "xmtp-message_api-v1" = ["xmtp-message_contents"] "xmtp-message_contents" = [] @@ -35,5 +46,5 @@ proto_full = ["xmtp-identity","xmtp-identity-api-v1","xmtp-identity-associations "xmtp-mls-database" = [] "xmtp-mls-message_contents" = ["xmtp-message_contents"] "xmtp-mls_validation-v1" = ["xmtp-identity-associations"] -"xmtp-xmtpv4" = ["xmtp-identity-associations","xmtp-mls-api-v1"] -## @@protoc_insertion_point(features) \ No newline at end of file +"xmtp-xmtpv4" = ["xmtp-identity-associations", "xmtp-mls-api-v1"] +## @@protoc_insertion_point(features) diff --git a/xmtp_proto/src/api_client.rs b/xmtp_proto/src/api_client.rs index c48d9038f..ab6dabb96 100644 --- a/xmtp_proto/src/api_client.rs +++ b/xmtp_proto/src/api_client.rs @@ -31,6 +31,7 @@ pub enum ErrorKind { MlsError, IdentityError, SubscriptionUpdateError, + MetadataError, } type ErrorSource = Box; @@ -78,6 +79,7 @@ impl fmt::Display for Error { ErrorKind::IdentityError => "identity error", ErrorKind::MlsError => "mls error", ErrorKind::SubscriptionUpdateError => "subscription update error", + ErrorKind::MetadataError => "metadata error", })?; if self.source().is_some() { f.write_str(": ")?; @@ -108,6 +110,11 @@ pub trait MutableApiSubscription: Stream> + Send fn close(&self); } +pub trait ClientWithMetadata: Send + Sync { + fn set_libxmtp_version(&mut self, version: String) -> Result<(), Error>; + fn set_app_version(&mut self, version: String) -> Result<(), Error>; +} + // Wasm futures don't have `Send` or `Sync` bounds. #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -115,8 +122,6 @@ pub trait XmtpApiClient: Send + Sync { type Subscription: XmtpApiSubscription; type MutableSubscription: MutableApiSubscription; - fn set_app_version(&mut self, version: String); - async fn publish( &self, token: String, diff --git a/xmtp_user_preferences/Cargo.toml b/xmtp_user_preferences/Cargo.toml index c52321985..f948eb32a 100644 --- a/xmtp_user_preferences/Cargo.toml +++ b/xmtp_user_preferences/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "xmtp_user_preferences" -version = "0.1.0" edition = "2021" +name = "xmtp_user_preferences" [dependencies] base64 = "0.21.4" diff --git a/xmtp_v2/Cargo.toml b/xmtp_v2/Cargo.toml index f99ad24c0..4b1dddfdc 100644 --- a/xmtp_v2/Cargo.toml +++ b/xmtp_v2/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "xmtp_v2" -version = "0.1.0" edition = "2021" +name = "xmtp_v2" rust-version = "1.64" [dependencies]