Merge pull request #95 from slinkydeveloper/docs
Another round of docs fix + cleanups
This commit is contained in:
commit
e6500338c6
|
|
@ -11,6 +11,7 @@ repository = "https://github.com/cloudevents/sdk-rust"
|
|||
exclude = [
|
||||
".github/*"
|
||||
]
|
||||
categories = ["web-programming", "encoding", "data-structures"]
|
||||
|
||||
[lib]
|
||||
name = "cloudevents"
|
||||
|
|
@ -36,6 +37,7 @@ uuid = { version = "^0.8", features = ["v4", "wasm-bindgen"] }
|
|||
[dev-dependencies]
|
||||
rstest = "0.6"
|
||||
claim = "0.3.1"
|
||||
version-sync = "^0.9"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ Note: This project is WIP under active development, hence all APIs are considere
|
|||
To get started, add the dependency to `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
cloudevents-sdk = "0.2.0"
|
||||
```
|
||||
|
||||
|
|
@ -43,8 +44,7 @@ let event = EventBuilderV10::new()
|
|||
.id("aaa")
|
||||
.source(Url::parse("http://localhost").unwrap())
|
||||
.ty("example.demo")
|
||||
.build()
|
||||
.unwrap();
|
||||
.build()?;
|
||||
```
|
||||
|
||||
Checkout the examples using our integrations to learn how to send and receive events:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ description = "CloudEvents official Rust SDK - Actix-Web integration"
|
|||
documentation = "https://docs.rs/cloudevents-sdk-actix-web"
|
||||
repository = "https://github.com/cloudevents/sdk-rust"
|
||||
readme = "README.md"
|
||||
categories = ["web-programming", "encoding", "web-programming::http-server"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
|
@ -23,4 +24,5 @@ futures = "^0.3"
|
|||
[dev-dependencies]
|
||||
url = { version = "^2.1", features = ["serde"] }
|
||||
serde_json = "^1.0"
|
||||
chrono = { version = "^0.4", features = ["serde"] }
|
||||
chrono = { version = "^0.4", features = ["serde"] }
|
||||
version-sync = "^0.9"
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
//! To deserialize an HTTP request as CloudEvent:
|
||||
//!
|
||||
//! ```
|
||||
//! use cloudevents_sdk_actix_web::RequestExt;
|
||||
//! use cloudevents_sdk_actix_web::HttpRequestExt;
|
||||
//! use actix_web::{HttpRequest, web, post};
|
||||
//!
|
||||
//! #[post("/")]
|
||||
|
|
@ -41,6 +41,9 @@
|
|||
//!
|
||||
//! Check out the [cloudevents-sdk](https://docs.rs/cloudevents-sdk) docs for more details on how to use [`cloudevents::Event`]
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/cloudevents-sdk-actix-web/0.2.0")]
|
||||
#![deny(broken_intra_doc_links)]
|
||||
|
||||
#[macro_use]
|
||||
mod headers;
|
||||
mod server_request;
|
||||
|
|
@ -48,7 +51,7 @@ mod server_response;
|
|||
|
||||
pub use server_request::request_to_event;
|
||||
pub use server_request::HttpRequestDeserializer;
|
||||
pub use server_request::RequestExt;
|
||||
pub use server_request::HttpRequestExt;
|
||||
pub use server_response::event_to_response;
|
||||
pub use server_response::HttpResponseBuilderExt;
|
||||
pub use server_response::HttpResponseSerializer;
|
||||
|
|
|
|||
|
|
@ -113,8 +113,11 @@ pub async fn request_to_event(
|
|||
}
|
||||
|
||||
/// Extention Trait for [`HttpRequest`] which acts as a wrapper for the function [`request_to_event()`].
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of this crate.
|
||||
#[async_trait(?Send)]
|
||||
pub trait RequestExt {
|
||||
pub trait HttpRequestExt: private::Sealed {
|
||||
/// Convert this [`HttpRequest`] into an [`Event`].
|
||||
async fn to_event(
|
||||
&self,
|
||||
mut payload: web::Payload,
|
||||
|
|
@ -122,7 +125,7 @@ pub trait RequestExt {
|
|||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl RequestExt for HttpRequest {
|
||||
impl HttpRequestExt for HttpRequest {
|
||||
async fn to_event(
|
||||
&self,
|
||||
payload: web::Payload,
|
||||
|
|
@ -131,6 +134,12 @@ impl RequestExt for HttpRequest {
|
|||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
// Sealing the RequestExt
|
||||
pub trait Sealed {}
|
||||
impl Sealed for actix_web::HttpRequest {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -76,9 +76,12 @@ pub async fn event_to_response(
|
|||
.map_err(actix_web::error::ErrorBadRequest)
|
||||
}
|
||||
|
||||
/// Extention Trait for [`HttpResponseBuilder`] which acts as a wrapper for the function [`event_to_response()`].
|
||||
/// Extension Trait for [`HttpResponseBuilder`] which acts as a wrapper for the function [`event_to_response()`].
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of this crate.
|
||||
#[async_trait(?Send)]
|
||||
pub trait HttpResponseBuilderExt {
|
||||
pub trait HttpResponseBuilderExt: private::Sealed {
|
||||
/// Fill this [`HttpResponseBuilder`] with an [`Event`].
|
||||
async fn event(
|
||||
self,
|
||||
event: Event,
|
||||
|
|
@ -95,6 +98,12 @@ impl HttpResponseBuilderExt for HttpResponseBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
// Sealing the HttpResponseBuilderExt
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
impl Sealed for actix_web::dev::HttpResponseBuilder {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
#[test]
|
||||
fn test_readme_deps() {
|
||||
version_sync::assert_markdown_deps_updated!("README.md");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_html_root_url() {
|
||||
version_sync::assert_html_root_url_updated!("src/lib.rs");
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ description = "CloudEvents official Rust SDK - Kafka integration"
|
|||
documentation = "https://docs.rs/cloudevents-sdk-rdkafka"
|
||||
repository = "https://github.com/cloudevents/sdk-rust"
|
||||
readme = "README.md"
|
||||
categories = ["web-programming", "encoding"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
|
@ -15,11 +16,12 @@ readme = "README.md"
|
|||
bytes = "^0.5"
|
||||
cloudevents-sdk = { version = "0.2.0", path = ".." }
|
||||
lazy_static = "1.4.0"
|
||||
rdkafka = { version = "^0.24", features = ["cmake-build"] }
|
||||
|
||||
rdkafka = { version = "^0.24", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
url = { version = "^2.1" }
|
||||
serde_json = "^1.0"
|
||||
chrono = { version = "^0.4", features = ["serde"] }
|
||||
futures = "0.3.5"
|
||||
rdkafka = { version = "^0.24" }
|
||||
version-sync = "^0.9"
|
||||
|
|
|
|||
|
|
@ -134,8 +134,10 @@ pub fn record_to_event(msg: &impl Message) -> Result<Event> {
|
|||
MessageDeserializer::into_event(ConsumerRecordDeserializer::new(msg)?)
|
||||
}
|
||||
|
||||
/// Extension Trait for [`Message`] which acts as a wrapper for the function [`record_to_event()`]
|
||||
pub trait MessageExt {
|
||||
/// Extension Trait for [`Message`] which acts as a wrapper for the function [`record_to_event()`].
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of this crate.
|
||||
pub trait MessageExt: private::Sealed {
|
||||
/// Generates [`Event`] from [`BorrowedMessage`].
|
||||
fn to_event(&self) -> Result<Event>;
|
||||
}
|
||||
|
|
@ -152,6 +154,13 @@ impl MessageExt for OwnedMessage {
|
|||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
// Sealing the MessageExt
|
||||
pub trait Sealed {}
|
||||
impl Sealed for rdkafka::message::OwnedMessage {}
|
||||
impl Sealed for rdkafka::message::BorrowedMessage<'_> {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -88,7 +88,9 @@ impl StructuredSerializer<MessageRecord> for MessageRecord {
|
|||
}
|
||||
|
||||
/// Extension Trait for [`BaseRecord`] that fills the record with a [`MessageRecord`].
|
||||
pub trait BaseRecordExt<'a, K: ToBytes + ?Sized> {
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of this crate.
|
||||
pub trait BaseRecordExt<'a, K: ToBytes + ?Sized>: private::Sealed {
|
||||
/// Fill this [`BaseRecord`] with a [`MessageRecord`].
|
||||
fn message_record(
|
||||
self,
|
||||
|
|
@ -112,7 +114,9 @@ impl<'a, K: ToBytes + ?Sized> BaseRecordExt<'a, K> for BaseRecord<'a, K, Vec<u8>
|
|||
}
|
||||
|
||||
/// Extension Trait for [`FutureRecord`] that fills the record with a [`MessageRecord`].
|
||||
pub trait FutureRecordExt<'a, K: ToBytes + ?Sized> {
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of this crate.
|
||||
pub trait FutureRecordExt<'a, K: ToBytes + ?Sized>: private::Sealed {
|
||||
/// Fill this [`FutureRecord`] with a [`MessageRecord`].
|
||||
fn message_record(self, message_record: &'a MessageRecord) -> FutureRecord<'a, K, Vec<u8>>;
|
||||
}
|
||||
|
|
@ -128,3 +132,16 @@ impl<'a, K: ToBytes + ?Sized> FutureRecordExt<'a, K> for FutureRecord<'a, K, Vec
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
// Sealing the FutureRecordExt and BaseRecordExt
|
||||
pub trait Sealed {}
|
||||
impl<K: rdkafka::message::ToBytes + ?Sized, V: rdkafka::message::ToBytes> Sealed
|
||||
for rdkafka::producer::FutureRecord<'_, K, V>
|
||||
{
|
||||
}
|
||||
impl<K: rdkafka::message::ToBytes + ?Sized, V: rdkafka::message::ToBytes> Sealed
|
||||
for rdkafka::producer::BaseRecord<'_, K, V>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@
|
|||
//! use rdkafka::util::Timeout;
|
||||
//! use cloudevents_sdk_rdkafka::{MessageRecord, FutureRecordExt};
|
||||
//!
|
||||
//! # async fn produce(producer: &FutureProducer, event: Event) {
|
||||
//! let message_record = MessageRecord::from_event(event)
|
||||
//! .expect("error while serializing the event");
|
||||
//! # async fn produce(producer: &FutureProducer, event: Event) -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! let message_record = MessageRecord::from_event(event)?;
|
||||
//!
|
||||
//! producer.send(
|
||||
//! FutureRecord::to("topic")
|
||||
|
|
@ -20,7 +19,7 @@
|
|||
//! .message_record(&message_record),
|
||||
//! Timeout::Never
|
||||
//! ).await;
|
||||
//!
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -32,22 +31,26 @@
|
|||
//! use cloudevents_sdk_rdkafka::MessageExt;
|
||||
//! use futures::StreamExt;
|
||||
//!
|
||||
//! # async fn consume(consumer: StreamConsumer<DefaultConsumerContext>) {
|
||||
//! # async fn consume(consumer: StreamConsumer<DefaultConsumerContext>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! let mut message_stream = consumer.start();
|
||||
//!
|
||||
//! while let Some(message) = message_stream.next().await {
|
||||
//! match message {
|
||||
//! Err(e) => println!("Kafka error: {}", e),
|
||||
//! Ok(m) => {
|
||||
//! let event = m.to_event().expect("error while deserializing record to CloudEvent");
|
||||
//! println!("Received Event: {:#?}", event);
|
||||
//! consumer.commit_message(&m, CommitMode::Async).unwrap();
|
||||
//! let event = m.to_event()?;
|
||||
//! println!("Received Event: {}", event);
|
||||
//! consumer.commit_message(&m, CommitMode::Async)?;
|
||||
//! }
|
||||
//! };
|
||||
//! }
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/cloudevents-sdk-rdkafka/0.2.0")]
|
||||
#![deny(broken_intra_doc_links)]
|
||||
|
||||
#[macro_use]
|
||||
mod headers;
|
||||
mod kafka_consumer_record;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
#[test]
|
||||
fn test_readme_deps() {
|
||||
version_sync::assert_markdown_deps_updated!("README.md");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_html_root_url() {
|
||||
version_sync::assert_html_root_url_updated!("src/lib.rs");
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ description = "CloudEvents official Rust SDK - Reqwest integration"
|
|||
documentation = "https://docs.rs/cloudevents-sdk-reqwest"
|
||||
repository = "https://github.com/cloudevents/sdk-rust"
|
||||
readme = "README.md"
|
||||
categories = ["web-programming", "encoding", "web-programming::http-client"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
|
@ -27,4 +28,5 @@ mockito = "0.25.1"
|
|||
tokio = { version = "^0.2", features = ["full"] }
|
||||
url = { version = "^2.1" }
|
||||
serde_json = "^1.0"
|
||||
chrono = { version = "^0.4", features = ["serde"] }
|
||||
chrono = { version = "^0.4", features = ["serde"] }
|
||||
version-sync = "^0.9"
|
||||
|
|
@ -62,13 +62,16 @@ impl StructuredSerializer<RequestBuilder> for RequestSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
/// Method to fill a [`RequestBuilder`] with an [`Event`]
|
||||
/// Method to fill a [`RequestBuilder`] with an [`Event`].
|
||||
pub fn event_to_request(event: Event, request_builder: RequestBuilder) -> Result<RequestBuilder> {
|
||||
BinaryDeserializer::deserialize_binary(event, RequestSerializer::new(request_builder))
|
||||
}
|
||||
|
||||
/// Extention Trait for [`RequestBuilder`] which acts as a wrapper for the function [`event_to_request()`]
|
||||
pub trait RequestBuilderExt {
|
||||
/// Extension Trait for [`RequestBuilder`] which acts as a wrapper for the function [`event_to_request()`].
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of this crate.
|
||||
pub trait RequestBuilderExt: private::Sealed {
|
||||
/// Write in this [`RequestBuilder`] the provided [`Event`]. Similar to invoking [`Event`].
|
||||
fn event(self, event: Event) -> Result<RequestBuilder>;
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +81,12 @@ impl RequestBuilderExt for RequestBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
// Sealing the RequestBuilderExt
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
impl Sealed for reqwest::RequestBuilder {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -109,8 +109,11 @@ pub async fn response_to_event(res: Response) -> Result<Event> {
|
|||
}
|
||||
|
||||
/// Extension Trait for [`Response`] which acts as a wrapper for the function [`response_to_event()`].
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of this crate.
|
||||
#[async_trait(?Send)]
|
||||
pub trait ResponseExt {
|
||||
pub trait ResponseExt: private::Sealed {
|
||||
/// Convert this [`Response`] to [`Event`].
|
||||
async fn into_event(self) -> Result<Event>;
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +124,12 @@ impl ResponseExt for Response {
|
|||
}
|
||||
}
|
||||
|
||||
// Sealing the ResponseExt
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
impl Sealed for reqwest::Response {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
//! use cloudevents::{EventBuilderV10, EventBuilder};
|
||||
//! use serde_json::json;
|
||||
//!
|
||||
//! # async fn example() {
|
||||
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! let client = reqwest::Client::new();
|
||||
//!
|
||||
//! // Prepare the event to send
|
||||
|
|
@ -14,23 +14,23 @@
|
|||
//! .ty("example.test")
|
||||
//! .source("http://localhost/")
|
||||
//! .data("application/json", json!({"hello": "world"}))
|
||||
//! .build()
|
||||
//! .expect("No error while building the event");
|
||||
//! .build()?;
|
||||
//!
|
||||
//! // Send request
|
||||
//! let response = client.post("http://localhost")
|
||||
//! .event(event_to_send)
|
||||
//! .expect("Error while serializing the event")
|
||||
//! .send().await
|
||||
//! .expect("Error while sending the request");
|
||||
//! .event(event_to_send)?
|
||||
//! .send().await?;
|
||||
//! // Parse response as event
|
||||
//! let received_event = response
|
||||
//! .into_event().await
|
||||
//! .expect("Error while deserializing the response");
|
||||
//! .into_event().await?;
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! Check out the [cloudevents-sdk](https://docs.rs/cloudevents-sdk) docs for more details on how to use [`cloudevents::Event`]
|
||||
//! Check out the [cloudevents-sdk](https://docs.rs/cloudevents-sdk) docs for more details on how to use [`cloudevents::Event`].
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/cloudevents-sdk-reqwest/0.2.0")]
|
||||
#![deny(broken_intra_doc_links)]
|
||||
|
||||
#[macro_use]
|
||||
mod headers;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
#[test]
|
||||
fn test_readme_deps() {
|
||||
version_sync::assert_markdown_deps_updated!("README.md");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_html_root_url() {
|
||||
version_sync::assert_html_root_url_updated!("src/lib.rs");
|
||||
}
|
||||
|
|
@ -7,9 +7,9 @@ edition = "2018"
|
|||
[dependencies]
|
||||
cloudevents-sdk = { path = "../.." }
|
||||
cloudevents-sdk-actix-web = { path = "../../cloudevents-sdk-actix-web" }
|
||||
actix-web = "2"
|
||||
actix-web = "^3"
|
||||
actix-rt = "1"
|
||||
actix-cors = "^0.2.0"
|
||||
actix-cors = "^0.5"
|
||||
lazy_static = "1.4.0"
|
||||
bytes = "^0.5"
|
||||
futures = "^0.3"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use actix_web::{get, post, web, App, HttpRequest, HttpResponse, HttpServer};
|
||||
use cloudevents::{EventBuilder, EventBuilderV10};
|
||||
use cloudevents_sdk_actix_web::{HttpResponseBuilderExt, RequestExt};
|
||||
use cloudevents_sdk_actix_web::{HttpResponseBuilderExt, HttpRequestExt};
|
||||
use serde_json::json;
|
||||
|
||||
#[post("/")]
|
||||
|
|
@ -36,7 +36,7 @@ async fn main() -> std::io::Result<()> {
|
|||
HttpServer::new(|| {
|
||||
App::new()
|
||||
.wrap(actix_web::middleware::Logger::default())
|
||||
.wrap(actix_cors::Cors::new().finish())
|
||||
.wrap(actix_cors::Cors::permissive())
|
||||
.service(post_event)
|
||||
.service(get_event)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,5 +19,7 @@ tokio = { version = "^0.2", features = ["full"] }
|
|||
clap = "2.33.1"
|
||||
|
||||
[dependencies.rdkafka]
|
||||
version = "~0.23"
|
||||
features = ["ssl", "sasl"]
|
||||
version = "^0.24"
|
||||
features = ["cmake-build"]
|
||||
|
||||
[workspace]
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use rdkafka::config::{ClientConfig, RDKafkaLogLevel};
|
|||
use rdkafka::consumer::stream_consumer::StreamConsumer;
|
||||
use rdkafka::consumer::{CommitMode, Consumer, DefaultConsumerContext};
|
||||
use rdkafka::producer::{FutureProducer, FutureRecord};
|
||||
use std::time::Duration;
|
||||
|
||||
// You need a running Kafka cluster to try out this example.
|
||||
// With docker: docker run --rm --net=host -e ADV_HOST=localhost -e SAMPLEDATA=0 lensesio/fast-data-dev
|
||||
|
|
@ -78,7 +79,7 @@ async fn produce(brokers: &str, topic_name: &str) {
|
|||
FutureRecord::to(topic_name)
|
||||
.message_record(&message_record)
|
||||
.key(&format!("Key {}", i)),
|
||||
0,
|
||||
Duration::from_secs(10),
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use serde::Serializer;
|
|||
use std::fmt;
|
||||
use url::Url;
|
||||
|
||||
/// Value of a CloudEvent attribute
|
||||
/// Enum representing a borrowed value of a CloudEvent attribute.
|
||||
/// This represents the types defined in the [CloudEvent spec type system](https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system)
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum AttributeValue<'a> {
|
||||
SpecVersion(SpecVersion),
|
||||
|
|
@ -230,20 +231,20 @@ impl AttributesWriter for Attributes {
|
|||
}
|
||||
|
||||
impl Attributes {
|
||||
pub fn into_v10(self) -> Self {
|
||||
pub(crate) fn into_v10(self) -> Self {
|
||||
match self {
|
||||
Attributes::V03(v03) => Attributes::V10(v03.into_v10()),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
pub fn into_v03(self) -> Self {
|
||||
pub(crate) fn into_v03(self) -> Self {
|
||||
match self {
|
||||
Attributes::V10(v10) => Attributes::V03(v10.into_v03()),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&str, AttributeValue)> {
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = (&str, AttributeValue)> {
|
||||
match self {
|
||||
Attributes::V03(a) => AttributesIter::IterV03(a.into_iter()),
|
||||
Attributes::V10(a) => AttributesIter::IterV10(a.into_iter()),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use serde::export::Formatter;
|
||||
use serde_json::Value;
|
||||
use std::convert::{Into, TryFrom};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
|
||||
/// Event [data attribute](https://github.com/cloudevents/spec/blob/master/spec.md#event-data) representation
|
||||
|
|
@ -14,40 +14,6 @@ pub enum Data {
|
|||
Json(serde_json::Value),
|
||||
}
|
||||
|
||||
impl Data {
|
||||
/// Create a [`Data`] from a [`Into<Vec<u8>>`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use cloudevents::event::Data;
|
||||
///
|
||||
/// let value = Data::from_base64(b"dmFsdWU=").unwrap();
|
||||
/// assert_eq!(value, Data::Binary(base64::decode("dmFsdWU=").unwrap()));
|
||||
/// ```
|
||||
///
|
||||
/// [`AsRef<[u8]>`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html
|
||||
/// [`Data`]: enum.Data.html
|
||||
pub fn from_base64<I>(i: I) -> Result<Self, base64::DecodeError>
|
||||
where
|
||||
I: AsRef<[u8]>,
|
||||
{
|
||||
Ok(base64::decode(&i)?.into())
|
||||
}
|
||||
|
||||
pub fn from_binary<I>(content_type: Option<&str>, i: I) -> Result<Self, serde_json::Error>
|
||||
where
|
||||
I: AsRef<[u8]>,
|
||||
{
|
||||
let is_json = is_json_content_type(content_type.unwrap_or("application/json"));
|
||||
if is_json {
|
||||
serde_json::from_slice::<serde_json::Value>(i.as_ref()).map(Data::Json)
|
||||
} else {
|
||||
Ok(Data::Binary(i.as_ref().to_vec()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_json_content_type(ct: &str) -> bool {
|
||||
ct.starts_with("application/json") || ct.starts_with("text/json") || ct.ends_with("+json")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ use std::fmt;
|
|||
#[serde(untagged)]
|
||||
/// Represents all the possible [CloudEvents extension](https://github.com/cloudevents/spec/blob/master/spec.md#extension-context-attributes) values
|
||||
pub enum ExtensionValue {
|
||||
/// Represents a [`String`](std::string::String) value.
|
||||
/// Represents a [`String`] value.
|
||||
String(String),
|
||||
/// Represents a [`bool`](bool) value.
|
||||
/// Represents a [`bool`] value.
|
||||
Boolean(bool),
|
||||
/// Represents an integer [`i64`](i64) value.
|
||||
/// Represents an integer [`i64`] value.
|
||||
Integer(i64),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Provides [`Event`] data structure, [`EventBuilder`] and other facilities to work with [`Event`].
|
||||
|
||||
mod attributes;
|
||||
mod builder;
|
||||
mod data;
|
||||
|
|
|
|||
|
|
@ -5,14 +5,18 @@ use std::fmt;
|
|||
|
||||
pub(crate) const SPEC_VERSIONS: [&'static str; 2] = ["0.3", "1.0"];
|
||||
|
||||
/// CloudEvent specification version
|
||||
/// CloudEvent specification version.
|
||||
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
|
||||
pub enum SpecVersion {
|
||||
/// CloudEvents v0.3
|
||||
V03,
|
||||
/// CloudEvents v1.0
|
||||
V10,
|
||||
}
|
||||
|
||||
impl SpecVersion {
|
||||
/// Returns the string representation of [`SpecVersion`].
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
SpecVersion::V03 => "0.3",
|
||||
|
|
@ -28,7 +32,7 @@ impl SpecVersion {
|
|||
SpecVersion::V10 => &v10::ATTRIBUTE_NAMES,
|
||||
}
|
||||
}
|
||||
/// Get all attribute names for all Spec versions.
|
||||
/// Get all attribute names for all specification versions.
|
||||
/// Note that the result iterator could contain duplicate entries.
|
||||
pub fn all_attribute_names() -> impl Iterator<Item = &'static str> {
|
||||
vec![SpecVersion::V03, SpecVersion::V10]
|
||||
|
|
|
|||
30
src/lib.rs
30
src/lib.rs
|
|
@ -1,8 +1,10 @@
|
|||
//! This crate implements the [CloudEvents](https://cloudevents.io/) Spec for Rust.
|
||||
//!
|
||||
//! ```
|
||||
//! # use std::error::Error;
|
||||
//! # fn main() -> Result<(), Box<dyn Error>> {
|
||||
//! use cloudevents::{EventBuilder, AttributesReader, EventBuilderV10};
|
||||
//! use chrono::Utc;
|
||||
//! use chrono::{Utc, DateTime};
|
||||
//! use url::Url;
|
||||
//!
|
||||
//! let event = EventBuilderV10::new()
|
||||
|
|
@ -10,27 +12,35 @@
|
|||
//! .source("http://localhost:8080")
|
||||
//! .ty("example.demo")
|
||||
//! .time(Utc::now())
|
||||
//! .build()
|
||||
//! .unwrap();
|
||||
//! .build()?;
|
||||
//!
|
||||
//! println!("CloudEvent Id: {}", event.id());
|
||||
//! println!("CloudEvent Time: {}", event.time().unwrap());
|
||||
//! match event.time() {
|
||||
//! Some(t) => println!("CloudEvent Time: {}", t),
|
||||
//! None => println!("CloudEvent Time: None")
|
||||
//! }
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! This crate includes:
|
||||
//!
|
||||
//! * The [`Event`] data structure, to represent CloudEvent (version 1.0 and 0.3)
|
||||
//! * The [`EventBuilder`] trait and implementations, to create [`Event`] instances
|
||||
//! * The implementation of [`serde::Serialize`] and [`serde::Deserialize`] for [`Event`] to serialize/deserialize CloudEvents to/from JSON
|
||||
//! * Traits and utilities in [`message`] to implement Protocol Bindings
|
||||
//!
|
||||
//! If you're looking for Protocol Binding implementations, look at crates:
|
||||
//!
|
||||
//! * [cloudevents-sdk-actix-web](https://docs.rs/cloudevents-sdk-actix-web): Integration with [Actix Web](https://github.com/actix/actix-web)
|
||||
//! * [cloudevents-sdk-reqwest](https://docs.rs/cloudevents-sdk-reqwest): Integration with [reqwest](https://github.com/seanmonstar/reqwest)
|
||||
//! * [cloudevents-sdk-rdkafka](https://docs.rs/cloudevents-sdk-rdkafka): Integration with [rdkafka](https://fede1024.github.io/rust-rdkafka)
|
||||
//!
|
||||
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate serde_value;
|
||||
extern crate snafu;
|
||||
#![doc(html_root_url = "https://docs.rs/cloudevents-sdk/0.2.0")]
|
||||
#![deny(broken_intra_doc_links)]
|
||||
|
||||
/// Provides [`Event`] data structure, [`EventBuilder`] and other facilities to work with [`Event`]
|
||||
pub mod event;
|
||||
/// Provides facilities to implement Protocol Bindings
|
||||
pub mod message;
|
||||
|
||||
pub use event::Data;
|
||||
|
|
|
|||
|
|
@ -2,46 +2,46 @@ use super::{BinarySerializer, Encoding, Error, Result, StructuredSerializer};
|
|||
use crate::event::{EventBinarySerializer, EventStructuredSerializer};
|
||||
use crate::Event;
|
||||
|
||||
/// Deserializer trait for a Message that can be encoded as structured mode
|
||||
/// Deserializer trait for a Message that can be encoded as structured mode.
|
||||
pub trait StructuredDeserializer
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
/// Deserialize the message to [`StructuredSerializer`]
|
||||
/// Deserialize the message to [`StructuredSerializer`].
|
||||
fn deserialize_structured<R: Sized, V: StructuredSerializer<R>>(
|
||||
self,
|
||||
serializer: V,
|
||||
) -> Result<R>;
|
||||
|
||||
/// Convert this Message to [`Event`]
|
||||
/// Convert this Message to [`Event`].
|
||||
fn into_event(self) -> Result<Event> {
|
||||
self.deserialize_structured(EventStructuredSerializer {})
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializer trait for a Message that can be encoded as binary mode
|
||||
/// Deserializer trait for a Message that can be encoded as binary mode.
|
||||
pub trait BinaryDeserializer
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
/// Deserialize the message to [`BinarySerializer`]
|
||||
/// Deserialize the message to [`BinarySerializer`].
|
||||
fn deserialize_binary<R: Sized, V: BinarySerializer<R>>(self, serializer: V) -> Result<R>;
|
||||
|
||||
/// Convert this Message to [`Event`]
|
||||
/// Convert this Message to [`Event`].
|
||||
fn into_event(self) -> Result<Event> {
|
||||
self.deserialize_binary(EventBinarySerializer::new())
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializer trait for a Message that can be encoded both in structured mode or binary mode
|
||||
/// Deserializer trait for a Message that can be encoded both in structured mode or binary mode.
|
||||
pub trait MessageDeserializer
|
||||
where
|
||||
Self: StructuredDeserializer + BinaryDeserializer + Sized,
|
||||
{
|
||||
/// Get this message [`Encoding`]
|
||||
/// Get this message [`Encoding`].
|
||||
fn encoding(&self) -> Encoding;
|
||||
|
||||
/// Convert this Message to [`Event`]
|
||||
/// Convert this Message to [`Event`].
|
||||
fn into_event(self) -> Result<Event> {
|
||||
match self.encoding() {
|
||||
Encoding::BINARY => BinaryDeserializer::into_event(self),
|
||||
|
|
@ -50,7 +50,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Deserialize the message to [`BinarySerializer`]
|
||||
/// Deserialize the message to [`BinarySerializer`].
|
||||
fn deserialize_to_binary<R: Sized, T: BinarySerializer<R>>(self, serializer: T) -> Result<R> {
|
||||
if self.encoding() == Encoding::BINARY {
|
||||
return self.deserialize_binary(serializer);
|
||||
|
|
@ -59,7 +59,7 @@ where
|
|||
return MessageDeserializer::into_event(self)?.deserialize_binary(serializer);
|
||||
}
|
||||
|
||||
/// Deserialize the message to [`StructuredSerializer`]
|
||||
/// Deserialize the message to [`StructuredSerializer`].
|
||||
fn deserialize_to_structured<R: Sized, T: StructuredSerializer<R>>(
|
||||
self,
|
||||
serializer: T,
|
||||
|
|
@ -71,8 +71,8 @@ where
|
|||
return MessageDeserializer::into_event(self)?.deserialize_structured(serializer);
|
||||
}
|
||||
|
||||
/// Deserialize the message to a serializer, depending on the message encoding
|
||||
/// You can use this method to transcode this message directly to another serializer, without going through [`Event`]
|
||||
/// Deserialize the message to a serializer, depending on the message encoding.
|
||||
/// You can use this method to transcode this message directly to another serializer, without going through [`Event`].
|
||||
fn deserialize_to<R: Sized, T: BinarySerializer<R> + StructuredSerializer<R>>(
|
||||
self,
|
||||
serializer: T,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
/// Represents one of the possible [message encodings/modes](https://github.com/cloudevents/spec/blob/v1.0/spec.md#message)
|
||||
/// Represents one of the possible [message encodings/modes](https://github.com/cloudevents/spec/blob/v1.0/spec.md#message).
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum Encoding {
|
||||
/// Represents the _structured-mode message_.
|
||||
STRUCTURED,
|
||||
/// Represents the _binary-mode message_.
|
||||
BINARY,
|
||||
/// Represents a non-CloudEvent or a malformed CloudEvent that cannot be recognized by the SDK.
|
||||
UNKNOWN,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
//! Provides facilities to implement Protocol Bindings.
|
||||
//!
|
||||
//! Note: these APIs should be considered unstable and subject to changes.
|
||||
|
||||
mod deserializer;
|
||||
mod encoding;
|
||||
mod error;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use super::{MessageAttributeValue, Result};
|
||||
use crate::event::SpecVersion;
|
||||
|
||||
/// Serializer for structured mode messages
|
||||
/// Serializer for structured mode messages.
|
||||
pub trait StructuredSerializer<RETURN: Sized> {
|
||||
fn set_structured_event(self, bytes: Vec<u8>) -> Result<RETURN>;
|
||||
}
|
||||
|
||||
/// Serializer for binary mode messages
|
||||
/// Serializer for binary mode messages.
|
||||
pub trait BinarySerializer<RETURN: Sized>
|
||||
where
|
||||
Self: Sized,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use crate::event::ExtensionValue;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::export::Formatter;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
use url::Url;
|
||||
|
||||
/// Union type representing a [CloudEvent context attribute type](https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system)
|
||||
/// Union type representing a [CloudEvent context attribute type](https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system).
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum MessageAttributeValue {
|
||||
Boolean(bool),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
#[test]
|
||||
fn test_readme_deps() {
|
||||
version_sync::assert_markdown_deps_updated!("README.md");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_html_root_url() {
|
||||
version_sync::assert_html_root_url_updated!("src/lib.rs");
|
||||
}
|
||||
Loading…
Reference in New Issue