Skip to content

Commit c61c0a8

Browse files
authored
Merge pull request #182 from shashitnak/std-protobuf
feat: adding wasm compatibility, windows support and removing protoc dependency
2 parents a608f96 + 3eacb3c commit c61c0a8

File tree

12 files changed

+812
-867
lines changed

12 files changed

+812
-867
lines changed

Diff for: Cargo.lock

+604-687
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

+23-11
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ license = "MIT"
1010
keywords = ["async_graphql", "async", "graphql", "apollo", "studio"]
1111
categories = ["network-programming", "asynchronous"]
1212
edition = "2021"
13+
resolver = "2"
1314

1415
[features]
15-
default = ["tokio-comp", "compression"]
16+
default = ["compression"]
1617
compression = ["libflate"]
17-
tokio-comp = ["tokio"]
1818

1919
[dependencies]
2020
anyhow = "1"
@@ -25,21 +25,33 @@ cfg-if = "1"
2525
derive_builder = "0.13"
2626
futures = "0.3"
2727
futures-locks = "0.7"
28-
prost = "0.12"
29-
prost-types = "0.12"
3028
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
31-
serde_json = "1"
32-
serde = { version = "1", features = ["derive"] }
3329
sha2 = "0.10"
34-
tonic = "0.10"
30+
serde-json-wasm = "1.0.1"
3531
tracing = "0.1"
36-
tracing-futures = { version = "0.2.5", default-features = false, features = ["tokio", "futures-03", "std"] }
37-
uuid = { version = "1.7", features = ["v4"] } # A library to generate and parse UUIDs.
32+
uuid = { version = "1.7", features = ["v4", "js"] } # A library to generate and parse UUIDs.
33+
wasm-bindgen-futures = "0.4.18"
34+
protobuf = "3.4.0"
35+
36+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
37+
serde = { version = "1", features = ["derive"] }
38+
serde_json = "1"
39+
tokio = { version = "1", features = ["full"] }
3840

3941
# Non-feature optional dependencies
4042
libflate = { version = "2", optional = true }
41-
tokio = { version = "1", features = ["full"], optional = true }
43+
44+
[target.'cfg(all(not(target_arch = "wasm32"), not(target_os = "windows")))'.dependencies]
45+
uname = "0.1.1"
4246

4347
[build-dependencies]
44-
reqwest = { version = "0.11", default-features = false, features = ["blocking", "rustls-tls"] }
48+
protobuf-codegen = "3.4.0"
49+
async-std = { version = "1", default-features = false, features = ["default", "tokio1"] }
50+
cfg-if = "1.0.0"
51+
reqwest = { version = "0.11", default-features = false, features = ["rustls-tls"] }
52+
prost-build = "0.12.3"
53+
protox = "0.6.0"
4554
tonic-build = "0.10"
55+
56+
[target.'cfg(not(target_arch = "wasm32"))'.build-dependencies]
57+
tokio = { version = "1", features = ["full"] }

Diff for: build.rs

+40-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// Derived from https://github.com/pellizzetti/router/blob/cc0ebcaf1d68184e1fe06f16534fddff76286b40/apollo-spaceport/build.rs
2+
use protobuf_codegen::Customize;
3+
use std::io::Write;
4+
use std::path::Path;
25
use std::{
36
error::Error,
47
fs::File,
@@ -11,8 +14,18 @@ fn main() -> Result<(), Box<dyn Error>> {
1114
} else {
1215
// Retrieve a live version of the reports.proto file
1316
let proto_url = "https://usage-reporting.api.apollographql.com/proto/reports.proto";
14-
let response = reqwest::blocking::get(proto_url)?;
15-
let mut content = response.text()?;
17+
let fut = reqwest::get(proto_url);
18+
19+
cfg_if::cfg_if! {
20+
if #[cfg(not(target_arch = "wasm32"))] {
21+
let rt = tokio::runtime::Runtime::new().unwrap();
22+
let response = rt.block_on(fut)?;
23+
let mut content = rt.block_on(response.text())?;
24+
} else {
25+
let response = async_std::task::block_on(fut)?;
26+
let mut content = async_std::task::block_on(response.text())?;
27+
}
28+
}
1629

1730
// Process the retrieved content to:
1831
// - Insert a package Report; line after the import lines (currently only one) and before the first message definition
@@ -45,19 +58,32 @@ fn main() -> Result<(), Box<dyn Error>> {
4558
}
4659

4760
// Process the proto files
48-
let proto_files = vec!["proto/agents.proto", "proto/reports.proto"];
61+
let proto_files = vec!["proto/reports.proto"];
62+
63+
protobuf_codegen::Codegen::new()
64+
.pure()
65+
.cargo_out_dir("proto")
66+
.inputs(&proto_files)
67+
.include(".")
68+
.customize(Customize::default().gen_mod_rs(false))
69+
.run_from_script();
70+
71+
let out_dir = std::env::var("OUT_DIR")?;
72+
let path = Path::new(&out_dir).join("proto").join("reports.rs");
73+
let content = std::fs::read_to_string(&path)?;
74+
75+
let content = content
76+
.lines()
77+
.filter(|line| !(line.contains("#![") || line.contains("//!")))
78+
.fold(String::new(), |mut content, line| {
79+
content.push_str(line);
80+
content.push('\n');
81+
content
82+
});
4983

50-
tonic_build::configure()
51-
.type_attribute("ContextualizedStats", "#[derive(serde::Serialize)]")
52-
.type_attribute("StatsContext", "#[derive(serde::Serialize)]")
53-
.type_attribute("QueryLatencyStats", "#[derive(serde::Serialize)]")
54-
.type_attribute("TypeStat", "#[derive(serde::Serialize)]")
55-
.type_attribute("PathErrorStats", "#[derive(serde::Serialize)]")
56-
.type_attribute("FieldStat", "#[derive(serde::Serialize)]")
57-
.type_attribute("ReferencedFieldsForType", "#[derive(serde::Serialize)]")
58-
.type_attribute("StatsContext", "#[derive(Eq, Hash)]")
59-
.build_server(true)
60-
.compile(&proto_files, &["."])?;
84+
std::fs::remove_file(&path)?;
85+
let mut file = std::fs::File::create(&path)?;
86+
file.write_all(content.as_bytes())?;
6187

6288
for file in proto_files {
6389
println!("cargo:rerun-if-changed={}", file);

Diff for: src/compression.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
#[cfg(feature = "compression")]
1+
#[cfg(all(feature = "compression", not(target_arch = "wasm32")))]
22
use libflate::gzip;
33

4-
#[cfg(feature = "compression")]
4+
#[cfg(all(feature = "compression", not(target_arch = "wasm32")))]
55
const TARGET_LOG_COMPRESSION: &str = "apollo-studio-extension-compression";
66

7-
#[cfg(feature = "compression")]
7+
#[cfg(all(feature = "compression", not(target_arch = "wasm32")))]
88
pub fn compress(msg: Vec<u8>) -> Result<Vec<u8>, std::io::Error> {
99
let mut encoder = gzip::Encoder::new(Vec::new()).unwrap();
1010
let mut msg = std::io::Cursor::new(msg);
@@ -20,7 +20,7 @@ pub fn compress(msg: Vec<u8>) -> Result<Vec<u8>, std::io::Error> {
2020
encoder.finish().into_result()
2121
}
2222

23-
#[cfg(not(feature = "compression"))]
23+
#[cfg(any(not(feature = "compression"), target_arch = "wasm32"))]
2424
pub fn compress(msg: Vec<u8>) -> Result<Vec<u8>, std::io::Error> {
2525
Ok::<Vec<u8>, std::io::Error>(msg)
2626
}

Diff for: src/lib.rs

+44-35
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,25 @@
2626
//!
2727
//! * `compression` - To enable GZIP Compression when sending traces to Apollo Studio.
2828
mod compression;
29-
mod packages;
3029
mod proto;
3130
pub mod register;
3231
mod report_aggregator;
3332

3433
mod runtime;
34+
mod packages;
35+
3536
use futures::SinkExt;
36-
use prost_types::Timestamp;
37+
use protobuf::{well_known_types::timestamp::Timestamp, EnumOrUnknown, MessageField};
3738
use report_aggregator::ReportAggregator;
3839
use runtime::spawn;
40+
use packages::serde_json;
3941

4042
#[macro_use]
4143
extern crate tracing;
4244

43-
use futures_locks::RwLock;
4445
use std::collections::HashMap;
4546
use std::sync::Arc;
47+
use std::sync::RwLock;
4648

4749
use async_graphql::QueryPathSegment;
4850
use chrono::{DateTime, Utc};
@@ -55,13 +57,13 @@ use async_graphql::extensions::{
5557
};
5658
use async_graphql::parser::types::{ExecutableDocument, OperationType, Selection};
5759
use async_graphql::{Response, ServerResult, Value, Variables};
58-
use proto::report::{
60+
use proto::reports::{
5961
trace::{self, node, Node},
6062
Trace,
6163
};
6264
use std::convert::TryInto;
6365

64-
pub use proto::report::trace::http::Method;
66+
pub use proto::reports::trace::http::Method;
6567

6668
/// Apollo Tracing Extension to send traces to Apollo Studio
6769
/// The extension to include to your `async_graphql` instance to connect with Apollo Studio.
@@ -185,7 +187,7 @@ impl Extension for ApolloTracingExtension {
185187
.any(|(_, operation)| operation.node.selection_set.node.items.iter().any(|selection| matches!(&selection.node, Selection::Field(field) if field.node.name.node == "__schema")));
186188
if !is_schema {
187189
let result: String =
188-
ctx.stringify_execute_doc(&document, &Variables::from_json(serde_json::json!({})));
190+
ctx.stringify_execute_doc(&document, &Variables::from_json(serde_json::from_str("{}").unwrap()));
189191
let name = document
190192
.operations
191193
.iter()
@@ -194,7 +196,7 @@ impl Extension for ApolloTracingExtension {
194196
.map(|x| x.as_str())
195197
.unwrap_or("no_name");
196198
let query_type = format!("# {name}\n {query}", name = name, query = result);
197-
*self.operation_name.write().await = query_type;
199+
*self.operation_name.write().unwrap() = query_type;
198200
}
199201
Ok(document)
200202
}
@@ -227,7 +229,9 @@ impl Extension for ApolloTracingExtension {
227229
let client_version = tracing_extension
228230
.client_version
229231
.unwrap_or_else(|| "no client version".to_string());
230-
let method = tracing_extension.method.unwrap_or(Method::Unknown);
232+
let method = tracing_extension
233+
.method
234+
.or(<Method as protobuf::Enum>::from_str("UNKNOWN"));
231235
let status_code = tracing_extension.status_code.unwrap_or(0);
232236

233237
let mut trace: Trace = Trace {
@@ -245,34 +249,39 @@ impl Extension for ApolloTracingExtension {
245249
.map(|x| x.to_string())
246250
.unwrap_or_else(|| "no operation".to_string()),
247251
..Default::default()
248-
});
252+
})
253+
.into();
249254

250-
trace.http = Some(trace::Http {
251-
method: method.into(),
255+
trace.http = Some(trace::HTTP {
256+
method: EnumOrUnknown::new(method.unwrap()),
252257
status_code,
253258
..Default::default()
254-
});
259+
})
260+
.into();
255261

256-
trace.end_time = Some(Timestamp {
262+
trace.end_time = MessageField::some(Timestamp {
257263
nanos: inner.end_time.timestamp_subsec_nanos().try_into().unwrap(),
258264
seconds: inner.end_time.timestamp(),
265+
special_fields: Default::default(),
259266
});
260267

261-
trace.start_time = Some(Timestamp {
262-
nanos: inner
263-
.start_time
264-
.timestamp_subsec_nanos()
265-
.try_into()
266-
.unwrap(),
267-
seconds: inner.start_time.timestamp(),
268-
});
268+
trace.start_time =
269+
protobuf::MessageField::some(protobuf::well_known_types::timestamp::Timestamp {
270+
nanos: inner
271+
.start_time
272+
.timestamp_subsec_nanos()
273+
.try_into()
274+
.unwrap(),
275+
seconds: inner.start_time.timestamp(),
276+
special_fields: Default::default(),
277+
});
269278

270-
let root_node = self.root_node.read().await;
271-
trace.root = Some(root_node.clone());
279+
let root_node = self.root_node.read().unwrap();
280+
trace.root = Some(root_node.clone()).into();
272281

273282
let mut sender = self.report.sender();
274283

275-
let operation_name = self.operation_name.read().await.clone();
284+
let operation_name = self.operation_name.read().unwrap().clone();
276285

277286
let _handle = spawn(async move {
278287
if let Err(e) = sender.send((operation_name, trace)).await {
@@ -295,7 +304,7 @@ impl Extension for ApolloTracingExtension {
295304
let path = info.path_node.to_string_vec().join(".");
296305
let field_name = info.path_node.field_name().to_string();
297306
let parent_type = info.parent_type.to_string();
298-
let return_type = info.return_type.to_string();
307+
let _return_type = info.return_type.to_string();
299308
let start_time = Utc::now() - self.inner.lock().await.start_time;
300309
let path_node = info.path_node;
301310

@@ -320,12 +329,11 @@ impl Extension for ApolloTracingExtension {
320329
},
321330
parent_type: parent_type.to_string(),
322331
original_field_name: field_name,
323-
r#type: return_type,
324332
..Default::default()
325333
};
326334

327335
let node = Arc::new(RwLock::new(node));
328-
self.nodes.write().await.insert(path, node.clone());
336+
self.nodes.write().unwrap().insert(path, node.clone());
329337
let parent_node = path_node.parent.map(|x| x.to_string_vec().join("."));
330338
// Use the path to create a new node
331339
// https://github.com/apollographql/apollo-server/blob/291c17e255122d4733b23177500188d68fac55ce/packages/apollo-server-core/src/plugin/traceTreeBuilder.ts
@@ -334,7 +342,7 @@ impl Extension for ApolloTracingExtension {
334342
Err(e) => {
335343
let json = match serde_json::to_string(&e) {
336344
Ok(content) => content,
337-
Err(e) => serde_json::json!({ "error": format!("{:?}", e) }).to_string(),
345+
Err(e) => format!("{{ \"error\": \"{e:?}\" }}"),
338346
};
339347
let error = trace::Error {
340348
message: e.message.clone(),
@@ -345,19 +353,20 @@ impl Extension for ApolloTracingExtension {
345353
.map(|x| trace::Location {
346354
line: x.line as u32,
347355
column: x.column as u32,
356+
special_fields: protobuf::SpecialFields::default(),
348357
})
349358
.collect(),
350359
json,
351360
..Default::default()
352361
};
353362

354-
node.write().await.error = vec![error];
363+
node.write().unwrap().error = vec![error];
355364
Err(e)
356365
}
357366
};
358367
let end_time = Utc::now() - self.inner.lock().await.start_time;
359368

360-
node.write().await.end_time = match end_time
369+
node.write().unwrap().end_time = match end_time
361370
.num_nanoseconds()
362371
.and_then(|x| u64::try_from(x).ok())
363372
{
@@ -371,19 +380,19 @@ impl Extension for ApolloTracingExtension {
371380

372381
match parent_node {
373382
None => {
374-
let mut root_node = self.root_node.write().await;
383+
let mut root_node = self.root_node.write().unwrap();
375384
let child = &mut root_node.child;
376-
let node = node.read().await;
385+
let node = node.read().unwrap();
377386
// Can't copy or pass a ref to Protobuf
378387
// So we clone
379388
child.push(node.clone());
380389
}
381390
Some(parent) => {
382-
let nodes = self.nodes.read().await;
391+
let nodes = self.nodes.read().unwrap();
383392
let node_read = nodes.get(&parent).unwrap();
384-
let mut parent = node_read.write().await;
393+
let mut parent = node_read.write().unwrap();
385394
let child = &mut parent.child;
386-
let node = node.read().await;
395+
let node = node.read().unwrap();
387396
// Can't copy or pass a ref to Protobuf
388397
// So we clone
389398
child.push(node.clone());

Diff for: src/packages/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
pub mod uname;
1+
2+
pub mod serde_json;
3+
pub mod uname;

Diff for: src/packages/serde_json.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
#[cfg(not(target_arch = "wasm32"))]
3+
pub use serde_json::*;
4+
#[cfg(target_arch = "wasm32")]
5+
pub use serde_json_wasm::*;

0 commit comments

Comments
 (0)