Skip to content

Commit

Permalink
Attempt to make openssl optional by splitting packages and using feat…
Browse files Browse the repository at this point in the history
…ures
  • Loading branch information
daniel-chambers committed Sep 2, 2024
1 parent 64dbb8e commit 9d26466
Show file tree
Hide file tree
Showing 13 changed files with 258 additions and 142 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

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

33 changes: 33 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,39 @@ members = [
"crates/*",
]

[workspace.dependencies]
ndc-sdk-core = { path = "../sdk-core" }
ndc-models = { git = "http://github.com/hasura/ndc-spec.git", tag = "v0.1.6" }
ndc-test = { git = "http://github.com/hasura/ndc-spec.git", tag = "v0.1.6" }

anyhow = "1"
async-trait = "0.1"
axum = { version = "0.6", features = ["http2"] }
axum-extra = "0.8"
bytes = "1"
clap = { version = "4", features = ["derive", "env"] }
http = "0.2"
mime = "0.3"
opentelemetry = "0.22"
opentelemetry-http = "0.11"
opentelemetry-otlp = { version = "0.15", features = ["reqwest-client", "gzip-tonic", "tls", "tls-roots", "http-proto"] }
opentelemetry-semantic-conventions = "0.14"
opentelemetry_sdk = { version = "0.22", features = ["rt-tokio"] }
opentelemetry-zipkin = "0.20"
prometheus = "0.13"
reqwest = "0.11"
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["raw_value"] }
thiserror = "1"
tokio = { version = "1", features = ["fs", "macros", "rt-multi-thread", "signal"] }
tokio-test = "0.4"
tower-http = { version = "0.4", features = ["cors", "limit", "trace", "validate-request"] }
tracing = "0.1"
tracing-opentelemetry = "0.23"
tracing-subscriber = { version = "0.3", default-features = false, features = ["ansi", "env-filter", "fmt", "json"] }
url = "2"


[workspace.lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
Expand Down
41 changes: 41 additions & 0 deletions crates/sdk-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[package]
name = "ndc-sdk-core"
version.workspace = true
edition.workspace = true
license.workspace = true

[lints]
workspace = true

[lib]
name = "ndc_sdk_core"
path = "src/lib.rs"

[features]
default = ["axum", "ndc-test"]

axum = ["dep:axum", "dep:mime"]

ndc-test = ["dep:ndc-test"]

[dependencies]
ndc-models = { workspace = true }
ndc-test = { workspace = true, optional = true }

async-trait = { workspace = true }
axum = { workspace = true, features = ["http2"], optional = true }
bytes = { workspace = true }
http = { workspace = true }
mime = { workspace = true, optional = true }
prometheus = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, features = ["raw_value"] }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["fs", "macros", "rt-multi-thread", "signal", "sync"] }
tracing = { workspace = true }

[dev-dependencies]
anyhow = { workspace = true }
axum = { workspace = true, features = ["http2"] }
reqwest = { workspace = true }
tokio-test = { workspace = true }
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::fmt::Display;
use std::path::PathBuf;

use axum::response::{IntoResponse, Response};
use axum::Json;
#[cfg(feature = "axum")]
use axum::{
response::{IntoResponse, Response},
Json,
};
use http::StatusCode;
use serde::Serialize;

Expand Down Expand Up @@ -101,6 +104,7 @@ impl From<String> for ErrorResponse {
}
}

#[cfg(feature = "axum")]
impl IntoResponse for ErrorResponse {
fn into_response(self) -> Response {
(self.status_code, Json(self.inner)).into_response()
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#[cfg(feature = "axum")]
use axum::response::IntoResponse;
use bytes::Bytes;
#[cfg(feature = "axum")]
use http::{header, HeaderValue};

/// Represents a response value that will be serialized to JSON.
Expand Down Expand Up @@ -27,9 +29,7 @@ impl<A: (for<'de> serde::Deserialize<'de>)> JsonResponse<A> {
///
/// This is only intended for testing and compatibility. If it lives on a
/// critical path, we recommend you avoid it.
pub(crate) fn into_value<E: From<Box<dyn std::error::Error + Send + Sync>>>(
self,
) -> Result<A, E> {
pub fn into_value<E: From<Box<dyn std::error::Error + Send + Sync>>>(self) -> Result<A, E> {
match self {
Self::Value(value) => Ok(value),
Self::Serialized(bytes) => {
Expand All @@ -39,6 +39,7 @@ impl<A: (for<'de> serde::Deserialize<'de>)> JsonResponse<A> {
}
}

#[cfg(feature = "axum")]
impl<A: serde::Serialize> IntoResponse for JsonResponse<A> {
fn into_response(self) -> axum::response::Response {
match self {
Expand Down
4 changes: 4 additions & 0 deletions crates/sdk-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod connector;
pub mod json_response;
pub mod schema;
pub mod state;
94 changes: 94 additions & 0 deletions crates/sdk-core/src/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use std::{io::Write, path::Path};

use crate::{
connector::{Connector, ConnectorSetup, Result},
json_response::JsonResponse,
state::init_server_state,
};

pub async fn get_capabilities<C: Connector>() -> JsonResponse<ndc_models::CapabilitiesResponse> {
let capabilities = C::get_capabilities().await;
ndc_models::CapabilitiesResponse {
version: ndc_models::VERSION.into(),
capabilities,
}
.into()
}

/// Prints a JSON object to the writer containing the ndc schema and capabilities of the connector
pub async fn print_schema_and_capabilities<Setup, W: Write>(
setup: Setup,
config_directory: &Path,
writer: W,
) -> Result<()>
where
Setup: ConnectorSetup,
Setup::Connector: Connector + 'static,
<Setup::Connector as Connector>::Configuration: Clone,
<Setup::Connector as Connector>::State: Clone,
{
let server_state = init_server_state(setup, config_directory).await?;

let schema = Setup::Connector::get_schema(server_state.configuration()).await?;
let capabilities = get_capabilities::<Setup::Connector>().await;

print_json_schema_and_capabilities(writer, schema, capabilities)?;

Ok(())
}

/// This foulness manually writes out a JSON object with schema and capabilities properties.
/// We do it like this to avoid having to deserialize and reserialize any
/// JsonResponse::Serialized values.
fn print_json_schema_and_capabilities<W: Write>(
mut writer: W,
schema: JsonResponse<ndc_models::SchemaResponse>,
capabilities: JsonResponse<ndc_models::CapabilitiesResponse>,
) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
write!(writer, r#"{{"schema":"#)?;
write_json_response(&mut writer, schema)?;
write!(writer, r#","capabilities":"#)?;
write_json_response(&mut writer, capabilities)?;
writeln!(writer, r#"}}"#)?;

Ok(())
}

fn write_json_response<W: Write, A: serde::Serialize>(
writer: &mut W,
json: JsonResponse<A>,
) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
match json {
JsonResponse::Value(value) => Ok(serde_json::to_writer(writer, &value)?),
JsonResponse::Serialized(bytes) => Ok(writer.write_all(&bytes)?),
}
}

#[cfg(test)]
mod tests {
use std::io::Cursor;

use crate::connector::{example::Example, Connector};

use super::{get_capabilities, print_json_schema_and_capabilities};

#[derive(Debug, serde::Deserialize)]
#[allow(dead_code)]
struct SchemaAndCapabilities {
pub schema: ndc_models::SchemaResponse,
pub capabilities: ndc_models::CapabilitiesResponse,
}

#[test]
fn test_print_json_schema_and_capabilities_is_valid_json() {
tokio_test::block_on(async {
let mut bytes = Cursor::new(vec![]);
let schema = Example::get_schema(&()).await.unwrap();
let capabilities = get_capabilities::<Example>().await;
print_json_schema_and_capabilities(&mut bytes, schema, capabilities).unwrap();

let bytes = bytes.into_inner();
serde_json::from_slice::<SchemaAndCapabilities>(&bytes).unwrap();
});
}
}
12 changes: 12 additions & 0 deletions crates/sdk/src/state.rs → crates/sdk-core/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::path::Path;
use std::sync::Arc;

use prometheus::Registry;
use tokio::sync::OnceCell;

use crate::connector::error::*;
Expand Down Expand Up @@ -79,3 +81,13 @@ impl<C: Connector> ServerState<C> {
&self.metrics
}
}

/// Initialize the server state from the configuration file.
pub async fn init_server_state<Setup: ConnectorSetup>(
setup: Setup,
config_directory: &Path,
) -> Result<ServerState<Setup::Connector>> {
let metrics = Registry::new();
let configuration = setup.parse_configuration(config_directory).await?;
Ok(ServerState::new(configuration, setup, metrics))
}
61 changes: 31 additions & 30 deletions crates/sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,38 @@ default = ["native-tls", "ndc-test"]
native-tls = ["reqwest/native-tls"]
rustls = ["reqwest/rustls"]

ndc-test = ["dep:ndc-test"]
ndc-test = ["dep:ndc-test", "ndc-sdk-core/ndc-test"]

[dependencies]
ndc-models = { git = "http://github.com/hasura/ndc-spec.git", tag = "v0.1.6" }
ndc-test = { git = "http://github.com/hasura/ndc-spec.git", tag = "v0.1.6", optional = true }

async-trait = "0.1"
axum = { version = "0.6", features = ["http2"] }
axum-extra = "0.8"
bytes = "1"
clap = { version = "4", features = ["derive", "env"] }
http = "0.2"
mime = "0.3"
opentelemetry = "0.22"
opentelemetry-http = "0.11"
opentelemetry-otlp = { version = "0.15", features = ["reqwest-client", "gzip-tonic", "tls", "tls-roots", "http-proto"] }
opentelemetry-semantic-conventions = "0.14"
opentelemetry_sdk = { version = "0.22", features = ["rt-tokio"] }
opentelemetry-zipkin = "0.20"
prometheus = "0.13"
reqwest = "0.11"
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["raw_value"] }
thiserror = "1"
tokio = { version = "1", features = ["fs", "macros", "rt-multi-thread", "signal"] }
tower-http = { version = "0.4", features = ["cors", "limit", "trace", "validate-request"] }
tracing = "0.1"
tracing-opentelemetry = "0.23"
tracing-subscriber = { version = "0.3", default-features = false, features = ["ansi", "env-filter", "fmt", "json"] }
url = "2"
ndc-sdk-core = { path = "../sdk-core", default-features = false, features = ["axum"]}
ndc-models = { workspace = true }
ndc-test = { workspace = true, optional = true }

async-trait = { workspace = true }
axum = { workspace = true, features = ["http2"] }
axum-extra = { workspace = true }
bytes = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] }
http = { workspace = true }
mime = { workspace = true }
opentelemetry = { workspace = true }
opentelemetry-http = { workspace = true }
opentelemetry-otlp = { workspace = true, features = ["reqwest-client", "gzip-tonic", "tls", "tls-roots", "http-proto"] }
opentelemetry-semantic-conventions = { workspace = true }
opentelemetry_sdk = { workspace = true, features = ["rt-tokio"] }
opentelemetry-zipkin = { workspace = true }
prometheus = { workspace = true }
reqwest = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, features = ["raw_value"] }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["fs", "macros", "rt-multi-thread", "signal"] }
tower-http = { workspace = true, features = ["cors", "limit", "trace", "validate-request"] }
tracing = { workspace = true }
tracing-opentelemetry = { workspace = true }
tracing-subscriber = { workspace = true, default-features = false, features = ["ansi", "env-filter", "fmt", "json"] }
url = { workspace = true }

[dev-dependencies]
anyhow = "1"
tokio-test = "0.4"
anyhow = { workspace = true }
tokio-test = { workspace = true }
Loading

0 comments on commit 9d26466

Please sign in to comment.