├── rustfmt.toml ├── rsocket-test ├── README.md ├── tests │ ├── test_routing_metadata.rs │ ├── test_mimes.rs │ ├── test_composite_metadata.rs │ ├── test_messaging.rs │ ├── test_frames.rs │ └── test_clients.rs └── Cargo.toml ├── .gitignore ├── rsocket ├── src │ ├── macros │ │ ├── mod.rs │ │ ├── routing.rs │ │ └── composite.rs │ ├── payload │ │ ├── mod.rs │ │ ├── misc.rs │ │ ├── normal.rs │ │ └── setup.rs │ ├── core │ │ ├── mod.rs │ │ ├── factory.rs │ │ └── server.rs │ ├── transport │ │ ├── mod.rs │ │ ├── spi.rs │ │ ├── misc.rs │ │ └── fragmentation.rs │ ├── extension │ │ ├── mod.rs │ │ ├── routing.rs │ │ ├── composite.rs │ │ └── mime.rs │ ├── prelude.rs │ ├── runtime │ │ └── mod.rs │ ├── frame │ │ ├── cancel.rs │ │ ├── version.rs │ │ ├── utils.rs │ │ ├── request_n.rs │ │ ├── resume_ok.rs │ │ ├── metadata_push.rs │ │ ├── error.rs │ │ ├── keepalive.rs │ │ ├── payload.rs │ │ ├── request_fnf.rs │ │ ├── request_response.rs │ │ ├── lease.rs │ │ ├── request_stream.rs │ │ ├── request_channel.rs │ │ ├── resume.rs │ │ ├── setup.rs │ │ └── mod.rs │ ├── spi.rs │ ├── error.rs │ ├── lib.rs │ └── utils.rs ├── Cargo.toml └── README.md ├── examples ├── tls │ ├── foobar.com.p12 │ ├── README.md │ ├── server.rs │ ├── client.rs │ ├── foobar.com.pem │ └── foobar.com-key.pem ├── cli.rs ├── proxy.rs ├── Cargo.toml └── qps.rs ├── rsocket-messaging ├── README.md ├── src │ ├── lib.rs │ └── misc.rs └── Cargo.toml ├── Cargo.toml ├── rsocket-transport-tcp ├── src │ ├── client │ │ ├── mod.rs │ │ ├── tls.rs │ │ ├── uds.rs │ │ └── tcp.rs │ ├── server │ │ ├── mod.rs │ │ ├── tls.rs │ │ ├── tcp.rs │ │ └── uds.rs │ ├── connection │ │ ├── mod.rs │ │ ├── tcp.rs │ │ ├── uds.rs │ │ ├── tls.rs │ │ └── codec.rs │ ├── misc.rs │ └── lib.rs ├── Cargo.toml └── README.md ├── .github ├── dependabot.yml └── workflows │ ├── rust.yml │ └── linelint.yml ├── rsocket-transport-wasm ├── README.md ├── src │ ├── lib.rs │ ├── connection.rs │ ├── misc.rs │ └── client.rs └── Cargo.toml ├── justfile ├── .linelint.yml ├── rsocket-transport-websocket ├── Cargo.toml ├── src │ ├── lib.rs │ ├── server.rs │ ├── connection.rs │ └── client.rs └── README.md ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── cliff.toml └── README.md /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2021" 2 | -------------------------------------------------------------------------------- /rsocket-test/README.md: -------------------------------------------------------------------------------- 1 | # RSocket Tests 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | .vscode/ 5 | /flamegraph.svg 6 | -------------------------------------------------------------------------------- /rsocket/src/macros/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod composite; 3 | #[macro_use] 4 | mod routing; 5 | -------------------------------------------------------------------------------- /examples/tls/foobar.com.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rsocket/rsocket-rust/HEAD/examples/tls/foobar.com.p12 -------------------------------------------------------------------------------- /rsocket/src/payload/mod.rs: -------------------------------------------------------------------------------- 1 | mod misc; 2 | mod normal; 3 | mod setup; 4 | 5 | pub use normal::{Payload, PayloadBuilder}; 6 | pub use setup::{SetupPayload, SetupPayloadBuilder}; 7 | -------------------------------------------------------------------------------- /rsocket/src/core/mod.rs: -------------------------------------------------------------------------------- 1 | mod client; 2 | mod factory; 3 | mod server; 4 | 5 | pub use client::{Client, ClientBuilder}; 6 | pub use factory::RSocketFactory; 7 | pub use server::ServerBuilder; 8 | -------------------------------------------------------------------------------- /rsocket-messaging/README.md: -------------------------------------------------------------------------------- 1 | # RSocket Messaging 2 | 3 | Communicate with Spring RSocket Messaging. 4 | 5 | ## Example 6 | 7 | Here's a good example: [https://github.com/feuyeux/kio](https://github.com/feuyeux/kio). 8 | -------------------------------------------------------------------------------- /rsocket-messaging/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::upper_case_acronyms)] 2 | 3 | mod misc; 4 | mod requester; 5 | 6 | pub use misc::{cbor, json, SerDe}; 7 | pub use requester::{RequestSpec, Requester, RequesterBuilder}; 8 | -------------------------------------------------------------------------------- /rsocket/src/transport/mod.rs: -------------------------------------------------------------------------------- 1 | mod fragmentation; 2 | mod misc; 3 | mod socket; 4 | mod spi; 5 | 6 | pub(crate) use fragmentation::{Joiner, Splitter, MIN_MTU}; 7 | pub(crate) use socket::{ClientRequester,DuplexSocket}; 8 | pub use spi::*; 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "rsocket", 5 | "rsocket-transport-tcp", 6 | "rsocket-transport-websocket", 7 | "rsocket-transport-wasm", 8 | "rsocket-messaging", 9 | "examples", 10 | "rsocket-test", 11 | ] 12 | -------------------------------------------------------------------------------- /rsocket/src/payload/misc.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | 3 | #[inline] 4 | pub(crate) fn bytes_to_utf8(input: &Option) -> Option<&str> { 5 | match input { 6 | Some(b) => std::str::from_utf8(b).ok(), 7 | None => None, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /rsocket/src/extension/mod.rs: -------------------------------------------------------------------------------- 1 | mod composite; 2 | mod mime; 3 | mod routing; 4 | 5 | pub use composite::{CompositeMetadata, CompositeMetadataBuilder, CompositeMetadataEntry}; 6 | pub use mime::MimeType; 7 | pub use routing::{RoutingMetadata, RoutingMetadataBuilder}; 8 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/client/mod.rs: -------------------------------------------------------------------------------- 1 | mod tcp; 2 | mod uds; 3 | 4 | pub use tcp::TcpClientTransport; 5 | pub use uds::UnixClientTransport; 6 | 7 | cfg_if! { 8 | if #[cfg(feature = "tls")] { 9 | mod tls; 10 | pub use tls::TlsClientTransport; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/server/mod.rs: -------------------------------------------------------------------------------- 1 | mod tcp; 2 | mod uds; 3 | 4 | pub use tcp::TcpServerTransport; 5 | pub use uds::UnixServerTransport; 6 | 7 | cfg_if! { 8 | if #[cfg(feature = "tls")] { 9 | mod tls; 10 | pub use tls::TlsServerTransport; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/connection/mod.rs: -------------------------------------------------------------------------------- 1 | mod codec; 2 | mod tcp; 3 | mod uds; 4 | 5 | pub use tcp::TcpConnection; 6 | pub use uds::UnixConnection; 7 | 8 | cfg_if! { 9 | if #[cfg(feature = "tls")] { 10 | mod tls; 11 | pub use tls::TlsConnection; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rsocket/src/prelude.rs: -------------------------------------------------------------------------------- 1 | pub use futures::{Sink, SinkExt, Stream, StreamExt}; 2 | 3 | pub use crate::core::RSocketFactory; 4 | pub use crate::payload::{Payload, PayloadBuilder, SetupPayload, SetupPayloadBuilder}; 5 | pub use crate::spi::*; 6 | pub use crate::transport::{ServerTransport, Transport}; 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: cargo 7 | directory: "/" 8 | schedule: 9 | interval: daily 10 | time: "12:00" 11 | open-pull-requests-limit: 10 12 | -------------------------------------------------------------------------------- /rsocket-transport-wasm/README.md: -------------------------------------------------------------------------------- 1 | # RSocket Transport For WebAssembly (Client-Side) 2 | 3 | ## Example 4 | 5 | See: [https://github.com/jjeffcaii/rsocket-rust-wasm-example](https://github.com/jjeffcaii/rsocket-rust-wasm-example)) 6 | 7 | ## TODO 8 | 9 | - [ ] MetadataPush 10 | - [x] FireAndForget 11 | - [x] RequestResponse 12 | - [ ] RequestStream 13 | - [ ] RequestChannel 14 | -------------------------------------------------------------------------------- /rsocket/src/runtime/mod.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | 3 | pub fn spawn(task: F) 4 | where 5 | F: Send + Future + 'static, 6 | { 7 | cfg_if! { 8 | if #[cfg(not(target_arch = "wasm32"))] { 9 | tokio::spawn(task); 10 | } else { 11 | use wasm_bindgen_futures::spawn_local; 12 | spawn_local(task); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rsocket-transport-wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::type_complexity)] 2 | #![allow(clippy::unused_unit)] 3 | #![allow(clippy::from_over_into)] 4 | 5 | #[macro_use] 6 | extern crate serde_derive; 7 | 8 | mod client; 9 | mod connection; 10 | mod misc; 11 | 12 | pub use client::WebsocketClientTransport; 13 | pub use connection::WebsocketConnection; 14 | pub use misc::{connect, new_payload, JsClient, JsPayload}; 15 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | alias b := bench 2 | alias e := echo 3 | alias t := test 4 | 5 | build: 6 | @cargo build 7 | test: 8 | @cargo test -- --nocapture 9 | lint: 10 | @cargo clippy 11 | fmt: 12 | @cargo fmt 13 | echo: 14 | @RUST_LOG=release cargo run --release --example echo -- serve tcp://127.0.0.1:7878 15 | bench: 16 | @RUST_LOG=info cargo run --release --example qps -- -c 1000000 -s 1024 --pprof tcp://127.0.0.1:7878 17 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | -------------------------------------------------------------------------------- /examples/tls/README.md: -------------------------------------------------------------------------------- 1 | # TLS Example 2 | 3 | ## Generate Certificates and Keys 4 | 5 | 1. Install [mkcert](https://github.com/FiloSottile/mkcert) 6 | 2. Generate keys: `mkcert foobar.com` 7 | 3. Generate `p12` file: `openssl pkcs12 -export -out foobar.com.p12 -inkey foobar.com-key.pem -in foobar.com.pem -password pass:foobar` 8 | 9 | ## Run 10 | 11 | 1. Start TLS Server: `RUST_LOG=info cargo run --example tls-server` 12 | 2. Start TLS Client: `RUST_LOG=info cargo run --example tls-client` 13 | -------------------------------------------------------------------------------- /rsocket/src/frame/cancel.rs: -------------------------------------------------------------------------------- 1 | use super::{Body, Frame}; 2 | 3 | #[derive(Debug, Eq, PartialEq)] 4 | pub struct Cancel {} 5 | 6 | pub struct CancelBuilder { 7 | stream_id: u32, 8 | flag: u16, 9 | } 10 | 11 | impl CancelBuilder { 12 | pub fn build(self) -> Frame { 13 | Frame::new(self.stream_id, Body::Cancel(), self.flag) 14 | } 15 | } 16 | 17 | impl Cancel { 18 | pub fn builder(stream_id: u32, flag: u16) -> CancelBuilder { 19 | CancelBuilder { stream_id, flag } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.linelint.yml: -------------------------------------------------------------------------------- 1 | # 'true' will fix files 2 | autofix: true 3 | 4 | # list of paths to ignore, uses gitignore syntaxes (executes before any rule) 5 | ignore: 6 | - .git/ 7 | 8 | rules: 9 | # checks if file ends in a newline character 10 | end-of-file: 11 | # set to true to enable this rule 12 | enable: true 13 | 14 | # set to true to disable autofix (if enabled globally) 15 | disable-autofix: false 16 | 17 | # if true also checks if file ends in a single newline character 18 | single-new-line: true 19 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/misc.rs: -------------------------------------------------------------------------------- 1 | pub(crate) fn parse_uds_addr(addr: impl AsRef) -> String { 2 | let addr = addr.as_ref(); 3 | if addr.starts_with("unix://") || addr.starts_with("UNIX://") { 4 | addr.chars().skip(7).collect::() 5 | } else { 6 | addr.to_owned() 7 | } 8 | } 9 | 10 | pub(crate) fn parse_tcp_addr(addr: impl AsRef) -> String { 11 | let addr = addr.as_ref(); 12 | if addr.starts_with("tcp://") || addr.starts_with("TCP://") { 13 | addr.chars().skip(6).collect::() 14 | } else { 15 | addr.to_owned() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /rsocket/src/macros/routing.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! tags { 3 | ($($v:expr),+) => { 4 | { 5 | let mut b = $crate::extension::RoutingMetadata::builder(); 6 | $( 7 | b = b.push_str($v); 8 | )* 9 | b.build() 10 | } 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | 18 | #[test] 19 | fn test_routing() { 20 | let t = tags!("a", "b", "c"); 21 | let tags = t.get_tags(); 22 | println!("{:?}", tags); 23 | assert_eq!("a,b,c", t.get_tags().join(",")) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::type_complexity)] 2 | 3 | #[macro_use] 4 | extern crate log; 5 | #[macro_use] 6 | extern crate cfg_if; 7 | 8 | mod client; 9 | mod connection; 10 | mod misc; 11 | mod server; 12 | 13 | pub use client::{TcpClientTransport, UnixClientTransport}; 14 | pub use connection::{TcpConnection, UnixConnection}; 15 | pub use server::{TcpServerTransport, UnixServerTransport}; 16 | 17 | cfg_if! { 18 | if #[cfg(feature = "tls")] { 19 | pub use tokio_native_tls; 20 | pub use client::TlsClientTransport; 21 | pub use connection::TlsConnection; 22 | pub use server::TlsServerTransport; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /rsocket/src/core/factory.rs: -------------------------------------------------------------------------------- 1 | use super::{Client, ClientBuilder, ServerBuilder}; 2 | use crate::transport::{Connection, ServerTransport, Transport}; 3 | 4 | #[derive(Debug)] 5 | pub struct RSocketFactory; 6 | 7 | impl RSocketFactory { 8 | pub fn connect() -> ClientBuilder 9 | where 10 | T: Send + Sync + Transport, 11 | C: Send + Sync + Connection, 12 | { 13 | ClientBuilder::new() 14 | } 15 | 16 | pub fn receive() -> ServerBuilder 17 | where 18 | S: Send + Sync + ServerTransport, 19 | T: Send + Sync + Transport, 20 | { 21 | ServerBuilder::new() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rsocket-test/tests/test_routing_metadata.rs: -------------------------------------------------------------------------------- 1 | extern crate rsocket_rust; 2 | 3 | use bytes::BytesMut; 4 | use rsocket_rust::extension::RoutingMetadata; 5 | use rsocket_rust::utils::Writeable; 6 | 7 | #[test] 8 | fn routing_metadata_codec() { 9 | let m = RoutingMetadata::builder() 10 | .push_str("/orders") 11 | .push_str("/orders/77778888") 12 | .push_str("/users") 13 | .push_str("/users/1234") 14 | .build(); 15 | 16 | let mut bf = BytesMut::new(); 17 | m.write_to(&mut bf); 18 | println!("encode routing metadata: {}", hex::encode(bf.to_vec())); 19 | let m2 = RoutingMetadata::decode(&mut bf).unwrap(); 20 | let tags = m2.get_tags(); 21 | for tag in tags { 22 | println!("decode tag: {}", tag); 23 | } 24 | assert_eq!(4, tags.len()); 25 | assert_eq!(m.get_tags(), tags); 26 | } 27 | -------------------------------------------------------------------------------- /rsocket-transport-wasm/src/connection.rs: -------------------------------------------------------------------------------- 1 | use futures_channel::mpsc; 2 | use futures_util::{SinkExt, StreamExt}; 3 | use rsocket_rust::transport::{Connection, FrameSink, FrameStream}; 4 | use rsocket_rust::{error::RSocketError, frame::Frame}; 5 | 6 | #[derive(Debug)] 7 | pub struct WebsocketConnection { 8 | rx: mpsc::Receiver, 9 | tx: mpsc::Sender, 10 | } 11 | 12 | impl WebsocketConnection { 13 | pub(crate) fn new(tx: mpsc::Sender, rx: mpsc::Receiver) -> WebsocketConnection { 14 | WebsocketConnection { rx, tx } 15 | } 16 | } 17 | 18 | impl Connection for WebsocketConnection { 19 | fn split(self) -> (Box, Box) { 20 | ( 21 | Box::new(self.tx.sink_map_err(|e| RSocketError::Other(e.into()))), 22 | Box::new(self.rx.map(Ok)), 23 | ) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rsocket-transport-websocket/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsocket_rust_transport_websocket" 3 | version = "0.7.4" 4 | authors = ["Jeffsky "] 5 | edition = "2021" 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | repository = "https://github.com/rsocket/rsocket-rust" 9 | homepage = "https://github.com/rsocket/rsocket-rust" 10 | description = "Websocket RSocket transport implementation." 11 | 12 | [dependencies] 13 | log = "0.4.14" 14 | futures = "0.3.15" 15 | bytes = "1.0.1" 16 | url = "2.2.2" 17 | 18 | [dependencies.tokio-tungstenite] 19 | version = "0.18.0" 20 | features = ["native-tls"] 21 | 22 | [dependencies.rsocket_rust] 23 | path = "../rsocket" 24 | version = "0.7" 25 | features = ["frame"] 26 | 27 | [dependencies.tokio] 28 | version = "1.0.3" 29 | default-features = false 30 | features = [ "macros", "rt", "rt-multi-thread", "net", "sync"] 31 | -------------------------------------------------------------------------------- /rsocket/src/frame/version.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use crate::utils::Writeable; 4 | 5 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 6 | pub struct Version { 7 | major: u16, 8 | minor: u16, 9 | } 10 | 11 | impl Default for Version { 12 | fn default() -> Version { 13 | Version { major: 1, minor: 0 } 14 | } 15 | } 16 | 17 | impl Writeable for Version { 18 | fn write_to(&self, bf: &mut BytesMut) { 19 | bf.put_u16(self.major); 20 | bf.put_u16(self.minor); 21 | } 22 | fn len(&self) -> usize { 23 | 4 24 | } 25 | } 26 | 27 | impl Version { 28 | pub fn new(major: u16, minor: u16) -> Version { 29 | Version { major, minor } 30 | } 31 | 32 | pub fn get_major(self) -> u16 { 33 | self.major 34 | } 35 | 36 | pub fn get_minor(self) -> u16 { 37 | self.minor 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/cli.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | 4 | use rsocket_rust::prelude::*; 5 | use rsocket_rust::utils::EchoRSocket; 6 | use rsocket_rust::Result; 7 | use rsocket_rust_transport_tcp::TcpClientTransport; 8 | 9 | #[tokio::main] 10 | async fn main() -> Result<()> { 11 | env_logger::builder().format_timestamp_millis().init(); 12 | let client = RSocketFactory::connect() 13 | .transport(TcpClientTransport::from("127.0.0.1:7878")) 14 | .acceptor(Box::new(|| { 15 | // Return a responder. 16 | Box::new(EchoRSocket) 17 | })) 18 | .start() 19 | .await 20 | .expect("Connect failed!"); 21 | 22 | let req = Payload::builder().set_data_utf8("Ping!").build(); 23 | 24 | match client.request_response(req).await { 25 | Ok(res) => info!("{:?}", res), 26 | Err(e) => error!("{}", e), 27 | } 28 | 29 | Ok(()) 30 | } 31 | -------------------------------------------------------------------------------- /rsocket-messaging/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsocket_rust_messaging" 3 | version = "0.7.4" 4 | authors = ["Jeffsky "] 5 | edition = "2021" 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | repository = "https://github.com/rsocket/rsocket-rust" 9 | homepage = "https://github.com/rsocket/rsocket-rust" 10 | description = "Communicate with Spring RSocket Messaging." 11 | 12 | [dependencies] 13 | futures = "0.3.10" 14 | bytes = "1.0.1" 15 | serde = "1.0.119" 16 | serde_json = "1.0.61" 17 | serde_cbor = "0.11.1" 18 | hex = "0.4.2" 19 | url = "2.2.0" 20 | 21 | [dependencies.rsocket_rust] 22 | path = "../rsocket" 23 | version = "0.7" 24 | features = ["frame"] 25 | 26 | [dependencies.rsocket_rust_transport_tcp] 27 | path = "../rsocket-transport-tcp" 28 | version = "0.7" 29 | 30 | [dependencies.rsocket_rust_transport_websocket] 31 | path = "../rsocket-transport-websocket" 32 | version = "0.7" 33 | -------------------------------------------------------------------------------- /rsocket/src/macros/composite.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! composite { 3 | ($($x:expr,$y:expr),+) => { 4 | { 5 | let mut b = $crate::extension::CompositeMetadata::builder(); 6 | $( 7 | b = b.push($x.into(),$y); 8 | )* 9 | b.build() 10 | } 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | 18 | #[test] 19 | fn test_composite() { 20 | let c = composite!("application/json", "123", "text/plain", "ccc"); 21 | let vv: Vec<_> = c 22 | .iter() 23 | .map(|it| { 24 | format!( 25 | "{}={}", 26 | it.get_mime_type(), 27 | it.get_metadata_utf8().unwrap_or_default() 28 | ) 29 | }) 30 | .collect(); 31 | assert_eq!(vv.join(","), "application/json=123,text/plain=ccc"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/connection/tcp.rs: -------------------------------------------------------------------------------- 1 | use futures::{SinkExt, StreamExt}; 2 | use rsocket_rust::error::RSocketError; 3 | use rsocket_rust::transport::{Connection, FrameSink, FrameStream}; 4 | use tokio::net::TcpStream; 5 | use tokio_util::codec::Framed; 6 | 7 | use super::codec::LengthBasedFrameCodec; 8 | 9 | #[derive(Debug)] 10 | pub struct TcpConnection { 11 | stream: TcpStream, 12 | } 13 | 14 | impl Connection for TcpConnection { 15 | fn split(self) -> (Box, Box) { 16 | let (sink, stream) = Framed::new(self.stream, LengthBasedFrameCodec).split(); 17 | ( 18 | Box::new(sink.sink_map_err(|e| RSocketError::Other(e.into()))), 19 | Box::new(stream.map(|next| next.map_err(|e| RSocketError::Other(e.into())))), 20 | ) 21 | } 22 | } 23 | 24 | impl From for TcpConnection { 25 | fn from(stream: TcpStream) -> TcpConnection { 26 | TcpConnection { stream } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/connection/uds.rs: -------------------------------------------------------------------------------- 1 | use futures::{SinkExt, StreamExt}; 2 | use rsocket_rust::error::RSocketError; 3 | use rsocket_rust::transport::{Connection, FrameSink, FrameStream}; 4 | use tokio::net::UnixStream; 5 | use tokio_util::codec::Framed; 6 | 7 | use super::codec::LengthBasedFrameCodec; 8 | 9 | #[derive(Debug)] 10 | pub struct UnixConnection { 11 | stream: UnixStream, 12 | } 13 | 14 | impl Connection for UnixConnection { 15 | fn split(self) -> (Box, Box) { 16 | let (sink, stream) = Framed::new(self.stream, LengthBasedFrameCodec).split(); 17 | ( 18 | Box::new(sink.sink_map_err(|e| RSocketError::Other(e.into()))), 19 | Box::new(stream.map(|it| it.map_err(|e| RSocketError::Other(e.into())))), 20 | ) 21 | } 22 | } 23 | 24 | impl From for UnixConnection { 25 | fn from(stream: UnixStream) -> UnixConnection { 26 | UnixConnection { stream } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/tls/server.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | 4 | use rsocket_rust::prelude::*; 5 | use rsocket_rust::utils::EchoRSocket; 6 | use rsocket_rust::Result; 7 | use rsocket_rust_transport_tcp::tokio_native_tls::{native_tls, TlsAcceptor}; 8 | use rsocket_rust_transport_tcp::TlsServerTransport; 9 | 10 | #[tokio::main] 11 | async fn main() -> Result<()> { 12 | env_logger::builder().format_timestamp_millis().init(); 13 | 14 | let der = include_bytes!("foobar.com.p12"); 15 | let cert = native_tls::Identity::from_pkcs12(der, "foobar")?; 16 | RSocketFactory::receive() 17 | .acceptor(Box::new(|setup, _socket| { 18 | info!("connection established: {:?}", setup); 19 | Ok(Box::new(EchoRSocket)) 20 | })) 21 | .transport(TlsServerTransport::new( 22 | "127.0.0.1:4444".parse()?, 23 | TlsAcceptor::from(native_tls::TlsAcceptor::builder(cert).build()?), 24 | )) 25 | .serve() 26 | .await 27 | } 28 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/connection/tls.rs: -------------------------------------------------------------------------------- 1 | use futures::{SinkExt, StreamExt}; 2 | use rsocket_rust::error::RSocketError; 3 | use rsocket_rust::transport::{Connection, FrameSink, FrameStream}; 4 | use tokio::net::TcpStream; 5 | use tokio_native_tls::TlsStream; 6 | use tokio_util::codec::Framed; 7 | 8 | use super::codec::LengthBasedFrameCodec; 9 | 10 | #[derive(Debug)] 11 | pub struct TlsConnection { 12 | stream: TlsStream, 13 | } 14 | 15 | impl Connection for TlsConnection { 16 | fn split(self) -> (Box, Box) { 17 | let (sink, stream) = Framed::new(self.stream, LengthBasedFrameCodec).split(); 18 | ( 19 | Box::new(sink.sink_map_err(|e| RSocketError::Other(e.into()))), 20 | Box::new(stream.map(|it| it.map_err(|e| RSocketError::Other(e.into())))), 21 | ) 22 | } 23 | } 24 | 25 | impl From> for TlsConnection { 26 | fn from(stream: TlsStream) -> Self { 27 | Self { stream } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsocket_rust_transport_tcp" 3 | version = "0.7.4" 4 | authors = ["Jeffsky "] 5 | edition = "2021" 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | repository = "https://github.com/rsocket/rsocket-rust" 9 | homepage = "https://github.com/rsocket/rsocket-rust" 10 | description = "TCP RSocket transport implementation." 11 | 12 | [features] 13 | default = [] 14 | tls = ["tokio-native-tls"] 15 | 16 | [dependencies] 17 | log = "0.4.14" 18 | futures = "0.3.15" 19 | bytes = "1.0.1" 20 | cfg-if = "1.0.0" 21 | 22 | [dependencies.rsocket_rust] 23 | path = "../rsocket" 24 | version = "0.7" 25 | features = ["frame"] 26 | 27 | [dependencies.tokio] 28 | version = "1.0.3" 29 | default-features = false 30 | features = [ "rt", "rt-multi-thread", "net", "sync", "io-util", "macros" ] 31 | 32 | [dependencies.tokio-util] 33 | version = "0.6.6" 34 | default-features = false 35 | features = ["codec"] 36 | 37 | [dependencies.tokio-native-tls] 38 | optional = true 39 | version = "0.3.0" 40 | -------------------------------------------------------------------------------- /rsocket/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsocket_rust" 3 | version = "0.7.5" 4 | authors = ["Jeffsky "] 5 | edition = "2021" 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | repository = "https://github.com/rsocket/rsocket-rust" 9 | homepage = "https://github.com/rsocket/rsocket-rust" 10 | description = "rsocket-rust is an implementation of the RSocket protocol in Rust." 11 | 12 | [dependencies] 13 | log = "0.4.14" 14 | bytes = "1.0.1" 15 | futures = "0.3.15" 16 | once_cell = "1.7.2" 17 | async-trait = "0.1.50" 18 | dashmap = "5.3.4" 19 | thiserror = "1.0.24" 20 | anyhow = "1.0.40" 21 | async-stream = "0.3.1" 22 | cfg-if = "1.0.0" 23 | 24 | [target.'cfg(target_arch = "wasm32")'.dependencies] 25 | wasm-bindgen-futures = "0.4.24" 26 | 27 | [dependencies.tokio] 28 | version = "1.0.3" 29 | default-features = false 30 | features = [ "macros", "rt", "rt-multi-thread", "sync", "time" ] 31 | 32 | [dependencies.tokio-stream] 33 | version = "0.1.7" 34 | features = ["sync"] 35 | 36 | [features] 37 | default = [] 38 | frame = [] 39 | -------------------------------------------------------------------------------- /rsocket-transport-wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsocket_rust_transport_wasm" 3 | version = "0.7.4" 4 | authors = ["Jeffsky "] 5 | edition = "2021" 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | repository = "https://github.com/rsocket/rsocket-rust" 9 | homepage = "https://github.com/rsocket/rsocket-rust" 10 | description = "WASM Websocket RSocket transport implementation." 11 | 12 | [dependencies] 13 | bytes = "1.0.1" 14 | wasm-bindgen-futures = "0.4.24" 15 | futures-channel = "0.3.15" 16 | futures-util = "0.3.15" 17 | js-sys = "0.3.51" 18 | serde = "1.0.126" 19 | serde_derive = "1.0.126" 20 | log = "0.4.14" 21 | 22 | [dependencies.rsocket_rust] 23 | path = "../rsocket" 24 | version = "0.7" 25 | features = ["frame"] 26 | 27 | [dependencies.wasm-bindgen] 28 | version = "0.2.74" 29 | features = ["serde-serialize"] 30 | 31 | [dependencies.web-sys] 32 | version = "0.3.51" 33 | features = [ 34 | "FileReader", 35 | "ProgressEvent", 36 | "Blob", 37 | "ErrorEvent", 38 | "MessageEvent", 39 | "WebSocket", 40 | "Event", 41 | ] 42 | -------------------------------------------------------------------------------- /examples/proxy.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | 4 | use futures::executor::block_on; 5 | use rsocket_rust::prelude::*; 6 | use rsocket_rust::utils::EchoRSocket; 7 | use rsocket_rust::Result; 8 | use rsocket_rust_transport_tcp::*; 9 | 10 | #[tokio::main] 11 | async fn main() -> Result<()> { 12 | env_logger::builder().format_timestamp_millis().init(); 13 | 14 | RSocketFactory::receive() 15 | .transport(TcpServerTransport::from("127.0.0.1:7979")) 16 | .acceptor(Box::new(|setup, _sending_socket| { 17 | info!("incoming socket: setup={:?}", setup); 18 | Ok(Box::new(block_on(async move { 19 | RSocketFactory::connect() 20 | .transport(TcpClientTransport::from("127.0.0.1:7878")) 21 | .acceptor(Box::new(|| Box::new(EchoRSocket))) 22 | .setup(Payload::from("I'm Rust!")) 23 | .start() 24 | .await 25 | .unwrap() 26 | }))) 27 | })) 28 | .serve() 29 | .await 30 | } 31 | -------------------------------------------------------------------------------- /examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples" 3 | version = "0.0.0" 4 | authors = ["Jeffsky "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dev-dependencies] 9 | log = "0.4.14" 10 | env_logger = "0.8.3" 11 | futures = "0.3.15" 12 | clap = "2.33.3" 13 | pprof = { version = "0.4.3", features = ["flamegraph"] } 14 | 15 | [dev-dependencies.rsocket_rust] 16 | version = "0.7" 17 | 18 | [dev-dependencies.rsocket_rust_transport_tcp] 19 | version = "0.7" 20 | features = ["tls"] 21 | 22 | [dev-dependencies.rsocket_rust_transport_websocket] 23 | version = "0.7" 24 | 25 | [dev-dependencies.tokio] 26 | version = "1.0.3" 27 | default-features = false 28 | features = ["full"] 29 | 30 | [[example]] 31 | name = "echo" 32 | path = "echo.rs" 33 | 34 | [[example]] 35 | name = "proxy" 36 | path = "proxy.rs" 37 | 38 | [[example]] 39 | name = "cli" 40 | path = "cli.rs" 41 | 42 | [[example]] 43 | name = "qps" 44 | path = "qps.rs" 45 | 46 | [[example]] 47 | name = "tls-server" 48 | path = "tls/server.rs" 49 | 50 | [[example]] 51 | name = "tls-client" 52 | path = "tls/client.rs" 53 | -------------------------------------------------------------------------------- /examples/tls/client.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | 4 | use rsocket_rust::prelude::*; 5 | use rsocket_rust::Result; 6 | use rsocket_rust_transport_tcp::tokio_native_tls::{native_tls, TlsConnector}; 7 | use rsocket_rust_transport_tcp::TlsClientTransport; 8 | 9 | #[tokio::main] 10 | async fn main() -> Result<()> { 11 | env_logger::builder().format_timestamp_millis().init(); 12 | 13 | let pem = include_bytes!("foobar.com.pem"); 14 | let cert = native_tls::Certificate::from_pem(pem)?; 15 | let cx = native_tls::TlsConnector::builder() 16 | .add_root_certificate(cert) 17 | .build()?; 18 | let cx = TlsConnector::from(cx); 19 | let cli = RSocketFactory::connect() 20 | .transport(TlsClientTransport::new( 21 | "foobar.com".into(), 22 | "127.0.0.1:4444".parse()?, 23 | cx, 24 | )) 25 | .start() 26 | .await?; 27 | let res = cli 28 | .request_response(Payload::builder().set_data_utf8("hello").build()) 29 | .await?; 30 | info!("response: {:?}", res); 31 | 32 | cli.wait_for_close().await; 33 | 34 | Ok(()) 35 | } 36 | -------------------------------------------------------------------------------- /rsocket/src/transport/spi.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | use std::io::Error as IOError; 3 | use std::marker::Unpin; 4 | use std::pin::Pin; 5 | use std::result::Result as StdResult; 6 | use std::sync::Arc; 7 | 8 | use async_trait::async_trait; 9 | use futures::channel::{mpsc, oneshot}; 10 | use futures::{Sink, Stream}; 11 | use tokio::sync::Notify; 12 | 13 | use crate::payload::SetupPayload; 14 | use crate::spi::{ClientResponder, RSocket, ServerResponder}; 15 | use crate::{error::RSocketError, frame::Frame}; 16 | use crate::{Error, Result}; 17 | 18 | pub type FrameSink = dyn Sink + Send + Unpin; 19 | pub type FrameStream = dyn Stream> + Send + Unpin; 20 | 21 | pub trait Connection { 22 | fn split(self) -> (Box, Box); 23 | } 24 | 25 | #[async_trait] 26 | pub trait Transport { 27 | type Conn: Connection + Send; 28 | 29 | async fn connect(self) -> Result; 30 | } 31 | 32 | #[async_trait] 33 | pub trait ServerTransport { 34 | type Item: Transport; 35 | 36 | async fn start(&mut self) -> Result<()>; 37 | 38 | async fn next(&mut self) -> Option>; 39 | } 40 | -------------------------------------------------------------------------------- /.github/workflows/linelint.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | name: linelint 21 | on: [push, pull_request] 22 | 23 | jobs: 24 | linelint: 25 | runs-on: ubuntu-latest 26 | name: Check if all files end in newline 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v2 30 | - name: Linelint 31 | uses: fernandrone/linelint@0.0.4 32 | -------------------------------------------------------------------------------- /rsocket-test/tests/test_mimes.rs: -------------------------------------------------------------------------------- 1 | extern crate rsocket_rust; 2 | 3 | use rsocket_rust::extension::{self, MimeType}; 4 | 5 | #[test] 6 | fn test_from_str() { 7 | let result = MimeType::from("foobar"); 8 | match result { 9 | MimeType::WellKnown(_) => panic!("failed"), 10 | MimeType::Normal(s) => assert_eq!(&s, "foobar"), 11 | } 12 | } 13 | 14 | #[test] 15 | fn test_wellknown() { 16 | let well = MimeType::from("application/json"); 17 | assert_eq!(extension::MimeType::APPLICATION_JSON, well); 18 | assert_eq!(0x05, well.as_u8().unwrap()); 19 | let custom = MimeType::from("application/custom"); 20 | assert_eq!(MimeType::Normal("application/custom".to_owned()), custom); 21 | } 22 | 23 | #[test] 24 | fn test_parse() { 25 | assert!(MimeType::parse(0xFF).is_none(), "should be none"); 26 | for x in 0..0x29 { 27 | assert!(MimeType::parse(x).is_some(), "should not be none"); 28 | } 29 | for x in 0x29..0x7A { 30 | assert!(MimeType::parse(x).is_none(), "should be none"); 31 | } 32 | for x in 0x7A..0x80 { 33 | assert!(MimeType::parse(x).is_some(), "should not be none"); 34 | } 35 | for x in 0x80..0xFF { 36 | assert!(MimeType::parse(x).is_none(), "should be none"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rsocket-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsocket_rust_test" 3 | version = "0.0.0" 4 | authors = ["Jeffsky "] 5 | edition = "2021" 6 | publish = false 7 | 8 | [dev-dependencies] 9 | log = "0.4.14" 10 | futures = "0.3.15" 11 | env_logger = "0.8.3" 12 | bytes = "1.0.1" 13 | hex = "0.4.3" 14 | rand = "0.8.3" 15 | serde = "1.0.126" 16 | serde_derive = "1.0.126" 17 | 18 | [dev-dependencies.rsocket_rust] 19 | path = "../rsocket" 20 | version = "0.7" 21 | features = ["frame"] 22 | 23 | [dev-dependencies.rsocket_rust_transport_tcp] 24 | path = "../rsocket-transport-tcp" 25 | version = "0.7" 26 | 27 | [dev-dependencies.rsocket_rust_transport_websocket] 28 | path = "../rsocket-transport-websocket" 29 | version = "0.7" 30 | 31 | [dev-dependencies.rsocket_rust_messaging] 32 | path = "../rsocket-messaging" 33 | version = "0.7" 34 | 35 | [dev-dependencies.tokio] 36 | version = "1.0.3" 37 | default-features = false 38 | features = ["full"] 39 | 40 | [dev-dependencies.tokio-stream] 41 | version = "0.1.7" 42 | features = ["sync"] 43 | 44 | [dev-dependencies.anyhow] 45 | version = "1.0.40" 46 | 47 | [dev-dependencies.async-trait] 48 | version = "0.1.50" 49 | 50 | [dev-dependencies.serial_test] 51 | version = "0.5.1" 52 | 53 | [dev-dependencies.async-stream] 54 | version = "0.3.1" 55 | -------------------------------------------------------------------------------- /rsocket-transport-websocket/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::type_complexity)] 2 | 3 | #[macro_use] 4 | extern crate log; 5 | 6 | mod client; 7 | mod connection; 8 | mod server; 9 | 10 | pub use client::{WebsocketClientTransport, WebsocketRequest}; 11 | pub use server::WebsocketServerTransport; 12 | 13 | #[cfg(test)] 14 | mod test_websocket { 15 | use rsocket_rust::prelude::*; 16 | use tokio_tungstenite::tungstenite::client::IntoClientRequest; 17 | 18 | use super::*; 19 | 20 | #[ignore] 21 | #[tokio::test] 22 | async fn test_client() { 23 | let mut req = "ws://127.0.0.1:8080/hello".into_client_request().unwrap(); 24 | 25 | // Optional: custom headers 26 | let headers = req.headers_mut(); 27 | headers.insert("x-foo-bar", "42".parse().unwrap()); 28 | 29 | let tp = WebsocketClientTransport::from(req); 30 | let c = RSocketFactory::connect() 31 | .transport(tp) 32 | .start() 33 | .await 34 | .expect("connect failed"); 35 | let res = c 36 | .request_response(Payload::builder().set_data_utf8("foo").build()) 37 | .await 38 | .expect("request failed") 39 | .unwrap(); 40 | 41 | println!("response: {:?}", res); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one or more 3 | # contributor license agreements. See the NOTICE file distributed with 4 | # this work for additional information regarding copyright ownership. 5 | # The ASF licenses this file to You under the Apache License, Version 2.0 6 | # (the "License"); you may not use this file except in compliance with 7 | # the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # See https://pre-commit.com for more information 19 | # See https://pre-commit.com/hooks.html for more hooks 20 | 21 | repos: 22 | - repo: https://github.com/pre-commit/pre-commit-hooks 23 | rev: v2.3.0 24 | hooks: 25 | - id: end-of-file-fixer 26 | - id: trailing-whitespace 27 | - repo: https://github.com/doublify/pre-commit-rust 28 | rev: v1.0 29 | hooks: 30 | - id: fmt 31 | - id: cargo-check 32 | - id: clippy 33 | -------------------------------------------------------------------------------- /rsocket/src/transport/misc.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::{AtomicI64, AtomicU32, Ordering}; 2 | use std::sync::Arc; 3 | 4 | use crate::frame::Frame; 5 | 6 | #[derive(Debug, Clone)] 7 | pub(crate) struct StreamID { 8 | inner: Arc, 9 | } 10 | 11 | impl StreamID { 12 | pub(crate) fn new(value: u32) -> StreamID { 13 | let inner = Arc::new(AtomicU32::new(value)); 14 | StreamID { inner } 15 | } 16 | 17 | pub(crate) fn next(&self) -> u32 { 18 | let counter = self.inner.clone(); 19 | counter.fetch_add(2, Ordering::SeqCst) 20 | } 21 | } 22 | 23 | impl From for StreamID { 24 | fn from(v: u32) -> StreamID { 25 | StreamID::new(v) 26 | } 27 | } 28 | 29 | #[derive(Debug, Clone)] 30 | pub(crate) struct Counter { 31 | inner: Arc, 32 | } 33 | 34 | impl Counter { 35 | pub(crate) fn new(value: i64) -> Counter { 36 | Counter { 37 | inner: Arc::new(AtomicI64::new(value)), 38 | } 39 | } 40 | 41 | pub(crate) fn count_down(&self) -> i64 { 42 | self.inner.fetch_add(-1, Ordering::SeqCst) - 1 43 | } 44 | } 45 | 46 | #[inline] 47 | pub(crate) fn debug_frame(snd: bool, f: &Frame) { 48 | if snd { 49 | debug!("===> SND: {:?}", f); 50 | } else { 51 | debug!("<=== RCV: {:?}", f); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rsocket/src/frame/utils.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use super::Frame; 4 | use crate::error::RSocketError; 5 | use crate::utils::{u24, Writeable}; 6 | 7 | #[inline] 8 | pub(crate) fn read_payload( 9 | flag: u16, 10 | bf: &mut BytesMut, 11 | ) -> crate::Result<(Option, Option)> { 12 | let m: Option = if flag & Frame::FLAG_METADATA != 0 { 13 | if bf.len() < 3 { 14 | return Err(RSocketError::InCompleteFrame.into()); 15 | } 16 | let n = u24::read_advance(bf); 17 | Some(bf.split_to(n.into()).freeze()) 18 | } else { 19 | None 20 | }; 21 | let d: Option = if bf.is_empty() { 22 | None 23 | } else { 24 | Some(bf.split().freeze()) 25 | }; 26 | Ok((m, d)) 27 | } 28 | 29 | pub(crate) fn calculate_payload_length(metadata: Option<&Bytes>, data: Option<&Bytes>) -> usize { 30 | metadata.map(|v| 3 + v.len()).unwrap_or(0) + data.map(|v| v.len()).unwrap_or(0) 31 | } 32 | 33 | #[inline] 34 | pub(crate) fn write_payload(bf: &mut BytesMut, metadata: Option<&Bytes>, data: Option<&Bytes>) { 35 | if let Some(v) = metadata { 36 | u24::from(v.len()).write_to(bf); 37 | bf.extend_from_slice(v); 38 | } 39 | if let Some(v) = data { 40 | bf.extend_from_slice(v); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/connection/codec.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Error, ErrorKind}; 2 | 3 | use bytes::{Buf, BytesMut}; 4 | use rsocket_rust::frame::Frame; 5 | use rsocket_rust::utils::{u24, Writeable}; 6 | use tokio_util::codec::{Decoder, Encoder}; 7 | 8 | pub struct LengthBasedFrameCodec; 9 | 10 | const LEN_BYTES: usize = 3; 11 | 12 | impl Decoder for LengthBasedFrameCodec { 13 | type Item = Frame; 14 | type Error = Error; 15 | 16 | fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { 17 | let actual = buf.len(); 18 | if actual < LEN_BYTES { 19 | return Ok(None); 20 | } 21 | let l = u24::read(buf).into(); 22 | if actual < LEN_BYTES + l { 23 | return Ok(None); 24 | } 25 | buf.advance(LEN_BYTES); 26 | let mut bb = buf.split_to(l); 27 | match Frame::decode(&mut bb) { 28 | Ok(v) => Ok(Some(v)), 29 | Err(_e) => Err(Error::from(ErrorKind::InvalidInput)), 30 | } 31 | } 32 | } 33 | 34 | impl Encoder for LengthBasedFrameCodec { 35 | type Error = Error; 36 | fn encode(&mut self, item: Frame, buf: &mut BytesMut) -> Result<(), Self::Error> { 37 | let l = item.len(); 38 | buf.reserve(LEN_BYTES + l); 39 | u24::from(l).write_to(buf); 40 | item.write_to(buf); 41 | Ok(()) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /rsocket-test/tests/test_composite_metadata.rs: -------------------------------------------------------------------------------- 1 | use bytes::{BufMut, BytesMut}; 2 | use rsocket_rust::extension::{self, CompositeMetadata, CompositeMetadataEntry, MimeType}; 3 | use rsocket_rust::utils::Writeable; 4 | 5 | #[test] 6 | fn test_encode_and_decode() { 7 | let bingo = |metadatas: Vec<&CompositeMetadataEntry>| { 8 | assert_eq!(2, metadatas.len()); 9 | assert_eq!( 10 | extension::MimeType::TEXT_PLAIN, 11 | *metadatas[0].get_mime_type() 12 | ); 13 | assert_eq!("Hello World!", metadatas[0].get_metadata_utf8().unwrap()); 14 | assert_eq!( 15 | MimeType::from("application/not_well"), 16 | *metadatas[1].get_mime_type() 17 | ); 18 | assert_eq!(b"Not Well!", metadatas[1].get_metadata().as_ref()); 19 | }; 20 | 21 | let cm = CompositeMetadata::builder() 22 | .push(MimeType::from("text/plain"), b"Hello World!") 23 | .push(MimeType::from("application/not_well"), "Not Well!") 24 | .build(); 25 | bingo(cm.iter().collect()); 26 | 27 | let mut bf = BytesMut::new(); 28 | cm.write_to(&mut bf); 29 | let cm2 = CompositeMetadata::decode(&mut bf).unwrap(); 30 | bingo(cm2.iter().collect()); 31 | } 32 | 33 | #[test] 34 | fn test_bad() { 35 | let mut bf = BytesMut::new(); 36 | bf.put_slice(b"must bad"); 37 | assert!( 38 | CompositeMetadata::decode(&mut bf).is_err(), 39 | "should be error" 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /examples/tls/foobar.com.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIELzCCApegAwIBAgIRAL59MTynwUpUEUR3vAJXA5wwDQYJKoZIhvcNAQELBQAw 3 | dTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSUwIwYDVQQLDBxjYWl3 4 | QG1hcnMubG9jYWwgKFdlaXdlaSBDYWkpMSwwKgYDVQQDDCNta2NlcnQgY2Fpd0Bt 5 | YXJzLmxvY2FsIChXZWl3ZWkgQ2FpKTAeFw0yMTAxMTIwODA0NTZaFw0yMzA0MTIw 6 | ODA0NTZaMFAxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0 7 | ZTElMCMGA1UECwwcY2Fpd0BtYXJzLmxvY2FsIChXZWl3ZWkgQ2FpKTCCASIwDQYJ 8 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBANzR4YHiCU6SsKrdLW6Yc25FqGAvHboW 9 | cSF6xycu8kUnjfrlVz2oLWT/hnOPP7RjaCUWQGt5uflvuvq+E8PWvIY3nR21S2lX 10 | 4kQFLvP9/011P94AHs941jKDkAQ76Fa6T6ZcoFt5Z39srPldxYdxhMBqvpfCEXxP 11 | X5/pTlLIkFlV0QUfZ9E3p9QlYeR/NaeQ4EM5+gJo36ueJU9T4K8lqrgXXd6Ew5Tg 12 | mynZitfs9sTcXl+HX34eJlwUqPVpNnlr4+jWe+Yiuipck9jjBeVTnYqfpXP6uHZ7 13 | yUpjTwvzA7Samu43cUNVvunHf51jQtIrSWww3U1zFrrdsNzBEp9Mv7kCAwEAAaNf 14 | MF0wDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQY 15 | MBaAFIMrc/qDTdodpyMSPxDVH/RwVj39MBUGA1UdEQQOMAyCCmZvb2Jhci5jb20w 16 | DQYJKoZIhvcNAQELBQADggGBAG5BOYGqum7g0Bc8Z8gxTrkUyzd1e9D5cNLwmYm6 17 | G+6/xfH6NM4ooQo5ek7GclUN5nkU0ZF85ElqQawR6SxH7C9wZT1s0HL7bOXq49kJ 18 | Az2obJjyyap+sWNBnTcoKW/m9uc5ZSkKaI07AvWg4Uy16xxXWocN7zt3iEdgvTiE 19 | 953MFPMor5TgdgJScUuLh8OQrs+qX3AYKvl1wPoFeKqO2k9HdVu00uV7+x0LxtSU 20 | aH0fbeXS1KKQARq6Xa1L69iUUcOh3RIMTLnQNMmb6F4oMWLERvwsI5qZ9FWGi0e/ 21 | lQL/gGmNQSiihvTIC/oaMaIQyCrgJHYcXSB8RyPy4PvaWG6dVR0M8H/mtiU75U6j 22 | 7Z4Hwr74WhwY1wqIjnwL/jtVAyzyL8Yj9YkrYwditNYiDr3ciCDfxVOnTYK8XoQc 23 | v0RJ/cPlJji0VOTXV+ebIkTELjD27A2dXif+4hKfctehULsEVkUrY8jn36YXfw2g 24 | SP4kpOTQxpbmjW7KbVOmneIrsA== 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /rsocket/src/frame/request_n.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use super::{utils, Body, Frame, REQUEST_MAX}; 4 | use crate::error::RSocketError; 5 | use crate::utils::Writeable; 6 | 7 | #[derive(Debug, Eq, PartialEq)] 8 | pub struct RequestN { 9 | n: u32, 10 | } 11 | 12 | pub struct RequestNBuilder { 13 | stream_id: u32, 14 | flag: u16, 15 | value: RequestN, 16 | } 17 | 18 | impl RequestNBuilder { 19 | fn new(stream_id: u32, flag: u16) -> RequestNBuilder { 20 | RequestNBuilder { 21 | stream_id, 22 | flag, 23 | value: RequestN { n: REQUEST_MAX }, 24 | } 25 | } 26 | 27 | pub fn set_n(mut self, n: u32) -> Self { 28 | self.value.n = n; 29 | self 30 | } 31 | 32 | pub fn build(self) -> Frame { 33 | Frame::new(self.stream_id, Body::RequestN(self.value), self.flag) 34 | } 35 | } 36 | 37 | impl RequestN { 38 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 39 | if bf.len() < 4 { 40 | Err(RSocketError::InCompleteFrame.into()) 41 | } else { 42 | let n = bf.get_u32(); 43 | Ok(RequestN { n }) 44 | } 45 | } 46 | 47 | pub fn builder(stream_id: u32, flag: u16) -> RequestNBuilder { 48 | RequestNBuilder::new(stream_id, flag) 49 | } 50 | 51 | pub fn get_n(&self) -> u32 { 52 | self.n 53 | } 54 | } 55 | 56 | impl Writeable for RequestN { 57 | fn write_to(&self, bf: &mut BytesMut) { 58 | bf.put_u32(self.get_n()) 59 | } 60 | 61 | fn len(&self) -> usize { 62 | 4 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /rsocket/src/frame/resume_ok.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use super::{Body, Frame}; 4 | use crate::error::RSocketError; 5 | use crate::utils::Writeable; 6 | 7 | #[derive(Debug, Eq, PartialEq)] 8 | pub struct ResumeOK { 9 | position: u64, 10 | } 11 | 12 | pub struct ResumeOKBuilder { 13 | stream_id: u32, 14 | flag: u16, 15 | value: ResumeOK, 16 | } 17 | 18 | impl ResumeOKBuilder { 19 | fn new(stream_id: u32, flag: u16) -> ResumeOKBuilder { 20 | ResumeOKBuilder { 21 | stream_id, 22 | flag, 23 | value: ResumeOK { position: 0 }, 24 | } 25 | } 26 | pub fn set_position(mut self, position: u64) -> Self { 27 | self.value.position = position; 28 | self 29 | } 30 | 31 | pub fn build(self) -> Frame { 32 | Frame::new(self.stream_id, Body::ResumeOK(self.value), self.flag) 33 | } 34 | } 35 | 36 | impl ResumeOK { 37 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 38 | if bf.len() < 8 { 39 | Err(RSocketError::InCompleteFrame.into()) 40 | } else { 41 | Ok(ResumeOK { 42 | position: bf.get_u64(), 43 | }) 44 | } 45 | } 46 | 47 | pub fn builder(stream_id: u32, flag: u16) -> ResumeOKBuilder { 48 | ResumeOKBuilder::new(stream_id, flag) 49 | } 50 | 51 | pub fn get_position(&self) -> u64 { 52 | self.position 53 | } 54 | } 55 | 56 | impl Writeable for ResumeOK { 57 | fn write_to(&self, bf: &mut BytesMut) { 58 | bf.put_u64(self.get_position()) 59 | } 60 | 61 | fn len(&self) -> usize { 62 | 8 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/client/tls.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use rsocket_rust::async_trait; 4 | use rsocket_rust::{error::RSocketError, transport::Transport, Result}; 5 | use tokio::net::TcpStream; 6 | use tokio_native_tls::{TlsConnector, TlsStream}; 7 | 8 | use crate::connection::TlsConnection; 9 | 10 | #[derive(Debug)] 11 | enum Connector { 12 | Direct(TlsStream), 13 | Lazy(String, SocketAddr, TlsConnector), 14 | } 15 | 16 | pub struct TlsClientTransport { 17 | connector: Connector, 18 | } 19 | 20 | impl TlsClientTransport { 21 | pub fn new(domain: String, addr: SocketAddr, connector: TlsConnector) -> Self { 22 | Self { 23 | connector: Connector::Lazy(domain, addr, connector), 24 | } 25 | } 26 | } 27 | 28 | #[async_trait] 29 | impl Transport for TlsClientTransport { 30 | type Conn = TlsConnection; 31 | 32 | async fn connect(self) -> Result { 33 | match self.connector { 34 | Connector::Direct(stream) => Ok(TlsConnection::from(stream)), 35 | Connector::Lazy(domain, addr, cx) => match TcpStream::connect(addr).await { 36 | Ok(stream) => match cx.connect(&domain, stream).await { 37 | Ok(stream) => Ok(TlsConnection::from(stream)), 38 | Err(e) => Err(RSocketError::Other(e.into()).into()), 39 | }, 40 | Err(e) => Err(RSocketError::IO(e).into()), 41 | }, 42 | } 43 | } 44 | } 45 | 46 | impl From> for TlsClientTransport { 47 | fn from(stream: TlsStream) -> Self { 48 | Self { 49 | connector: Connector::Direct(stream), 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/client/uds.rs: -------------------------------------------------------------------------------- 1 | use rsocket_rust::async_trait; 2 | use rsocket_rust::{error::RSocketError, transport::Transport, Result}; 3 | use tokio::net::UnixStream; 4 | 5 | use crate::connection::UnixConnection; 6 | use crate::misc::parse_uds_addr; 7 | 8 | #[derive(Debug)] 9 | enum Connector { 10 | Direct(UnixStream), 11 | Lazy(String), 12 | } 13 | 14 | #[derive(Debug)] 15 | pub struct UnixClientTransport { 16 | connector: Connector, 17 | } 18 | 19 | #[async_trait] 20 | impl Transport for UnixClientTransport { 21 | type Conn = UnixConnection; 22 | 23 | async fn connect(self) -> Result { 24 | match self.connector { 25 | Connector::Direct(socket) => Ok(UnixConnection::from(socket)), 26 | Connector::Lazy(addr) => match UnixStream::connect(addr).await { 27 | Ok(stream) => Ok(UnixConnection::from(stream)), 28 | Err(e) => Err(RSocketError::IO(e).into()), 29 | }, 30 | } 31 | } 32 | } 33 | 34 | impl From for UnixClientTransport { 35 | fn from(socket: UnixStream) -> UnixClientTransport { 36 | UnixClientTransport { 37 | connector: Connector::Direct(socket), 38 | } 39 | } 40 | } 41 | 42 | impl From for UnixClientTransport { 43 | fn from(addr: String) -> UnixClientTransport { 44 | UnixClientTransport { 45 | connector: Connector::Lazy(parse_uds_addr(addr)), 46 | } 47 | } 48 | } 49 | 50 | impl From<&str> for UnixClientTransport { 51 | fn from(addr: &str) -> UnixClientTransport { 52 | UnixClientTransport { 53 | connector: Connector::Lazy(parse_uds_addr(addr)), 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rsocket-messaging/src/misc.rs: -------------------------------------------------------------------------------- 1 | use rsocket_rust::Result; 2 | use serde::{de::DeserializeOwned, Serialize}; 3 | 4 | pub trait SerDe { 5 | fn marshal(&self, data: &T) -> Result> 6 | where 7 | Self: Sized, 8 | T: Sized + Serialize; 9 | 10 | fn unmarshal(&self, raw: &[u8]) -> Result 11 | where 12 | Self: Sized, 13 | T: Sized + DeserializeOwned; 14 | } 15 | 16 | #[derive(Default)] 17 | struct JsonSerDe {} 18 | 19 | impl SerDe for JsonSerDe { 20 | fn marshal(&self, data: &T) -> Result> 21 | where 22 | T: Sized + Serialize, 23 | { 24 | Ok(serde_json::to_vec(data)?) 25 | } 26 | 27 | fn unmarshal(&self, raw: &[u8]) -> Result 28 | where 29 | T: Sized + DeserializeOwned, 30 | { 31 | Ok(serde_json::from_slice(raw)?) 32 | } 33 | } 34 | 35 | pub fn json() -> impl SerDe { 36 | JsonSerDe {} 37 | } 38 | 39 | pub fn cbor() -> impl SerDe { 40 | CborSerDe {} 41 | } 42 | 43 | struct CborSerDe {} 44 | 45 | impl SerDe for CborSerDe { 46 | fn marshal(&self, data: &T) -> Result> 47 | where 48 | T: Sized + Serialize, 49 | { 50 | Ok(serde_cbor::to_vec(data)?) 51 | } 52 | 53 | fn unmarshal(&self, raw: &[u8]) -> Result 54 | where 55 | T: Sized + DeserializeOwned, 56 | { 57 | Ok(serde_cbor::from_slice(raw)?) 58 | } 59 | } 60 | 61 | pub(crate) fn marshal(ser: impl SerDe, data: &T) -> Result> 62 | where 63 | T: Sized + Serialize, 64 | { 65 | ser.marshal(data) 66 | } 67 | 68 | pub(crate) fn unmarshal(de: impl SerDe, raw: &[u8]) -> Result 69 | where 70 | T: Sized + DeserializeOwned, 71 | { 72 | de.unmarshal(raw) 73 | } 74 | -------------------------------------------------------------------------------- /examples/tls/foobar.com-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDc0eGB4glOkrCq 3 | 3S1umHNuRahgLx26FnEhescnLvJFJ4365Vc9qC1k/4Zzjz+0Y2glFkBrebn5b7r6 4 | vhPD1ryGN50dtUtpV+JEBS7z/f9NdT/eAB7PeNYyg5AEO+hWuk+mXKBbeWd/bKz5 5 | XcWHcYTAar6XwhF8T1+f6U5SyJBZVdEFH2fRN6fUJWHkfzWnkOBDOfoCaN+rniVP 6 | U+CvJaq4F13ehMOU4Jsp2YrX7PbE3F5fh19+HiZcFKj1aTZ5a+Po1nvmIroqXJPY 7 | 4wXlU52Kn6Vz+rh2e8lKY08L8wO0mpruN3FDVb7px3+dY0LSK0lsMN1Ncxa63bDc 8 | wRKfTL+5AgMBAAECggEABdX2I7yZil4OFTXrMXUN9+gXXxNfsb9OFhhskviGppU5 9 | B1xwRczgBj9KiltKz7Wg1voTkcORyqnNQzsqwo42RUXK/TIBYDNWY33Pk9sumBl1 10 | KqTOK6WB46vebn420bPyzu67vi8jMRbqK1zzD3VMkNlBWDlkxOhEGrHLxBxQ1EuH 11 | vLlKODwByMRMjozp8g9R4i+RIhLGP6HRFwaGPcDsKX5FBjFipeYH6mFFn4wqzg3p 12 | qL636u5bmD6bOcrA2P7c42dD2DWiN/jhfJCSw5eBMzNXSBIJxPWgFx/fdUZLNb7G 13 | XdTlNYFexnAntzTN9wP9aaNVE7Zr1vS8htGS2s2iQQKBgQDyymsosdRdfue0oWtp 14 | GgkB5K8KINAQfpw/6FyYry/QjSSO6KYe2B61AkTo5LsOoxalGvmxWrojK6P1sCPn 15 | hHZ4WcuEZqUtFxpzQJEVi8hJemSePofalPHYH5b0rie5msNPxtxsod/0uAlD4yyI 16 | 4mBta7mA79OLszylpaDbdFmKNQKBgQDo1XP1leUPr/tDmlxyP01Yh7bJzOrxHHGH 17 | 3USLW7lDo8o7rWJctr6svsIoCWWWNvNKUOnQL3hU/BZSQD+Y5aEwGfUz4WpF5Bfv 18 | T0uI3HXtYb1SYZhu4Ql9xIWdmKhV626hYf7tzzHB8gyMOm64MInC7gc32dq7Tn2l 19 | ly9XCcTv9QKBgDtqOcsdqaCvu7hCgGyaCHZEJmnOGdzPfyFMlcxvor3grH+kg3Ks 20 | 5ObbBU4RG427b4E8FrrGPyL4PQmU71Rq4CsXnmxqSiW8r6ZguKCTMpJ4t0LafpiJ 21 | Np3zLRf3vpT3QLC3M54KByp2Fx5b67wb2gktAZqCFjzrwf2viKvrzzW5AoGAF7iv 22 | kMTNypReYBvY8VbbtXpWOCclhJ0mP/ZeJmiY7nhAgWX/0HxZ3tWsiFG0xOIiVV77 23 | A1fixZ3NVGHxWM2EZ5ctcTS1FBvSCHKmunHjneTIWh1RX3KT+flMt6q289IBunV2 24 | eJoUcrMLbjoBz8g6MN75Y0pRy6WKjZVioFaBdwUCgYEAy4NrZ5HlST9lfbdTBwuu 25 | VeV5s26dR6xBd0gFr8HanRZBfsNFGXbo11nvVrNa98vS3WsnNTLX68jTsbYbxvpz 26 | +UhSliO7QZZF+vGvd6PUWg5HsxS6m8eBehAMRUX5Yw8/01LmqbjsKtkeLnR0QKsp 27 | Ralg7LHgoCJU+uAl/x0rXUo= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /rsocket/src/frame/metadata_push.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use super::{Body, Frame}; 4 | use crate::utils::Writeable; 5 | 6 | #[derive(Debug, Eq, PartialEq)] 7 | pub struct MetadataPush { 8 | metadata: Option, 9 | } 10 | 11 | pub struct MetadataPushBuiler { 12 | stream_id: u32, 13 | flag: u16, 14 | value: MetadataPush, 15 | } 16 | 17 | impl MetadataPushBuiler { 18 | fn new(stream_id: u32, flag: u16) -> MetadataPushBuiler { 19 | MetadataPushBuiler { 20 | stream_id, 21 | flag, 22 | value: MetadataPush { metadata: None }, 23 | } 24 | } 25 | 26 | pub fn set_metadata(mut self, metadata: Bytes) -> Self { 27 | self.value.metadata = Some(metadata); 28 | self 29 | } 30 | 31 | pub fn build(self) -> Frame { 32 | Frame::new(self.stream_id, Body::MetadataPush(self.value), self.flag) 33 | } 34 | } 35 | 36 | impl MetadataPush { 37 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 38 | Ok(MetadataPush { 39 | metadata: Some(bf.split().freeze()), 40 | }) 41 | } 42 | 43 | pub fn builder(stream_id: u32, flag: u16) -> MetadataPushBuiler { 44 | MetadataPushBuiler::new(stream_id, flag) 45 | } 46 | 47 | pub fn get_metadata(&self) -> Option<&Bytes> { 48 | self.metadata.as_ref() 49 | } 50 | 51 | pub fn split(self) -> (Option, Option) { 52 | (None, self.metadata) 53 | } 54 | } 55 | 56 | impl Writeable for MetadataPush { 57 | fn write_to(&self, bf: &mut BytesMut) { 58 | match &self.metadata { 59 | Some(v) => bf.extend_from_slice(v), 60 | None => (), 61 | } 62 | } 63 | 64 | fn len(&self) -> usize { 65 | match &self.metadata { 66 | Some(v) => v.len(), 67 | None => 0, 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/server/tls.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use rsocket_rust::async_trait; 4 | use rsocket_rust::{error::RSocketError, transport::ServerTransport, Result}; 5 | use tokio::net::TcpListener; 6 | use tokio_native_tls::TlsAcceptor; 7 | 8 | use crate::client::TlsClientTransport; 9 | 10 | pub struct TlsServerTransport { 11 | addr: SocketAddr, 12 | listener: Option, 13 | tls_acceptor: TlsAcceptor, 14 | } 15 | 16 | impl TlsServerTransport { 17 | pub fn new(addr: SocketAddr, tls_acceptor: TlsAcceptor) -> Self { 18 | Self { 19 | addr, 20 | listener: None, 21 | tls_acceptor, 22 | } 23 | } 24 | } 25 | 26 | #[async_trait] 27 | impl ServerTransport for TlsServerTransport { 28 | type Item = TlsClientTransport; 29 | 30 | async fn start(&mut self) -> Result<()> { 31 | if self.listener.is_some() { 32 | return Ok(()); 33 | } 34 | match TcpListener::bind(self.addr).await { 35 | Ok(listener) => { 36 | self.listener = Some(listener); 37 | debug!("listening on: {}", &self.addr); 38 | Ok(()) 39 | } 40 | Err(e) => Err(RSocketError::IO(e).into()), 41 | } 42 | } 43 | 44 | async fn next(&mut self) -> Option> { 45 | match self.listener.as_mut() { 46 | Some(listener) => match listener.accept().await { 47 | Ok((socket, _)) => { 48 | let tls_acceptor = self.tls_acceptor.clone(); 49 | match tls_acceptor.accept(socket).await { 50 | Ok(stream) => Some(Ok(TlsClientTransport::from(stream))), 51 | Err(e) => Some(Err(RSocketError::Other(e.into()).into())), 52 | } 53 | } 54 | Err(e) => Some(Err(RSocketError::IO(e).into())), 55 | }, 56 | None => None, 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /rsocket-transport-websocket/README.md: -------------------------------------------------------------------------------- 1 | # RSocket Transport For Websocket 2 | 3 | ## Example 4 | 5 | Add dependencies in your `Cargo.toml`. 6 | 7 | ```toml 8 | [dependencies] 9 | tokio = "0.3.6" 10 | rsocket_rust = "0.7.0" 11 | rsocket_rust_transport_websocket = "0.7.0" 12 | ``` 13 | 14 | ### Server 15 | 16 | ```rust 17 | use log::info; 18 | use rsocket_rust::prelude::*; 19 | use rsocket_rust::utils::EchoRSocket; 20 | use rsocket_rust::Result; 21 | use rsocket_rust_transport_websocket::WebsocketServerTransport; 22 | 23 | #[tokio::main] 24 | async fn main() -> Result<()> { 25 | let transport: WebsocketServerTransport = WebsocketServerTransport::from("127.0.0.1:8080"); 26 | 27 | let responder: ServerResponder = Box::new(|setup, _socket| { 28 | info!("accept setup: {:?}", setup); 29 | Ok(Box::new(EchoRSocket)) 30 | // Or you can reject setup 31 | // Err(From::from("SETUP_NOT_ALLOW")) 32 | }); 33 | 34 | let on_start: Box = 35 | Box::new(|| info!("+++++++ echo server started! +++++++")); 36 | 37 | RSocketFactory::receive() 38 | .transport(transport) 39 | .acceptor(responder) 40 | .on_start(on_start) 41 | .serve() 42 | .await?; 43 | 44 | Ok(()) 45 | } 46 | 47 | ``` 48 | 49 | ### Client 50 | 51 | ```rust 52 | use log::info; 53 | use rsocket_rust::prelude::*; 54 | use rsocket_rust::Result; 55 | use rsocket_rust_transport_websocket::WebsocketClientTransport; 56 | 57 | #[tokio::main] 58 | async fn main() -> Result<()> { 59 | let client = RSocketFactory::connect() 60 | .transport(WebsocketClientTransport::from("127.0.0.1:8080")) 61 | .setup(Payload::from("READY!")) 62 | .mime_type("text/plain", "text/plain") 63 | .start() 64 | .await?; 65 | 66 | let request_payload = Payload::builder() 67 | .set_data_utf8("Hello World!") 68 | .set_metadata_utf8("Rust") 69 | .build(); 70 | 71 | let res = client.request_response(request_payload).await?; 72 | 73 | info!("got: {:?}", res); 74 | 75 | client.close(); 76 | 77 | Ok(()) 78 | } 79 | ``` 80 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/README.md: -------------------------------------------------------------------------------- 1 | # RSocket Transport For TCP 2 | 3 | ## Example 4 | 5 | Add dependencies in your `Cargo.toml`. 6 | 7 | ```toml 8 | [dependencies] 9 | tokio = "0.3.6" 10 | rsocket_rust = "0.7.0" 11 | rsocket_rust_transport_tcp = "0.7.0" 12 | ``` 13 | 14 | ### Server 15 | 16 | ```rust 17 | use log::info; 18 | use rsocket_rust::prelude::{RSocketFactory, ServerResponder}; 19 | use rsocket_rust::Result; 20 | use rsocket_rust::utils::EchoRSocket; 21 | use rsocket_rust_transport_tcp::TcpServerTransport; 22 | 23 | #[tokio::main] 24 | async fn main() -> Result<()> { 25 | let transport: TcpServerTransport = TcpServerTransport::from("127.0.0.1:7878"); 26 | 27 | let responder: ServerResponder = Box::new(|setup, _socket| { 28 | info!("accept setup: {:?}", setup); 29 | Ok(Box::new(EchoRSocket)) 30 | // Or you can reject setup 31 | // Err(From::from("SETUP_NOT_ALLOW")) 32 | }); 33 | 34 | let on_start: Box = 35 | Box::new(|| info!("+++++++ echo server started! +++++++")); 36 | 37 | RSocketFactory::receive() 38 | .transport(transport) 39 | .acceptor(responder) 40 | .on_start(on_start) 41 | .serve() 42 | .await?; 43 | 44 | Ok(()) 45 | } 46 | 47 | ``` 48 | 49 | ### Client 50 | 51 | ```rust 52 | use log::info; 53 | use rsocket_rust::prelude::{ClientResponder, Payload, RSocket, RSocketFactory}; 54 | use rsocket_rust::Result; 55 | use rsocket_rust_transport_tcp::TcpClientTransport; 56 | 57 | #[tokio::main] 58 | async fn main() -> Result<()> { 59 | let client = RSocketFactory::connect() 60 | .transport(TcpClientTransport::from("127.0.0.1:7878")) 61 | .setup(Payload::from("READY!")) 62 | .mime_type("text/plain", "text/plain") 63 | .start() 64 | .await?; 65 | 66 | let request_payload: Payload = Payload::builder() 67 | .set_data_utf8("Hello World!") 68 | .set_metadata_utf8("Rust") 69 | .build(); 70 | 71 | let res = client.request_response(request_payload).await?; 72 | 73 | info!("got: {:?}", res); 74 | 75 | client.close(); 76 | 77 | Ok(()) 78 | } 79 | 80 | ``` 81 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/server/tcp.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use rsocket_rust::async_trait; 4 | use rsocket_rust::{error::RSocketError, transport::ServerTransport, Result}; 5 | use tokio::net::TcpListener; 6 | 7 | use crate::{client::TcpClientTransport, misc::parse_tcp_addr}; 8 | 9 | #[derive(Debug)] 10 | pub struct TcpServerTransport { 11 | addr: SocketAddr, 12 | listener: Option, 13 | } 14 | 15 | impl TcpServerTransport { 16 | fn new(addr: SocketAddr) -> TcpServerTransport { 17 | TcpServerTransport { 18 | addr, 19 | listener: None, 20 | } 21 | } 22 | } 23 | 24 | #[async_trait] 25 | impl ServerTransport for TcpServerTransport { 26 | type Item = TcpClientTransport; 27 | 28 | async fn start(&mut self) -> Result<()> { 29 | if self.listener.is_some() { 30 | return Ok(()); 31 | } 32 | match TcpListener::bind(self.addr).await { 33 | Ok(listener) => { 34 | self.listener = Some(listener); 35 | debug!("listening on: {}", &self.addr); 36 | Ok(()) 37 | } 38 | Err(e) => Err(RSocketError::IO(e).into()), 39 | } 40 | } 41 | 42 | async fn next(&mut self) -> Option> { 43 | match self.listener.as_mut() { 44 | Some(listener) => match listener.accept().await { 45 | Ok((socket, _)) => Some(Ok(TcpClientTransport::from(socket))), 46 | Err(e) => Some(Err(RSocketError::IO(e).into())), 47 | }, 48 | None => None, 49 | } 50 | } 51 | } 52 | 53 | impl From for TcpServerTransport { 54 | fn from(addr: SocketAddr) -> TcpServerTransport { 55 | TcpServerTransport::new(addr) 56 | } 57 | } 58 | 59 | impl From for TcpServerTransport { 60 | fn from(addr: String) -> TcpServerTransport { 61 | TcpServerTransport::new(parse_tcp_addr(addr).parse().unwrap()) 62 | } 63 | } 64 | 65 | impl From<&str> for TcpServerTransport { 66 | fn from(addr: &str) -> TcpServerTransport { 67 | TcpServerTransport::new(parse_tcp_addr(addr).parse().unwrap()) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [unreleased] 6 | 7 | ### Features 8 | 9 | - Support custom websocket request (#52) 10 | - Use rust 2021 edition (#54) 11 | - Add support for wss (TLS) connections for clients (#62) 12 | 13 | ### Miscellaneous Tasks 14 | 15 | - Use dependabot (#56) 16 | - Make clippy happy (#55) 17 | 18 | ## [0.7.2] - 2021-09-01 19 | 20 | ### Bug Fixes 21 | 22 | - Check send error 23 | 24 | ### Features 25 | 26 | - Use cfg_if and once_cell 27 | - Add some macros 28 | - Implemented cancel frame handling (#49) 29 | 30 | ### Miscellaneous Tasks 31 | 32 | - Upgrade version to 0.7.1 33 | - Update examples 34 | - Upgrade deps 35 | - Update dependencies for readme (#46) 36 | - Update example code in readme (#47) 37 | - Upgrade to 0.7.2 (#50) 38 | 39 | ## [0.7.0] - 2021-01-14 40 | 41 | ### Bug Fixes 42 | 43 | - Remove useless examples 44 | - Simplify Option convert 45 | - Register client-side responder correctly (#36) 46 | 47 | ### Features 48 | 49 | - Redesign RSocket trait based on async_trait 50 | - Handle empty response correctly 51 | - Implment tls transport (#31) 52 | - Change transport api (#35) 53 | - Migrate to tokio v1 54 | - Close connection correctly when client is dropped (#40) 55 | 56 | ### Miscellaneous Tasks 57 | 58 | - Bump tokio to v0.3.6 59 | - Fix readme 60 | - Add RSocket trait example in readme 61 | - Use mkcert to generate TLS example certificates and keys (#38) 62 | - Optimize import (#39) 63 | - Config chglog (#41) 64 | - Update deps (#42) 65 | 66 | ## [0.6.0] - 2020-12-13 67 | 68 | ### Bug Fixes 69 | 70 | - Optimize bytes write action (#24) 71 | - Convert bytes to utf8 safely (#27) 72 | 73 | ### Features 74 | 75 | - Support tokio v0.3.x (#23) 76 | - Implement client-side keepalive (#25) 77 | 78 | ### Miscellaneous Tasks 79 | 80 | - Use gh actions instead of travis (#22) 81 | - Upgrade deps 82 | - Prelease 0.6 83 | 84 | ### Refactor 85 | 86 | - Use thiserror & anyhow as error struct (#20) 87 | 88 | ## [0.4.0] - 2019-12-24 89 | 90 | ### Bugfix 91 | 92 | - Response payload of REQUEST_RESPONSE will be sent with NEXT|COMPLETE flag. 93 | 94 | 95 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/server/uds.rs: -------------------------------------------------------------------------------- 1 | use rsocket_rust::async_trait; 2 | use rsocket_rust::{error::RSocketError, transport::ServerTransport, Result}; 3 | use tokio::net::UnixListener; 4 | 5 | use crate::client::UnixClientTransport; 6 | use crate::misc::parse_uds_addr; 7 | 8 | #[derive(Debug)] 9 | pub struct UnixServerTransport { 10 | addr: String, 11 | listener: Option, 12 | } 13 | 14 | impl UnixServerTransport { 15 | fn new(addr: String) -> UnixServerTransport { 16 | UnixServerTransport { 17 | addr, 18 | listener: None, 19 | } 20 | } 21 | } 22 | 23 | #[async_trait] 24 | impl ServerTransport for UnixServerTransport { 25 | type Item = UnixClientTransport; 26 | 27 | async fn start(&mut self) -> Result<()> { 28 | if self.listener.is_some() { 29 | return Ok(()); 30 | } 31 | match UnixListener::bind(&self.addr) { 32 | Ok(listener) => { 33 | self.listener = Some(listener); 34 | debug!("listening on: {}", &self.addr); 35 | Ok(()) 36 | } 37 | Err(e) => Err(RSocketError::IO(e).into()), 38 | } 39 | } 40 | 41 | async fn next(&mut self) -> Option> { 42 | match self.listener.as_mut() { 43 | Some(listener) => match listener.accept().await { 44 | Ok((socket, _)) => Some(Ok(UnixClientTransport::from(socket))), 45 | Err(e) => Some(Err(RSocketError::IO(e).into())), 46 | }, 47 | None => None, 48 | } 49 | } 50 | } 51 | 52 | impl Drop for UnixServerTransport { 53 | fn drop(&mut self) { 54 | if let Err(e) = std::fs::remove_file(&self.addr) { 55 | warn!("remove unix sock file failed: {}", e); 56 | } 57 | } 58 | } 59 | 60 | impl From for UnixServerTransport { 61 | fn from(addr: String) -> UnixServerTransport { 62 | UnixServerTransport::new(parse_uds_addr(addr)) 63 | } 64 | } 65 | 66 | impl From<&str> for UnixServerTransport { 67 | fn from(addr: &str) -> UnixServerTransport { 68 | UnixServerTransport::new(parse_uds_addr(addr)) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /rsocket-transport-tcp/src/client/tcp.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use rsocket_rust::async_trait; 4 | use rsocket_rust::{error::RSocketError, transport::Transport, Result}; 5 | use tokio::net::TcpStream; 6 | 7 | use crate::{connection::TcpConnection, misc::parse_tcp_addr}; 8 | 9 | #[derive(Debug)] 10 | enum Connector { 11 | Direct(TcpStream), 12 | Lazy(SocketAddr), 13 | } 14 | 15 | #[derive(Debug)] 16 | pub struct TcpClientTransport { 17 | connector: Connector, 18 | } 19 | 20 | #[async_trait] 21 | impl Transport for TcpClientTransport { 22 | type Conn = TcpConnection; 23 | 24 | async fn connect(self) -> Result { 25 | match self.connector { 26 | Connector::Direct(socket) => Ok(TcpConnection::from(socket)), 27 | Connector::Lazy(addr) => match TcpStream::connect(addr).await { 28 | Ok(stream) => Ok(TcpConnection::from(stream)), 29 | Err(e) => Err(RSocketError::IO(e).into()), 30 | }, 31 | } 32 | } 33 | } 34 | 35 | impl From for TcpClientTransport { 36 | fn from(socket: TcpStream) -> TcpClientTransport { 37 | TcpClientTransport { 38 | connector: Connector::Direct(socket), 39 | } 40 | } 41 | } 42 | 43 | impl From for TcpClientTransport { 44 | fn from(addr: SocketAddr) -> TcpClientTransport { 45 | TcpClientTransport { 46 | connector: Connector::Lazy(addr), 47 | } 48 | } 49 | } 50 | 51 | impl From for TcpClientTransport { 52 | fn from(addr: String) -> Self { 53 | let socket_addr: SocketAddr = parse_tcp_addr(addr) 54 | .parse() 55 | .expect("Invalid transport string!"); 56 | TcpClientTransport { 57 | connector: Connector::Lazy(socket_addr), 58 | } 59 | } 60 | } 61 | 62 | impl From<&str> for TcpClientTransport { 63 | fn from(addr: &str) -> TcpClientTransport { 64 | let socket_addr: SocketAddr = parse_tcp_addr(addr) 65 | .parse() 66 | .expect("Invalid transport string!"); 67 | TcpClientTransport { 68 | connector: Connector::Lazy(socket_addr), 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /rsocket/src/spi.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | use std::pin::Pin; 3 | 4 | use async_trait::async_trait; 5 | use futures::Stream; 6 | 7 | use crate::payload::{Payload, SetupPayload}; 8 | use crate::Result; 9 | 10 | pub type ClientResponder = Box Box>; 11 | pub type ServerResponder = 12 | Box) -> Result>>; 13 | 14 | pub type Flux = Pin>>; 15 | 16 | /// A contract providing different interaction models for RSocket protocol. 17 | /// 18 | /// RSocket trait is based on `async_trait` crate. 19 | /// 20 | /// # Example 21 | /// ``` 22 | /// use rsocket_rust::prelude::*; 23 | /// use rsocket_rust::{async_trait, stream, Result}; 24 | /// 25 | /// struct ExampleRSocket; 26 | /// 27 | /// #[async_trait] 28 | /// impl RSocket for ExampleRSocket { 29 | /// async fn metadata_push(&self, req: Payload) -> Result<()> { 30 | /// Ok(()) 31 | /// } 32 | /// 33 | /// async fn fire_and_forget(&self, req: Payload) -> Result<()> { 34 | /// Ok(()) 35 | /// } 36 | /// 37 | /// async fn request_response(&self, req: Payload) -> Result> { 38 | /// Ok(Some(Payload::builder().set_data_utf8("bingo").build())) 39 | /// } 40 | /// 41 | /// fn request_stream(&self, req: Payload) -> Flux> { 42 | /// Box::pin(stream! { 43 | /// for _ in 0..3 { 44 | /// yield Ok(Payload::builder().set_data_utf8("next payload").build()); 45 | /// } 46 | /// }) 47 | /// } 48 | /// 49 | /// fn request_channel(&self, reqs: Flux>) -> Flux> { 50 | /// reqs 51 | /// } 52 | /// } 53 | /// ``` 54 | #[async_trait] 55 | pub trait RSocket: Sync + Send { 56 | /// Metadata-Push interaction model of RSocket. 57 | async fn metadata_push(&self, req: Payload) -> Result<()>; 58 | /// Fire and Forget interaction model of RSocket. 59 | async fn fire_and_forget(&self, req: Payload) -> Result<()>; 60 | /// Request-Response interaction model of RSocket. 61 | async fn request_response(&self, req: Payload) -> Result>; 62 | /// Request-Stream interaction model of RSocket. 63 | fn request_stream(&self, req: Payload) -> Flux>; 64 | /// Request-Channel interaction model of RSocket. 65 | fn request_channel(&self, reqs: Flux>) -> Flux>; 66 | } 67 | -------------------------------------------------------------------------------- /rsocket/src/frame/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 4 | 5 | use super::{Body, Frame}; 6 | use crate::error::RSocketError; 7 | use crate::utils::Writeable; 8 | 9 | #[derive(Debug, Eq, PartialEq)] 10 | pub struct Error { 11 | code: u32, 12 | data: Option, 13 | } 14 | 15 | pub struct ErrorBuilder { 16 | stream_id: u32, 17 | flag: u16, 18 | value: Error, 19 | } 20 | 21 | impl ErrorBuilder { 22 | fn new(stream_id: u32, flag: u16) -> ErrorBuilder { 23 | ErrorBuilder { 24 | stream_id, 25 | flag, 26 | value: Error { 27 | code: 0, 28 | data: None, 29 | }, 30 | } 31 | } 32 | 33 | pub fn set_code(mut self, code: u32) -> Self { 34 | self.value.code = code; 35 | self 36 | } 37 | 38 | pub fn set_data(mut self, data: Bytes) -> Self { 39 | self.value.data = Some(data); 40 | self 41 | } 42 | 43 | pub fn build(self) -> Frame { 44 | Frame::new(self.stream_id, Body::Error(self.value), self.flag) 45 | } 46 | } 47 | 48 | impl Error { 49 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 50 | if bf.len() < 4 { 51 | Err(RSocketError::InCompleteFrame.into()) 52 | } else { 53 | let code = bf.get_u32(); 54 | let data: Option = if !bf.is_empty() { 55 | Some(bf.split().freeze()) 56 | } else { 57 | None 58 | }; 59 | Ok(Error { code, data }) 60 | } 61 | } 62 | 63 | pub fn builder(stream_id: u32, flag: u16) -> ErrorBuilder { 64 | ErrorBuilder::new(stream_id, flag) 65 | } 66 | 67 | pub fn get_data_utf8(&self) -> Option<&str> { 68 | match &self.data { 69 | Some(b) => std::str::from_utf8(b).ok(), 70 | None => None, 71 | } 72 | } 73 | 74 | pub fn get_data(&self) -> Option<&Bytes> { 75 | self.data.as_ref() 76 | } 77 | 78 | pub fn get_code(&self) -> u32 { 79 | self.code 80 | } 81 | } 82 | 83 | impl Writeable for Error { 84 | fn write_to(&self, bf: &mut BytesMut) { 85 | bf.put_u32(self.code); 86 | match &self.data { 87 | Some(v) => bf.extend_from_slice(v), 88 | None => (), 89 | } 90 | } 91 | 92 | fn len(&self) -> usize { 93 | 4 + match &self.data { 94 | Some(v) => v.len(), 95 | None => 0, 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /rsocket/src/extension/routing.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use crate::error::RSocketError; 4 | use crate::utils::Writeable; 5 | 6 | const MAX_ROUTING_TAG_LEN: usize = 0xFF; 7 | 8 | #[derive(Debug, Clone)] 9 | pub struct RoutingMetadata { 10 | tags: Vec, 11 | } 12 | 13 | pub struct RoutingMetadataBuilder { 14 | inner: RoutingMetadata, 15 | } 16 | 17 | impl RoutingMetadataBuilder { 18 | pub fn push_str(self, tag: &str) -> Self { 19 | self.push(String::from(tag)) 20 | } 21 | pub fn push(mut self, tag: String) -> Self { 22 | assert!( 23 | tag.len() <= MAX_ROUTING_TAG_LEN, 24 | "exceeded maximum routing tag length!" 25 | ); 26 | self.inner.tags.push(tag); 27 | self 28 | } 29 | pub fn build(self) -> RoutingMetadata { 30 | self.inner 31 | } 32 | } 33 | 34 | impl RoutingMetadata { 35 | pub fn builder() -> RoutingMetadataBuilder { 36 | RoutingMetadataBuilder { 37 | inner: RoutingMetadata { tags: vec![] }, 38 | } 39 | } 40 | 41 | pub fn decode(bf: &mut BytesMut) -> crate::Result { 42 | let mut bu = RoutingMetadata::builder(); 43 | loop { 44 | match Self::decode_once(bf) { 45 | Ok(v) => match v { 46 | Some(tag) => bu = bu.push(tag), 47 | None => break, 48 | }, 49 | Err(e) => return Err(e), 50 | } 51 | } 52 | Ok(bu.build()) 53 | } 54 | 55 | pub fn get_tags(&self) -> &Vec { 56 | &self.tags 57 | } 58 | 59 | fn decode_once(bf: &mut BytesMut) -> crate::Result> { 60 | if bf.is_empty() { 61 | return Ok(None); 62 | } 63 | let size = bf.get_u8() as usize; 64 | if bf.len() < size { 65 | return Err(RSocketError::WithDescription("require more bytes!".into()).into()); 66 | } 67 | let tag = String::from_utf8(bf.split_to(size).to_vec())?; 68 | Ok(Some(tag)) 69 | } 70 | } 71 | 72 | impl Writeable for RoutingMetadata { 73 | fn write_to(&self, bf: &mut BytesMut) { 74 | for tag in &self.tags { 75 | let size = tag.len() as u8; 76 | bf.put_u8(size); 77 | bf.put_slice(tag.as_bytes()); 78 | } 79 | } 80 | 81 | fn len(&self) -> usize { 82 | let mut n = 0; 83 | for tag in &self.tags { 84 | n += 1 + tag.as_bytes().len(); 85 | } 86 | n 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /rsocket-transport-websocket/src/server.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use rsocket_rust::{async_trait, error::RSocketError, transport::ServerTransport, Result}; 4 | use tokio::net::TcpListener; 5 | 6 | use super::client::WebsocketClientTransport; 7 | 8 | const WS_PROTO: &str = "ws://"; 9 | 10 | #[derive(Debug)] 11 | pub struct WebsocketServerTransport { 12 | addr: SocketAddr, 13 | listener: Option, 14 | } 15 | 16 | #[async_trait] 17 | impl ServerTransport for WebsocketServerTransport { 18 | type Item = WebsocketClientTransport; 19 | 20 | async fn start(&mut self) -> Result<()> { 21 | if self.listener.is_some() { 22 | warn!("websocket server transport started already!"); 23 | return Ok(()); 24 | } 25 | match TcpListener::bind(self.addr).await { 26 | Ok(listener) => { 27 | self.listener = Some(listener); 28 | Ok(()) 29 | } 30 | Err(e) => Err(RSocketError::IO(e).into()), 31 | } 32 | } 33 | 34 | async fn next(&mut self) -> Option> { 35 | match self.listener.as_mut() { 36 | Some(listener) => match listener.accept().await { 37 | Ok((socket, _)) => Some(Ok(WebsocketClientTransport::from(socket))), 38 | Err(e) => Some(Err(RSocketError::Other(e.into()).into())), 39 | }, 40 | None => None, 41 | } 42 | } 43 | } 44 | 45 | #[inline] 46 | fn parse_socket_addr(addr: impl AsRef) -> SocketAddr { 47 | let addr = addr.as_ref(); 48 | if addr.starts_with(WS_PROTO) { 49 | addr.chars() 50 | .skip(WS_PROTO.len()) 51 | .collect::() 52 | .parse() 53 | } else { 54 | addr.parse() 55 | } 56 | .expect("Invalid transport string!") 57 | } 58 | 59 | impl From for WebsocketServerTransport { 60 | fn from(addr: SocketAddr) -> WebsocketServerTransport { 61 | WebsocketServerTransport { 62 | addr, 63 | listener: None, 64 | } 65 | } 66 | } 67 | 68 | impl From for WebsocketServerTransport { 69 | fn from(addr: String) -> WebsocketServerTransport { 70 | WebsocketServerTransport { 71 | addr: parse_socket_addr(addr), 72 | listener: None, 73 | } 74 | } 75 | } 76 | 77 | impl From<&str> for WebsocketServerTransport { 78 | fn from(addr: &str) -> WebsocketServerTransport { 79 | WebsocketServerTransport { 80 | addr: parse_socket_addr(addr), 81 | listener: None, 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /rsocket/src/frame/keepalive.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use super::{Body, Frame}; 4 | use crate::error::RSocketError; 5 | use crate::utils::Writeable; 6 | 7 | #[derive(Debug, Eq, PartialEq)] 8 | pub struct Keepalive { 9 | last_received_position: u64, 10 | data: Option, 11 | } 12 | 13 | pub struct KeepaliveBuilder { 14 | stream_id: u32, 15 | flag: u16, 16 | keepalive: Keepalive, 17 | } 18 | 19 | impl KeepaliveBuilder { 20 | fn new(stream_id: u32, flag: u16) -> KeepaliveBuilder { 21 | KeepaliveBuilder { 22 | stream_id, 23 | flag, 24 | keepalive: Keepalive { 25 | last_received_position: 0, 26 | data: None, 27 | }, 28 | } 29 | } 30 | 31 | pub fn set_data(mut self, data: Bytes) -> Self { 32 | self.keepalive.data = Some(data); 33 | self 34 | } 35 | 36 | pub fn set_last_received_position(mut self, position: u64) -> Self { 37 | self.keepalive.last_received_position = position; 38 | self 39 | } 40 | 41 | pub fn build(self) -> Frame { 42 | Frame::new(self.stream_id, Body::Keepalive(self.keepalive), self.flag) 43 | } 44 | } 45 | 46 | impl Keepalive { 47 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 48 | if bf.len() < 8 { 49 | return Err(RSocketError::InCompleteFrame.into()); 50 | } 51 | let position = bf.get_u64(); 52 | let data = if bf.is_empty() { 53 | None 54 | } else { 55 | Some(bf.split().freeze()) 56 | }; 57 | Ok(Keepalive { 58 | last_received_position: position, 59 | data, 60 | }) 61 | } 62 | 63 | pub fn builder(stream_id: u32, flag: u16) -> KeepaliveBuilder { 64 | KeepaliveBuilder::new(stream_id, flag) 65 | } 66 | 67 | pub fn get_last_received_position(&self) -> u64 { 68 | self.last_received_position 69 | } 70 | 71 | pub fn get_data(&self) -> Option<&Bytes> { 72 | self.data.as_ref() 73 | } 74 | 75 | pub fn split(self) -> (Option, Option) { 76 | (self.data, None) 77 | } 78 | } 79 | 80 | impl Writeable for Keepalive { 81 | fn write_to(&self, bf: &mut BytesMut) { 82 | bf.put_u64(self.last_received_position); 83 | match &self.data { 84 | Some(v) => bf.extend_from_slice(v), 85 | None => (), 86 | } 87 | } 88 | 89 | fn len(&self) -> usize { 90 | 8 + match &self.data { 91 | Some(v) => v.len(), 92 | None => 0, 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /rsocket/src/frame/payload.rs: -------------------------------------------------------------------------------- 1 | use bytes::{BufMut, Bytes, BytesMut}; 2 | 3 | use super::utils; 4 | use super::{Body, Frame}; 5 | use crate::utils::Writeable; 6 | use crate::Result; 7 | 8 | #[derive(Debug, Eq, PartialEq)] 9 | pub struct Payload { 10 | metadata: Option, 11 | data: Option, 12 | } 13 | 14 | pub struct PayloadBuilder { 15 | stream_id: u32, 16 | flag: u16, 17 | value: Payload, 18 | } 19 | 20 | impl PayloadBuilder { 21 | fn new(stream_id: u32, flag: u16) -> PayloadBuilder { 22 | PayloadBuilder { 23 | stream_id, 24 | flag, 25 | value: Payload { 26 | metadata: None, 27 | data: None, 28 | }, 29 | } 30 | } 31 | 32 | pub fn set_all(mut self, data_and_metadata: (Option, Option)) -> Self { 33 | self.value.data = data_and_metadata.0; 34 | match data_and_metadata.1 { 35 | Some(m) => { 36 | self.value.metadata = Some(m); 37 | self.flag |= Frame::FLAG_METADATA; 38 | } 39 | None => { 40 | self.value.metadata = None; 41 | self.flag &= !Frame::FLAG_METADATA; 42 | } 43 | } 44 | self 45 | } 46 | 47 | pub fn set_data(mut self, data: Bytes) -> Self { 48 | self.value.data = Some(data); 49 | self 50 | } 51 | 52 | pub fn set_metadata(mut self, metadata: Bytes) -> Self { 53 | self.value.metadata = Some(metadata); 54 | self.flag |= Frame::FLAG_METADATA; 55 | self 56 | } 57 | 58 | pub fn build(self) -> Frame { 59 | Frame::new(self.stream_id, Body::Payload(self.value), self.flag) 60 | } 61 | } 62 | 63 | impl Payload { 64 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> Result { 65 | utils::read_payload(flag, bf).map(|(metadata, data)| Payload { metadata, data }) 66 | } 67 | 68 | pub fn builder(stream_id: u32, flag: u16) -> PayloadBuilder { 69 | PayloadBuilder::new(stream_id, flag) 70 | } 71 | 72 | pub fn get_metadata(&self) -> Option<&Bytes> { 73 | self.metadata.as_ref() 74 | } 75 | 76 | pub fn get_data(&self) -> Option<&Bytes> { 77 | self.data.as_ref() 78 | } 79 | 80 | pub fn split(self) -> (Option, Option) { 81 | (self.data, self.metadata) 82 | } 83 | } 84 | 85 | impl Writeable for Payload { 86 | fn write_to(&self, bf: &mut BytesMut) { 87 | utils::write_payload(bf, self.get_metadata(), self.get_data()); 88 | } 89 | 90 | fn len(&self) -> usize { 91 | utils::calculate_payload_length(self.get_metadata(), self.get_data()) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /rsocket/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::io; 3 | 4 | use thiserror::Error; 5 | 6 | pub const ERR_INVALID_SETUP: u32 = 0x0000_0001; 7 | pub const ERR_UNSUPPORTED_SETUP: u32 = 0x0000_0002; 8 | pub const ERR_REJECT_SETUP: u32 = 0x0000_0003; 9 | pub const ERR_REJECT_RESUME: u32 = 0x0000_0004; 10 | pub const ERR_CONN_FAILED: u32 = 0x0000_0101; 11 | pub const ERR_CONN_CLOSED: u32 = 0x0000_0102; 12 | pub const ERR_APPLICATION: u32 = 0x0000_0201; 13 | pub const ERR_REJECTED: u32 = 0x0000_0202; 14 | pub const ERR_CANCELED: u32 = 0x0000_0203; 15 | pub const ERR_INVALID: u32 = 0x0000_0204; 16 | 17 | #[derive(Error, Debug)] 18 | pub enum RSocketError { 19 | // Protocol errors: 20 | #[error("INVALID_SETUP: {0}")] 21 | InvalidSetup(String), 22 | #[error("UNSUPPORTED_SETUP: {0}")] 23 | UnsupportedSetup(String), 24 | #[error("REJECTED_SETUP: {0}")] 25 | RejectedSetup(String), 26 | #[error("REJECTED_SETUP: {0}")] 27 | RejectedResume(String), 28 | #[error("CONNECTION_ERROR: {0}")] 29 | ConnectionException(String), 30 | #[error("CONNECTION_CLOSE: {0}")] 31 | ConnectionClosed(String), 32 | #[error("APPLICATION_ERROR: {0}")] 33 | ApplicationException(String), 34 | #[error("REJECTED: {0}")] 35 | RequestRejected(String), 36 | #[error("CANCELLED: {0}")] 37 | RequestCancelled(String), 38 | #[error("INVALID: {0}")] 39 | RequestInvalid(String), 40 | #[error("RESERVED({0}): {1}")] 41 | Reserved(u32, String), 42 | 43 | // Codec errors: 44 | #[error("this frame is incomplete")] 45 | InCompleteFrame, 46 | // Custom errors: 47 | #[error("{0}")] 48 | WithDescription(String), 49 | #[error(transparent)] 50 | IO(#[from] io::Error), 51 | #[error(transparent)] 52 | Other(#[from] anyhow::Error), 53 | } 54 | 55 | impl RSocketError { 56 | pub(crate) fn must_new_from_code(code: u32, desc: String) -> Self { 57 | match code { 58 | ERR_APPLICATION => RSocketError::ApplicationException(desc), 59 | ERR_INVALID_SETUP => RSocketError::InvalidSetup(desc), 60 | ERR_UNSUPPORTED_SETUP => RSocketError::UnsupportedSetup(desc), 61 | ERR_REJECT_SETUP => RSocketError::RejectedSetup(desc), 62 | ERR_REJECT_RESUME => RSocketError::RejectedResume(desc), 63 | ERR_CONN_FAILED => RSocketError::ConnectionException(desc), 64 | ERR_CONN_CLOSED => RSocketError::ConnectionClosed(desc), 65 | ERR_REJECTED => RSocketError::RequestRejected(desc), 66 | ERR_CANCELED => RSocketError::RequestCancelled(desc), 67 | ERR_INVALID => RSocketError::RequestInvalid(desc), 68 | _ => RSocketError::Reserved(code, desc), 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /rsocket/src/frame/request_fnf.rs: -------------------------------------------------------------------------------- 1 | use bytes::{BufMut, Bytes, BytesMut}; 2 | 3 | use super::{utils, Body, Frame}; 4 | use crate::utils::Writeable; 5 | 6 | #[derive(Debug, Eq, PartialEq)] 7 | pub struct RequestFNF { 8 | metadata: Option, 9 | data: Option, 10 | } 11 | 12 | pub struct RequestFNFBuilder { 13 | stream_id: u32, 14 | flag: u16, 15 | value: RequestFNF, 16 | } 17 | 18 | impl RequestFNFBuilder { 19 | fn new(stream_id: u32, flag: u16) -> RequestFNFBuilder { 20 | RequestFNFBuilder { 21 | stream_id, 22 | flag, 23 | value: RequestFNF { 24 | metadata: None, 25 | data: None, 26 | }, 27 | } 28 | } 29 | 30 | pub fn build(self) -> Frame { 31 | Frame::new(self.stream_id, Body::RequestFNF(self.value), self.flag) 32 | } 33 | 34 | pub fn set_metadata(mut self, metadata: Bytes) -> Self { 35 | self.value.metadata = Some(metadata); 36 | self.flag |= Frame::FLAG_METADATA; 37 | self 38 | } 39 | 40 | pub fn set_data(mut self, data: Bytes) -> Self { 41 | self.value.data = Some(data); 42 | self 43 | } 44 | 45 | pub fn set_all(mut self, data_and_metadata: (Option, Option)) -> Self { 46 | self.value.data = data_and_metadata.0; 47 | match data_and_metadata.1 { 48 | Some(m) => { 49 | self.value.metadata = Some(m); 50 | self.flag |= Frame::FLAG_METADATA; 51 | } 52 | None => { 53 | self.value.metadata = None; 54 | self.flag &= !Frame::FLAG_METADATA; 55 | } 56 | } 57 | self 58 | } 59 | } 60 | 61 | impl RequestFNF { 62 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 63 | utils::read_payload(flag, bf).map(|(m, d)| RequestFNF { 64 | metadata: m, 65 | data: d, 66 | }) 67 | } 68 | 69 | pub fn builder(stream_id: u32, flag: u16) -> RequestFNFBuilder { 70 | RequestFNFBuilder::new(stream_id, flag) 71 | } 72 | 73 | pub fn get_metadata(&self) -> Option<&Bytes> { 74 | self.metadata.as_ref() 75 | } 76 | 77 | pub fn get_data(&self) -> Option<&Bytes> { 78 | self.data.as_ref() 79 | } 80 | 81 | pub fn split(self) -> (Option, Option) { 82 | (self.data, self.metadata) 83 | } 84 | } 85 | 86 | impl Writeable for RequestFNF { 87 | fn write_to(&self, bf: &mut BytesMut) { 88 | utils::write_payload(bf, self.get_metadata(), self.get_data()); 89 | } 90 | 91 | fn len(&self) -> usize { 92 | utils::calculate_payload_length(self.get_metadata(), self.get_data()) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rsocket-test/tests/test_messaging.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | #[macro_use] 4 | extern crate serde_derive; 5 | 6 | use rsocket_rust::extension::MimeType; 7 | use rsocket_rust_messaging::*; 8 | 9 | fn init() { 10 | let _ = env_logger::builder() 11 | .format_timestamp_millis() 12 | .is_test(true) 13 | .try_init(); 14 | } 15 | 16 | #[derive(Serialize, Deserialize, Debug, Default)] 17 | pub struct Token { 18 | app: String, 19 | access: String, 20 | } 21 | 22 | #[derive(Serialize, Deserialize, Debug, Default)] 23 | pub struct Student { 24 | id: i64, 25 | name: String, 26 | birth: String, 27 | } 28 | 29 | #[derive(Serialize, Deserialize, Debug, Default)] 30 | pub struct Tracing { 31 | id: String, 32 | ts: i64, 33 | } 34 | 35 | #[derive(Serialize, Deserialize, Debug)] 36 | pub struct Response { 37 | code: i32, 38 | message: Option, 39 | data: T, 40 | } 41 | 42 | #[tokio::main] 43 | #[test] 44 | #[ignore] 45 | async fn test_messaging() { 46 | init(); 47 | let token = || Token { 48 | app: "xxx".to_owned(), 49 | access: "yyy".to_owned(), 50 | }; 51 | let requester = Requester::builder() 52 | .setup_metadata(token(), MimeType::APPLICATION_JSON) 53 | .setup_data(token()) 54 | .connect_tcp("127.0.0.1", 7878) 55 | .build() 56 | .await 57 | .expect("Connect failed!"); 58 | 59 | // TEST MONO BEGIN 60 | let res: Response = requester 61 | .route("student.v1.upsert") 62 | .metadata(Tracing::default(), "application/json") 63 | .metadata_raw("foobar", "message/x.rsocket.authentication.bearer.v0") 64 | .data(next_post()) 65 | .retrieve_mono() 66 | .await 67 | .block() 68 | .expect("Retrieve failed!") 69 | .expect("Empty result!"); 70 | info!("------> RESPONSE: {:?}", res); 71 | 72 | // TEST FLUX BEGIN 73 | let res: Vec = requester 74 | .route("students.v1") 75 | .data(next_post()) 76 | .retrieve_flux() 77 | .block() 78 | .await 79 | .expect("Retrieve failed!"); 80 | for it in res.iter() { 81 | info!("===> NEXT: {:?}", it); 82 | } 83 | requester 84 | .route("students.v1") 85 | .data(next_post()) 86 | .retrieve_flux() 87 | .foreach(|it: Student| { 88 | info!("===> FOREACH: {:?}", it); 89 | }) 90 | .await 91 | .expect("Retrieve failed!"); 92 | } 93 | 94 | fn next_post() -> Student { 95 | Student { 96 | id: 1234, 97 | name: "Jeffsky".to_owned(), 98 | birth: "2020-01-01".to_owned(), 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /rsocket/src/frame/request_response.rs: -------------------------------------------------------------------------------- 1 | use bytes::{BufMut, Bytes, BytesMut}; 2 | 3 | use super::{utils, Body, Frame}; 4 | use crate::utils::Writeable; 5 | 6 | #[derive(Debug, Eq, PartialEq)] 7 | pub struct RequestResponse { 8 | metadata: Option, 9 | data: Option, 10 | } 11 | 12 | pub struct RequestResponseBuilder { 13 | stream_id: u32, 14 | flag: u16, 15 | value: RequestResponse, 16 | } 17 | 18 | impl RequestResponseBuilder { 19 | fn new(stream_id: u32, flag: u16) -> RequestResponseBuilder { 20 | RequestResponseBuilder { 21 | stream_id, 22 | flag, 23 | value: RequestResponse { 24 | metadata: None, 25 | data: None, 26 | }, 27 | } 28 | } 29 | 30 | pub fn set_all(mut self, data_and_metadata: (Option, Option)) -> Self { 31 | self.value.data = data_and_metadata.0; 32 | match data_and_metadata.1 { 33 | Some(m) => { 34 | self.value.metadata = Some(m); 35 | self.flag |= Frame::FLAG_METADATA; 36 | } 37 | None => { 38 | self.value.metadata = None; 39 | self.flag &= !Frame::FLAG_METADATA; 40 | } 41 | } 42 | self 43 | } 44 | 45 | pub fn set_metadata(mut self, metadata: Bytes) -> Self { 46 | self.value.metadata = Some(metadata); 47 | self.flag |= Frame::FLAG_METADATA; 48 | self 49 | } 50 | 51 | pub fn set_data(mut self, data: Bytes) -> Self { 52 | self.value.data = Some(data); 53 | self 54 | } 55 | 56 | pub fn build(self) -> Frame { 57 | Frame::new(self.stream_id, Body::RequestResponse(self.value), self.flag) 58 | } 59 | } 60 | 61 | impl RequestResponse { 62 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 63 | utils::read_payload(flag, bf).map(|(m, d)| RequestResponse { 64 | metadata: m, 65 | data: d, 66 | }) 67 | } 68 | 69 | pub fn builder(stream_id: u32, flag: u16) -> RequestResponseBuilder { 70 | RequestResponseBuilder::new(stream_id, flag) 71 | } 72 | 73 | pub fn get_metadata(&self) -> Option<&Bytes> { 74 | self.metadata.as_ref() 75 | } 76 | 77 | pub fn get_data(&self) -> Option<&Bytes> { 78 | self.data.as_ref() 79 | } 80 | 81 | pub fn split(self) -> (Option, Option) { 82 | (self.data, self.metadata) 83 | } 84 | } 85 | 86 | impl Writeable for RequestResponse { 87 | fn write_to(&self, bf: &mut BytesMut) { 88 | utils::write_payload(bf, self.get_metadata(), self.get_data()) 89 | } 90 | 91 | fn len(&self) -> usize { 92 | utils::calculate_payload_length(self.get_metadata(), self.get_data()) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rsocket-transport-websocket/src/connection.rs: -------------------------------------------------------------------------------- 1 | use std::result::Result; 2 | 3 | use bytes::{BufMut, BytesMut}; 4 | use futures::stream::SplitSink; 5 | use futures::{Sink, SinkExt, StreamExt}; 6 | use rsocket_rust::{ 7 | error::RSocketError, 8 | frame::Frame, 9 | transport::{Connection, FrameSink, FrameStream}, 10 | utils::Writeable, 11 | }; 12 | use tokio::net::TcpStream; 13 | use tokio_tungstenite::MaybeTlsStream; 14 | use tokio_tungstenite::{ 15 | tungstenite::{Error as WsError, Message}, 16 | WebSocketStream, 17 | }; 18 | 19 | #[derive(Debug)] 20 | pub struct WebsocketConnection { 21 | stream: WebSocketStream>, 22 | } 23 | 24 | impl WebsocketConnection { 25 | pub(crate) fn new(stream: WebSocketStream>) -> WebsocketConnection { 26 | WebsocketConnection { stream } 27 | } 28 | } 29 | 30 | struct InnerSink(SplitSink>, Message>); 31 | 32 | impl Sink for InnerSink { 33 | type Error = WsError; 34 | 35 | fn poll_ready( 36 | mut self: std::pin::Pin<&mut Self>, 37 | cx: &mut std::task::Context<'_>, 38 | ) -> std::task::Poll> { 39 | self.as_mut().0.poll_ready_unpin(cx) 40 | } 41 | 42 | fn start_send(mut self: std::pin::Pin<&mut Self>, item: Frame) -> Result<(), Self::Error> { 43 | let mut b = BytesMut::new(); 44 | item.write_to(&mut b); 45 | let msg = Message::binary(b.to_vec()); 46 | self.as_mut().0.start_send_unpin(msg) 47 | } 48 | 49 | fn poll_flush( 50 | mut self: std::pin::Pin<&mut Self>, 51 | cx: &mut std::task::Context<'_>, 52 | ) -> std::task::Poll> { 53 | self.as_mut().0.poll_flush_unpin(cx) 54 | } 55 | 56 | fn poll_close( 57 | mut self: std::pin::Pin<&mut Self>, 58 | cx: &mut std::task::Context<'_>, 59 | ) -> std::task::Poll> { 60 | self.as_mut().0.poll_close_unpin(cx) 61 | } 62 | } 63 | 64 | impl Connection for WebsocketConnection { 65 | fn split(self) -> (Box, Box) { 66 | let (sink, stream) = self.stream.split(); 67 | ( 68 | Box::new(InnerSink(sink).sink_map_err(|e| RSocketError::Other(e.into()))), 69 | Box::new(stream.map(|it| match it { 70 | Ok(msg) => { 71 | let raw = msg.into_data(); 72 | let mut bf = BytesMut::new(); 73 | bf.put_slice(&raw[..]); 74 | match Frame::decode(&mut bf) { 75 | Ok(frame) => Ok(frame), 76 | Err(e) => Err(RSocketError::Other(e)), 77 | } 78 | } 79 | Err(e) => Err(RSocketError::Other(e.into())), 80 | })), 81 | ) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /cliff.toml: -------------------------------------------------------------------------------- 1 | # git-cliff ~ default configuration file 2 | # https://git-cliff.org/docs/configuration 3 | # 4 | # Lines starting with "#" are comments. 5 | # Configuration options are organized into tables and keys. 6 | # See documentation for more information on available options. 7 | 8 | [changelog] 9 | # changelog header 10 | header = """ 11 | # Changelog\n 12 | All notable changes to this project will be documented in this file.\n 13 | """ 14 | # template for the changelog body 15 | # https://tera.netlify.app/docs 16 | body = """ 17 | {% if version %}\ 18 | ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} 19 | {% else %}\ 20 | ## [unreleased] 21 | {% endif %}\ 22 | {% for group, commits in commits | group_by(attribute="group") %} 23 | ### {{ group | upper_first }} 24 | {% for commit in commits %} 25 | - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\ 26 | {% endfor %} 27 | {% endfor %}\n 28 | """ 29 | # remove the leading and trailing whitespace from the template 30 | trim = true 31 | # changelog footer 32 | footer = """ 33 | 34 | """ 35 | 36 | [git] 37 | # parse the commits based on https://www.conventionalcommits.org 38 | conventional_commits = true 39 | # filter out the commits that are not conventional 40 | filter_unconventional = true 41 | # process each line of a commit as an individual commit 42 | split_commits = false 43 | # regex for preprocessing the commit messages 44 | commit_preprocessors = [ 45 | # { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/orhun/git-cliff/issues/${2}))"}, # replace issue numbers 46 | ] 47 | # regex for parsing and grouping commits 48 | commit_parsers = [ 49 | { message = "^feat", group = "Features" }, 50 | { message = "^fix", group = "Bug Fixes" }, 51 | { message = "^doc", group = "Documentation" }, 52 | { message = "^perf", group = "Performance" }, 53 | { message = "^refactor", group = "Refactor" }, 54 | { message = "^style", group = "Styling" }, 55 | { message = "^test", group = "Testing" }, 56 | { message = "^chore\\(release\\): prepare for", skip = true }, 57 | { message = "^chore", group = "Miscellaneous Tasks" }, 58 | { body = ".*security", group = "Security" }, 59 | ] 60 | # protect breaking changes from being skipped due to matching a skipping commit_parser 61 | protect_breaking_commits = false 62 | # filter out the commits that are not matched by commit parsers 63 | filter_commits = false 64 | # glob pattern for matching git tags 65 | tag_pattern = "v[0-9]*" 66 | # regex for skipping tags 67 | skip_tags = "v0.1.0-beta.1" 68 | # regex for ignoring tags 69 | ignore_tags = "" 70 | # sort the tags topologically 71 | topo_order = false 72 | # sort the commits inside sections by oldest/newest order 73 | sort_commits = "oldest" 74 | # limit the number of commits included in the changelog. 75 | # limit_commits = 42 76 | -------------------------------------------------------------------------------- /rsocket/src/frame/lease.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use super::{Body, Frame}; 4 | use crate::error::RSocketError; 5 | use crate::utils::Writeable; 6 | 7 | #[derive(Debug, Eq, PartialEq)] 8 | pub struct Lease { 9 | ttl: u32, 10 | number_of_requests: u32, 11 | metadata: Option, 12 | } 13 | 14 | pub struct LeaseBuilder { 15 | stream_id: u32, 16 | flag: u16, 17 | value: Lease, 18 | } 19 | 20 | impl LeaseBuilder { 21 | fn new(stream_id: u32, flag: u16) -> LeaseBuilder { 22 | LeaseBuilder { 23 | stream_id, 24 | flag, 25 | value: Lease { 26 | ttl: 0, 27 | number_of_requests: 0, 28 | metadata: None, 29 | }, 30 | } 31 | } 32 | 33 | pub fn set_metadata(mut self, metadata: Bytes) -> Self { 34 | self.value.metadata = Some(metadata); 35 | self.flag |= Frame::FLAG_METADATA; 36 | self 37 | } 38 | 39 | pub fn set_ttl(mut self, ttl: u32) -> Self { 40 | self.value.ttl = ttl; 41 | self 42 | } 43 | 44 | pub fn set_number_of_requests(mut self, n: u32) -> Self { 45 | self.value.number_of_requests = n; 46 | self 47 | } 48 | 49 | pub fn build(self) -> Frame { 50 | Frame::new(self.stream_id, Body::Lease(self.value), self.flag) 51 | } 52 | } 53 | 54 | impl Lease { 55 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 56 | if bf.len() < 8 { 57 | return Err(RSocketError::InCompleteFrame.into()); 58 | } 59 | let ttl = bf.get_u32(); 60 | let n = bf.get_u32(); 61 | let m = if flag & Frame::FLAG_METADATA != 0 { 62 | Some(bf.split().freeze()) 63 | } else { 64 | None 65 | }; 66 | Ok(Lease { 67 | ttl, 68 | number_of_requests: n, 69 | metadata: m, 70 | }) 71 | } 72 | 73 | pub fn builder(stream_id: u32, flag: u16) -> LeaseBuilder { 74 | LeaseBuilder::new(stream_id, flag) 75 | } 76 | 77 | pub fn get_number_of_requests(&self) -> u32 { 78 | self.number_of_requests 79 | } 80 | 81 | pub fn get_metadata(&self) -> Option<&Bytes> { 82 | self.metadata.as_ref() 83 | } 84 | 85 | pub fn get_ttl(&self) -> u32 { 86 | self.ttl 87 | } 88 | } 89 | 90 | impl Writeable for Lease { 91 | fn write_to(&self, bf: &mut BytesMut) { 92 | bf.put_u32(self.ttl); 93 | bf.put_u32(self.number_of_requests); 94 | match &self.metadata { 95 | Some(v) => bf.extend_from_slice(v), 96 | None => (), 97 | } 98 | } 99 | 100 | fn len(&self) -> usize { 101 | 8 + match &self.metadata { 102 | Some(v) => v.len(), 103 | None => 0, 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /rsocket-transport-wasm/src/misc.rs: -------------------------------------------------------------------------------- 1 | use js_sys::{Promise, Uint8Array}; 2 | use rsocket_rust::prelude::*; 3 | use rsocket_rust::Client; 4 | use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; 5 | use wasm_bindgen_futures::future_to_promise; 6 | 7 | use super::client::WebsocketClientTransport; 8 | 9 | #[derive(Serialize, Deserialize)] 10 | pub struct JsPayload { 11 | data: Option>, 12 | metadata: Option>, 13 | } 14 | 15 | #[wasm_bindgen] 16 | pub struct JsClient { 17 | inner: Client, 18 | } 19 | 20 | impl Into for &JsPayload { 21 | fn into(self) -> JsValue { 22 | JsValue::from_serde(self).unwrap() 23 | } 24 | } 25 | 26 | impl Into for JsPayload { 27 | fn into(self) -> Payload { 28 | let mut bu = Payload::builder(); 29 | if let Some(v) = self.data { 30 | bu = bu.set_data(v); 31 | } 32 | if let Some(v) = self.metadata { 33 | bu = bu.set_metadata(v); 34 | } 35 | bu.build() 36 | } 37 | } 38 | 39 | impl From for JsPayload { 40 | fn from(input: Payload) -> JsPayload { 41 | let (d, m) = input.split(); 42 | JsPayload { 43 | data: d.map(|v| v.to_vec()), 44 | metadata: m.map(|v| v.to_vec()), 45 | } 46 | } 47 | } 48 | 49 | #[wasm_bindgen] 50 | pub fn new_payload(data: JsValue, metadata: JsValue) -> JsValue { 51 | let jp = JsPayload { 52 | data: to_vec(data), 53 | metadata: to_vec(metadata), 54 | }; 55 | (&jp).into() 56 | } 57 | 58 | #[wasm_bindgen] 59 | pub async fn connect(url: String) -> Result { 60 | match RSocketFactory::connect() 61 | .transport(WebsocketClientTransport::from(url)) 62 | .start() 63 | .await 64 | { 65 | Ok(inner) => Ok(JsClient { inner }), 66 | Err(e) => Err(JsValue::from_str(&format!("{}", e))), 67 | } 68 | } 69 | 70 | #[wasm_bindgen] 71 | impl JsClient { 72 | pub fn request_response(&self, request: &JsValue) -> Promise { 73 | let inner = self.inner.clone(); 74 | let request: JsPayload = request.into_serde().unwrap(); 75 | future_to_promise(async move { 76 | match inner.request_response(request.into()).await { 77 | Ok(Some(v)) => { 78 | let jp = JsPayload::from(v); 79 | Ok((&jp).into()) 80 | } 81 | Ok(None) => Ok(JsValue::UNDEFINED), 82 | Err(e) => Err(JsValue::from(&format!("{:?}", e))), 83 | } 84 | }) 85 | } 86 | 87 | pub fn fire_and_forget(&self, request: &JsValue) -> Promise { 88 | let inner = self.inner.clone(); 89 | let request: JsPayload = request.into_serde().unwrap(); 90 | 91 | future_to_promise(async move { 92 | let _ = inner.fire_and_forget(request.into()).await; 93 | Ok(JsValue::NULL) 94 | }) 95 | } 96 | } 97 | 98 | #[inline] 99 | fn to_vec(input: JsValue) -> Option> { 100 | if input.is_null() || input.is_undefined() { 101 | None 102 | } else if input.is_string() { 103 | input.as_string().map(|s| s.into_bytes()) 104 | } else { 105 | Some(Uint8Array::from(input).to_vec()) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /rsocket/src/frame/request_stream.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use super::{utils, Body, Frame, REQUEST_MAX}; 4 | use crate::error::RSocketError; 5 | use crate::utils::Writeable; 6 | 7 | #[derive(Debug, Eq, PartialEq)] 8 | pub struct RequestStream { 9 | initial_request_n: u32, 10 | metadata: Option, 11 | data: Option, 12 | } 13 | 14 | pub struct RequestStreamBuilder { 15 | stream_id: u32, 16 | flag: u16, 17 | value: RequestStream, 18 | } 19 | 20 | impl RequestStreamBuilder { 21 | pub fn build(self) -> Frame { 22 | Frame::new(self.stream_id, Body::RequestStream(self.value), self.flag) 23 | } 24 | 25 | pub fn set_initial_request_n(mut self, n: u32) -> Self { 26 | self.value.initial_request_n = n; 27 | self 28 | } 29 | 30 | pub fn set_all(mut self, data_and_metadata: (Option, Option)) -> Self { 31 | self.value.data = data_and_metadata.0; 32 | match data_and_metadata.1 { 33 | Some(m) => { 34 | self.value.metadata = Some(m); 35 | self.flag |= Frame::FLAG_METADATA; 36 | } 37 | None => { 38 | self.value.metadata = None; 39 | self.flag &= !Frame::FLAG_METADATA; 40 | } 41 | } 42 | self 43 | } 44 | 45 | pub fn set_data(mut self, data: Bytes) -> Self { 46 | self.value.data = Some(data); 47 | self 48 | } 49 | 50 | pub fn set_metadata(mut self, metadata: Bytes) -> Self { 51 | self.value.metadata = Some(metadata); 52 | self.flag |= Frame::FLAG_METADATA; 53 | self 54 | } 55 | } 56 | 57 | impl RequestStream { 58 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 59 | if bf.len() < 4 { 60 | Err(RSocketError::InCompleteFrame.into()) 61 | } else { 62 | let initial_request_n = bf.get_u32(); 63 | utils::read_payload(flag, bf).map(move |(metadata, data)| RequestStream { 64 | initial_request_n, 65 | metadata, 66 | data, 67 | }) 68 | } 69 | } 70 | 71 | pub fn builder(stream_id: u32, flag: u16) -> RequestStreamBuilder { 72 | RequestStreamBuilder { 73 | stream_id, 74 | flag, 75 | value: RequestStream { 76 | initial_request_n: REQUEST_MAX, 77 | metadata: None, 78 | data: None, 79 | }, 80 | } 81 | } 82 | 83 | pub fn get_initial_request_n(&self) -> u32 { 84 | self.initial_request_n 85 | } 86 | 87 | pub fn get_metadata(&self) -> Option<&Bytes> { 88 | self.metadata.as_ref() 89 | } 90 | 91 | pub fn get_data(&self) -> Option<&Bytes> { 92 | self.data.as_ref() 93 | } 94 | 95 | pub fn split(self) -> (Option, Option) { 96 | (self.data, self.metadata) 97 | } 98 | } 99 | 100 | impl Writeable for RequestStream { 101 | fn write_to(&self, bf: &mut BytesMut) { 102 | bf.put_u32(self.initial_request_n); 103 | utils::write_payload(bf, self.get_metadata(), self.get_data()) 104 | } 105 | 106 | fn len(&self) -> usize { 107 | 4 + utils::calculate_payload_length(self.get_metadata(), self.get_data()) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /rsocket-transport-websocket/src/client.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use rsocket_rust::{async_trait, error::RSocketError, transport::Transport, Result}; 4 | use tokio::net::TcpStream; 5 | use tokio_tungstenite::{ 6 | accept_async, connect_async, tungstenite::handshake::client::Request, MaybeTlsStream, 7 | }; 8 | use url::Url; 9 | 10 | use super::connection::WebsocketConnection; 11 | 12 | pub type WebsocketRequest = Request; 13 | 14 | const WS_PROTO: &str = "ws://"; 15 | const WSS_PROTO: &str = "wss://"; 16 | 17 | #[derive(Debug)] 18 | pub(crate) enum Connector { 19 | Direct(MaybeTlsStream), 20 | Url(Url), 21 | Request(WebsocketRequest), 22 | } 23 | 24 | #[derive(Debug)] 25 | pub struct WebsocketClientTransport { 26 | connector: Connector, 27 | } 28 | 29 | impl WebsocketClientTransport { 30 | pub(crate) fn new(connector: Connector) -> WebsocketClientTransport { 31 | WebsocketClientTransport { connector } 32 | } 33 | } 34 | 35 | #[async_trait] 36 | impl Transport for WebsocketClientTransport { 37 | type Conn = WebsocketConnection; 38 | 39 | async fn connect(self) -> Result { 40 | match self.connector { 41 | Connector::Direct(stream) => match accept_async(stream).await { 42 | Ok(ws) => Ok(WebsocketConnection::new(ws)), 43 | Err(e) => Err(RSocketError::Other(e.into()).into()), 44 | }, 45 | Connector::Url(u) => match connect_async(u).await { 46 | Ok((stream, _)) => Ok(WebsocketConnection::new(stream)), 47 | Err(e) => Err(RSocketError::Other(e.into()).into()), 48 | }, 49 | Connector::Request(req) => match connect_async(req).await { 50 | Ok((stream, _)) => Ok(WebsocketConnection::new(stream)), 51 | Err(e) => Err(RSocketError::Other(e.into()).into()), 52 | }, 53 | } 54 | } 55 | } 56 | 57 | impl From> for WebsocketClientTransport { 58 | fn from(socket: MaybeTlsStream) -> WebsocketClientTransport { 59 | WebsocketClientTransport::new(Connector::Direct(socket)) 60 | } 61 | } 62 | 63 | impl From for WebsocketClientTransport { 64 | fn from(socket: TcpStream) -> WebsocketClientTransport { 65 | WebsocketClientTransport::new(Connector::Direct(MaybeTlsStream::Plain(socket))) 66 | } 67 | } 68 | 69 | impl From<&str> for WebsocketClientTransport { 70 | fn from(addr: &str) -> WebsocketClientTransport { 71 | let u = if addr.starts_with(WS_PROTO) || addr.starts_with(WSS_PROTO) { 72 | Url::parse(addr).unwrap() 73 | } else { 74 | Url::parse(&format!("{}{}", WS_PROTO, addr)).unwrap() 75 | }; 76 | WebsocketClientTransport::new(Connector::Url(u)) 77 | } 78 | } 79 | 80 | impl From for WebsocketClientTransport { 81 | fn from(addr: SocketAddr) -> WebsocketClientTransport { 82 | let u = Url::parse(&format!("{}{}", WS_PROTO, addr)).unwrap(); 83 | WebsocketClientTransport::new(Connector::Url(u)) 84 | } 85 | } 86 | 87 | impl From for WebsocketClientTransport { 88 | fn from(url: Url) -> WebsocketClientTransport { 89 | WebsocketClientTransport::new(Connector::Url(url)) 90 | } 91 | } 92 | 93 | impl From for WebsocketClientTransport { 94 | fn from(req: WebsocketRequest) -> Self { 95 | WebsocketClientTransport::new(Connector::Request(req)) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /rsocket/src/frame/request_channel.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use super::utils; 4 | use super::{Body, Frame, REQUEST_MAX}; 5 | use crate::error::RSocketError; 6 | use crate::utils::Writeable; 7 | 8 | #[derive(Debug, Eq, PartialEq)] 9 | pub struct RequestChannel { 10 | initial_request_n: u32, 11 | metadata: Option, 12 | data: Option, 13 | } 14 | 15 | pub struct RequestChannelBuilder { 16 | stream_id: u32, 17 | flag: u16, 18 | value: RequestChannel, 19 | } 20 | 21 | impl RequestChannelBuilder { 22 | pub fn new(stream_id: u32, flag: u16) -> RequestChannelBuilder { 23 | RequestChannelBuilder { 24 | stream_id, 25 | flag, 26 | value: RequestChannel { 27 | initial_request_n: REQUEST_MAX, 28 | metadata: None, 29 | data: None, 30 | }, 31 | } 32 | } 33 | 34 | pub fn build(self) -> Frame { 35 | Frame::new(self.stream_id, Body::RequestChannel(self.value), self.flag) 36 | } 37 | 38 | pub fn set_initial_request_n(mut self, n: u32) -> Self { 39 | self.value.initial_request_n = n; 40 | self 41 | } 42 | 43 | pub fn set_all(mut self, data_and_metadata: (Option, Option)) -> Self { 44 | self.value.data = data_and_metadata.0; 45 | match data_and_metadata.1 { 46 | Some(m) => { 47 | self.value.metadata = Some(m); 48 | self.flag |= Frame::FLAG_METADATA; 49 | } 50 | None => { 51 | self.value.metadata = None; 52 | self.flag &= !Frame::FLAG_METADATA; 53 | } 54 | } 55 | self 56 | } 57 | 58 | pub fn set_metadata(mut self, metadata: Bytes) -> Self { 59 | self.value.metadata = Some(metadata); 60 | self.flag |= Frame::FLAG_METADATA; 61 | self 62 | } 63 | 64 | pub fn set_data(mut self, data: Bytes) -> Self { 65 | self.value.data = Some(data); 66 | self 67 | } 68 | } 69 | 70 | impl RequestChannel { 71 | pub(crate) fn decode(flag: u16, bf: &mut BytesMut) -> crate::Result { 72 | if bf.len() < 4 { 73 | Err(RSocketError::InCompleteFrame.into()) 74 | } else { 75 | let initial_request_n = bf.get_u32(); 76 | utils::read_payload(flag, bf).map(move |(metadata, data)| RequestChannel { 77 | initial_request_n, 78 | metadata, 79 | data, 80 | }) 81 | } 82 | } 83 | 84 | pub fn builder(stream_id: u32, flag: u16) -> RequestChannelBuilder { 85 | RequestChannelBuilder::new(stream_id, flag) 86 | } 87 | 88 | pub fn get_initial_request_n(&self) -> u32 { 89 | self.initial_request_n 90 | } 91 | 92 | pub fn get_metadata(&self) -> Option<&Bytes> { 93 | self.metadata.as_ref() 94 | } 95 | pub fn get_data(&self) -> Option<&Bytes> { 96 | self.data.as_ref() 97 | } 98 | 99 | pub fn split(self) -> (Option, Option) { 100 | (self.data, self.metadata) 101 | } 102 | } 103 | 104 | impl Writeable for RequestChannel { 105 | fn write_to(&self, bf: &mut BytesMut) { 106 | bf.put_u32(self.initial_request_n); 107 | utils::write_payload(bf, self.get_metadata(), self.get_data()); 108 | } 109 | 110 | fn len(&self) -> usize { 111 | 4 + utils::calculate_payload_length(self.get_metadata(), self.get_data()) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /rsocket-test/tests/test_frames.rs: -------------------------------------------------------------------------------- 1 | extern crate bytes; 2 | extern crate hex; 3 | extern crate rsocket_rust; 4 | 5 | use bytes::{Bytes, BytesMut}; 6 | use rsocket_rust::frame::*; 7 | use rsocket_rust::utils::Writeable; 8 | 9 | #[test] 10 | fn test_setup() { 11 | let f = Setup::builder(1234, 0) 12 | .set_mime_data("application/binary") 13 | .set_mime_metadata("text/plain") 14 | .set_token(Bytes::from("this_is_a_token")) 15 | .set_data(Bytes::from(String::from("Hello World!"))) 16 | .set_metadata(Bytes::from(String::from("foobar"))) 17 | .build(); 18 | try_codec(f); 19 | } 20 | 21 | #[test] 22 | fn test_keepalive() { 23 | let f = Keepalive::builder(1234, Frame::FLAG_RESPOND) 24 | .set_last_received_position(123) 25 | .set_data(Bytes::from("foobar")) 26 | .build(); 27 | try_codec(f); 28 | } 29 | 30 | #[test] 31 | fn test_request_response() { 32 | let f = RequestResponse::builder(1234, 0) 33 | .set_data(Bytes::from("Hello World")) 34 | .set_metadata(Bytes::from("Foobar")) 35 | .build(); 36 | try_codec(f); 37 | } 38 | 39 | #[test] 40 | fn test_payload() { 41 | let f = Payload::builder(1234, Frame::FLAG_NEXT | Frame::FLAG_COMPLETE) 42 | .set_data(Bytes::from("Hello World!")) 43 | .set_metadata(Bytes::from("foobar")) 44 | .build(); 45 | try_codec(f); 46 | } 47 | 48 | #[test] 49 | fn test_request_channel() { 50 | let f = RequestChannel::builder(1234, 0) 51 | .set_initial_request_n(1) 52 | .set_data(Bytes::from("Hello World!")) 53 | .set_metadata(Bytes::from("foobar")) 54 | .build(); 55 | try_codec(f); 56 | } 57 | 58 | #[test] 59 | fn test_cancel() { 60 | let f = Cancel::builder(1234, 0).build(); 61 | try_codec(f); 62 | } 63 | 64 | #[test] 65 | fn test_request_fnf() { 66 | let f = RequestFNF::builder(1234, 0) 67 | .set_data(Bytes::from("Hello")) 68 | .set_metadata(Bytes::from("World")) 69 | .build(); 70 | try_codec(f); 71 | } 72 | 73 | #[test] 74 | fn test_metadata_push() { 75 | let f = MetadataPush::builder(1234, 0) 76 | .set_metadata(Bytes::from("Hello Rust!")) 77 | .build(); 78 | try_codec(f); 79 | } 80 | 81 | #[test] 82 | fn test_request_n() { 83 | let f = RequestN::builder(1234, 0).set_n(77778888).build(); 84 | try_codec(f); 85 | } 86 | 87 | #[test] 88 | fn test_lease() { 89 | let f = Lease::builder(1234, 0) 90 | .set_metadata(Bytes::from("Hello Rust!")) 91 | .set_number_of_requests(333) 92 | .set_ttl(1000) 93 | .build(); 94 | try_codec(f); 95 | } 96 | 97 | #[test] 98 | fn test_error() { 99 | let f = Error::builder(1234, 0) 100 | .set_data(Bytes::from("Hello World!")) 101 | .set_code(4444) 102 | .build(); 103 | try_codec(f); 104 | } 105 | 106 | #[test] 107 | fn resume_ok() { 108 | let f = ResumeOK::builder(1234, 0).set_position(2333).build(); 109 | try_codec(f); 110 | } 111 | 112 | #[test] 113 | fn test_resume() { 114 | let f = Resume::builder(0, Frame::FLAG_RESUME) 115 | .set_last_received_server_position(123) 116 | .set_first_available_client_position(22) 117 | .set_token(Bytes::from("this is a token")) 118 | .build(); 119 | try_codec(f); 120 | } 121 | 122 | fn try_codec(f: Frame) { 123 | println!("******* codec: {:?}", f); 124 | let mut bf = BytesMut::with_capacity(f.len() as usize); 125 | f.write_to(&mut bf); 126 | println!("####### encode: {}", hex::encode(bf.to_vec())); 127 | let f2 = Frame::decode(&mut bf).unwrap(); 128 | println!("####### decode: {:?}", f2); 129 | assert_eq!( 130 | f, f2, 131 | "frames doesn't match: expect={:?}, actual={:?}", 132 | f, f2 133 | ); 134 | } 135 | -------------------------------------------------------------------------------- /rsocket/src/frame/resume.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use super::{Body, Frame, Version}; 4 | use crate::error::RSocketError; 5 | use crate::utils::Writeable; 6 | 7 | #[derive(Debug, Eq, PartialEq)] 8 | pub struct Resume { 9 | version: Version, 10 | token: Option, 11 | last_received_server_position: u64, 12 | first_available_client_position: u64, 13 | } 14 | 15 | pub struct ResumeBuilder { 16 | stream_id: u32, 17 | flag: u16, 18 | inner: Resume, 19 | } 20 | 21 | impl Resume { 22 | fn new() -> Resume { 23 | Resume { 24 | version: Version::default(), 25 | token: None, 26 | last_received_server_position: 0, 27 | first_available_client_position: 0, 28 | } 29 | } 30 | 31 | pub(crate) fn decode(flag: u16, b: &mut BytesMut) -> crate::Result { 32 | if b.len() < 6 { 33 | return Err(RSocketError::InCompleteFrame.into()); 34 | } 35 | let major = b.get_u16(); 36 | let minor = b.get_u16(); 37 | let token_size = b.get_u16() as usize; 38 | let token = if token_size > 0 { 39 | if b.len() < token_size { 40 | return Err(RSocketError::InCompleteFrame.into()); 41 | } 42 | Some(b.split_to(token_size).freeze()) 43 | } else { 44 | None 45 | }; 46 | if b.len() < 16 { 47 | return Err(RSocketError::InCompleteFrame.into()); 48 | } 49 | let last_received_server_position = b.get_u64(); 50 | let first_available_client_position = b.get_u64(); 51 | Ok(Resume { 52 | version: Version::new(major, minor), 53 | token, 54 | last_received_server_position, 55 | first_available_client_position, 56 | }) 57 | } 58 | 59 | pub fn builder(stream_id: u32, flag: u16) -> ResumeBuilder { 60 | ResumeBuilder::new(stream_id, flag) 61 | } 62 | 63 | pub fn get_version(&self) -> Version { 64 | self.version 65 | } 66 | 67 | pub fn get_token(&self) -> &Option { 68 | &self.token 69 | } 70 | 71 | pub fn get_last_received_server_position(&self) -> u64 { 72 | self.last_received_server_position 73 | } 74 | 75 | pub fn get_first_available_client_position(&self) -> u64 { 76 | self.first_available_client_position 77 | } 78 | } 79 | 80 | impl ResumeBuilder { 81 | fn new(stream_id: u32, flag: u16) -> ResumeBuilder { 82 | ResumeBuilder { 83 | stream_id, 84 | flag, 85 | inner: Resume::new(), 86 | } 87 | } 88 | 89 | pub fn set_token(mut self, token: Bytes) -> Self { 90 | self.inner.token = Some(token); 91 | self 92 | } 93 | 94 | pub fn set_last_received_server_position(mut self, position: u64) -> Self { 95 | self.inner.last_received_server_position = position; 96 | self 97 | } 98 | 99 | pub fn set_first_available_client_position(mut self, position: u64) -> Self { 100 | self.inner.first_available_client_position = position; 101 | self 102 | } 103 | 104 | pub fn build(self) -> Frame { 105 | Frame { 106 | stream_id: self.stream_id, 107 | flag: self.flag, 108 | body: Body::Resume(self.inner), 109 | } 110 | } 111 | } 112 | 113 | impl Writeable for Resume { 114 | fn write_to(&self, bf: &mut BytesMut) { 115 | self.version.write_to(bf); 116 | if let Some(b) = self.get_token() { 117 | bf.put_u16(b.len() as u16); 118 | bf.extend_from_slice(b); 119 | } 120 | bf.put_u64(self.get_last_received_server_position()); 121 | bf.put_u64(self.get_first_available_client_position()); 122 | } 123 | 124 | fn len(&self) -> usize { 125 | let mut size: usize = 22; 126 | if let Some(b) = self.get_token() { 127 | size += b.len(); 128 | } 129 | size 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /rsocket/README.md: -------------------------------------------------------------------------------- 1 | # RSocket Core 2 | 3 | ## Example 4 | 5 | > Here are some example codes which show how RSocket works in Rust. 6 | 7 | ### Dependencies 8 | 9 | Add dependencies in your `Cargo.toml`. 10 | 11 | ```toml 12 | [dependencies] 13 | tokio = "0.3.6" 14 | rsocket_rust = "0.7.0" 15 | 16 | # add transport dependencies: 17 | # rsocket_rust_transport_tcp = "0.7.0" 18 | # rsocket_rust_transport_websocket = "0.7.0" 19 | ``` 20 | 21 | ### Server 22 | 23 | ```rust 24 | use rsocket_rust::prelude::*; 25 | use rsocket_rust::utils::EchoRSocket; 26 | use rsocket_rust::Result; 27 | use rsocket_rust_transport_tcp::TcpServerTransport; 28 | 29 | #[tokio::main] 30 | async fn main() -> Result<()> { 31 | RSocketFactory::receive() 32 | .transport(TcpServerTransport::from("127.0.0.1:7878")) 33 | .acceptor(Box::new(|setup, _socket| { 34 | println!("accept setup: {:?}", setup); 35 | Ok(Box::new(EchoRSocket)) 36 | // Or you can reject setup 37 | // Err(From::from("SETUP_NOT_ALLOW")) 38 | })) 39 | .on_start(Box::new(|| println!("+++++++ echo server started! +++++++"))) 40 | .serve() 41 | .await 42 | } 43 | ``` 44 | 45 | ### Client 46 | 47 | ```rust 48 | use rsocket_rust::prelude::*; 49 | use rsocket_rust::Result; 50 | use rsocket_rust_transport_tcp::TcpClientTransport; 51 | 52 | #[tokio::main] 53 | async fn main() -> Result<()> { 54 | let cli = RSocketFactory::connect() 55 | .transport(TcpClientTransport::from("127.0.0.1:7878")) 56 | .setup(Payload::from("READY!")) 57 | .mime_type("text/plain", "text/plain") 58 | .on_close(Box::new(|| println!("connection closed"))) 59 | .start() 60 | .await?; 61 | let req = Payload::builder() 62 | .set_data_utf8("Hello World!") 63 | .set_metadata_utf8("Rust") 64 | .build(); 65 | let res = cli.request_response(req).await?; 66 | println!("got: {:?}", res); 67 | 68 | // If you want to block until socket disconnected. 69 | cli.wait_for_close().await; 70 | 71 | Ok(()) 72 | } 73 | ``` 74 | 75 | ### Implement RSocket trait 76 | 77 | Example for access Redis([crates](https://crates.io/crates/redis)): 78 | 79 | > NOTICE: add dependency in Cargo.toml => redis = { version = "0.19.0", features = [ "aio" ] } 80 | 81 | ```rust 82 | use std::str::FromStr; 83 | 84 | use redis::Client as RedisClient; 85 | use rsocket_rust::async_trait; 86 | use rsocket_rust::prelude::*; 87 | use rsocket_rust::Result; 88 | 89 | #[derive(Clone)] 90 | pub struct RedisDao { 91 | inner: RedisClient, 92 | } 93 | 94 | // Create RedisDao from str. 95 | // Example: RedisDao::from_str("redis://127.0.0.1").expect("Connect redis failed!"); 96 | impl FromStr for RedisDao { 97 | type Err = redis::RedisError; 98 | 99 | fn from_str(s: &str) -> std::result::Result { 100 | let client = redis::Client::open(s)?; 101 | Ok(RedisDao { inner: client }) 102 | } 103 | } 104 | 105 | #[async_trait] 106 | impl RSocket for RedisDao { 107 | async fn request_response(&self, req: Payload) -> Result> { 108 | let client = self.inner.clone(); 109 | let mut conn = client.get_async_connection().await?; 110 | let value: redis::RedisResult> = redis::cmd("GET") 111 | .arg(&[req.data_utf8()]) 112 | .query_async(&mut conn) 113 | .await; 114 | match value { 115 | Ok(Some(value)) => Ok(Some(Payload::builder().set_data_utf8(&value).build())), 116 | Ok(None) => Ok(None), 117 | Err(e) => Err(e.into()), 118 | } 119 | } 120 | 121 | async fn metadata_push(&self, _req: Payload) -> Result<()> { 122 | todo!() 123 | } 124 | 125 | async fn fire_and_forget(&self, _req: Payload) -> Result<()> { 126 | todo!() 127 | } 128 | 129 | fn request_stream(&self, _req: Payload) -> Flux> { 130 | todo!() 131 | } 132 | 133 | fn request_channel(&self, _reqs: Flux>) -> Flux> { 134 | todo!() 135 | } 136 | } 137 | 138 | ``` 139 | -------------------------------------------------------------------------------- /rsocket/src/payload/normal.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | 3 | use super::misc::bytes_to_utf8; 4 | use crate::frame; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct Payload { 8 | m: Option, 9 | d: Option, 10 | } 11 | 12 | #[derive(Debug)] 13 | pub struct PayloadBuilder { 14 | value: Payload, 15 | } 16 | 17 | impl PayloadBuilder { 18 | fn new() -> PayloadBuilder { 19 | PayloadBuilder { 20 | value: Payload { m: None, d: None }, 21 | } 22 | } 23 | 24 | pub fn set_data(mut self, data: A) -> Self 25 | where 26 | A: Into>, 27 | { 28 | self.value.d = Some(Bytes::from(data.into())); 29 | self 30 | } 31 | 32 | pub fn set_metadata(mut self, metadata: A) -> Self 33 | where 34 | A: Into>, 35 | { 36 | self.value.m = Some(Bytes::from(metadata.into())); 37 | self 38 | } 39 | 40 | pub fn set_metadata_utf8(mut self, metadata: &str) -> Self { 41 | self.value.m = Some(Bytes::from(metadata.to_owned())); 42 | self 43 | } 44 | 45 | pub fn set_data_utf8(mut self, data: &str) -> Self { 46 | self.value.d = Some(Bytes::from(data.to_owned())); 47 | self 48 | } 49 | 50 | pub fn build(self) -> Payload { 51 | self.value 52 | } 53 | } 54 | 55 | impl Payload { 56 | pub fn new(data: Option, metadata: Option) -> Payload { 57 | Payload { 58 | d: data, 59 | m: metadata, 60 | } 61 | } 62 | 63 | pub fn builder() -> PayloadBuilder { 64 | PayloadBuilder::new() 65 | } 66 | 67 | pub fn metadata(&self) -> Option<&Bytes> { 68 | self.m.as_ref() 69 | } 70 | 71 | pub fn data(&self) -> Option<&Bytes> { 72 | self.d.as_ref() 73 | } 74 | 75 | pub fn data_utf8(&self) -> Option<&str> { 76 | bytes_to_utf8(&self.d) 77 | } 78 | 79 | pub fn metadata_utf8(&self) -> Option<&str> { 80 | bytes_to_utf8(&self.m) 81 | } 82 | 83 | pub fn is_empty(&self) -> bool { 84 | self.len() == 0 85 | } 86 | 87 | pub fn len(&self) -> usize { 88 | let mut n = 0; 89 | if let Some(it) = &self.m { 90 | n += it.len(); 91 | } 92 | if let Some(it) = &self.d { 93 | n += it.len(); 94 | } 95 | n 96 | } 97 | 98 | pub fn split(self) -> (Option, Option) { 99 | (self.d, self.m) 100 | } 101 | } 102 | 103 | impl From<&'static str> for Payload { 104 | fn from(data: &'static str) -> Payload { 105 | Payload { 106 | d: Some(Bytes::from(data)), 107 | m: None, 108 | } 109 | } 110 | } 111 | 112 | impl From<(&'static str, &'static str)> for Payload { 113 | fn from((data, metadata): (&'static str, &'static str)) -> Payload { 114 | Payload { 115 | d: Some(Bytes::from(data)), 116 | m: Some(Bytes::from(metadata)), 117 | } 118 | } 119 | } 120 | 121 | impl From for Payload { 122 | fn from(input: frame::Payload) -> Payload { 123 | let (d, m) = input.split(); 124 | Payload::new(d, m) 125 | } 126 | } 127 | 128 | impl From for Payload { 129 | fn from(input: frame::Setup) -> Payload { 130 | let (d, m) = input.split(); 131 | Payload::new(d, m) 132 | } 133 | } 134 | 135 | impl From for Payload { 136 | fn from(input: frame::RequestChannel) -> Payload { 137 | let (d, m) = input.split(); 138 | Payload::new(d, m) 139 | } 140 | } 141 | 142 | impl From for Payload { 143 | fn from(input: frame::MetadataPush) -> Payload { 144 | let (d, m) = input.split(); 145 | Payload::new(d, m) 146 | } 147 | } 148 | 149 | impl From for Payload { 150 | fn from(input: frame::RequestStream) -> Payload { 151 | let (d, m) = input.split(); 152 | Payload::new(d, m) 153 | } 154 | } 155 | 156 | impl From for Payload { 157 | fn from(input: frame::RequestFNF) -> Payload { 158 | let (d, m) = input.split(); 159 | Payload::new(d, m) 160 | } 161 | } 162 | 163 | impl From for Payload { 164 | fn from(input: frame::RequestResponse) -> Payload { 165 | let (d, m) = input.split(); 166 | Payload::new(d, m) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /rsocket/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_imports)] 3 | #![allow(unused_variables)] 4 | #![allow(clippy::type_complexity)] 5 | #![allow(clippy::from_over_into)] 6 | #![doc(test( 7 | no_crate_inject, 8 | attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) 9 | ))] 10 | 11 | //! Official RSocket Rust implementation using Tokio. 12 | //! 13 | //! RSocket is an application protocol providing Reactive Streams semantics. 14 | //! 15 | //! It is a binary protocol for use on byte stream transports such as TCP, WebSockets, and Aeron. 16 | //! 17 | //! It enables the following symmetric interaction models via async message passing over a single connection: 18 | //! - request/response (stream of 1) 19 | //! - request/stream (finite stream of many) 20 | //! - fire-and-forget (no response) 21 | //! - channel (bi-directional streams) 22 | //! 23 | //! # A Tour of RSocket 24 | //! 25 | //! The easiest way to get started is to use RSocket. Do this by enabling TCP transport support. 26 | //! 27 | //! ```toml 28 | //! rsocket_rust = "0.5.1" 29 | //! rsocket_rust_transport_tcp = "0.5.1" 30 | //! 31 | //! # If you want to use websocket transport instead. 32 | //! # rsocket_rust_transport_websocket = "0.5.1" 33 | //! ``` 34 | //! 35 | //! # Examples 36 | //! 37 | //! A simple TCP echo server: 38 | //! 39 | //! ```no_run,ignore 40 | //! use rsocket_rust::prelude::*; 41 | //! use rsocket_rust::utils::EchoRSocket; 42 | //! use rsocket_rust::Result; 43 | //! use rsocket_rust_transport_tcp::TcpServerTransport; 44 | //! 45 | //! #[tokio::main] 46 | //! async fn main() -> Result<()> { 47 | //! RSocketFactory::receive() 48 | //! .transport(TcpServerTransport::from("127.0.0.1:7878")) 49 | //! .acceptor(Box::new(|setup, socket| { 50 | //! println!("socket establish: setup={:?}", setup); 51 | //! tokio::spawn(async move { 52 | //! let req = Payload::builder().set_data_utf8("Hello World!").build(); 53 | //! let res = socket.request_response(req).await.unwrap(); 54 | //! println!("SERVER request CLIENT success: response={:?}", res); 55 | //! }); 56 | //! // Return a responder. 57 | //! // You can write you own responder by implementing `RSocket` trait. 58 | //! Ok(Box::new(EchoRSocket)) 59 | //! })) 60 | //! .on_start(Box::new(|| println!("echo server start success!"))) 61 | //! .serve() 62 | //! .await 63 | //! } 64 | //! ``` 65 | //! 66 | //! Connect to echo server above: 67 | //! 68 | //! ```no_run,ignore 69 | //! use rsocket_rust::prelude::*; 70 | //! use rsocket_rust::utils::EchoRSocket; 71 | //! use rsocket_rust::Result; 72 | //! use rsocket_rust_transport_tcp::TcpClientTransport; 73 | //! 74 | //! #[tokio::main] 75 | //! async fn main() -> Result<()> { 76 | //! let client = RSocketFactory::connect() 77 | //! .transport(TcpClientTransport::from("127.0.0.1:7878")) 78 | //! .acceptor(Box::new(|| { 79 | //! // Return a responder. 80 | //! Box::new(EchoRSocket) 81 | //! })) 82 | //! .start() 83 | //! .await 84 | //! .expect("Connect failed!"); 85 | //! 86 | //! let req = Payload::builder().set_data_utf8("Ping!").build(); 87 | //! let res = client.request_response(req).await.expect("Requet failed!"); 88 | //! println!("request success: response={:?}", res); 89 | //! 90 | //! Ok(()) 91 | //! } 92 | //! ``` 93 | //! 94 | 95 | /// A re-export of [`async-stream`](https://docs.rs/async-stream) for creating a Stream. 96 | pub use async_stream::stream; 97 | /// A re-export of [`async-trait`](https://docs.rs/async-trait) for use with RSocket trait implementation. 98 | pub use async_trait::async_trait; 99 | 100 | #[macro_use] 101 | extern crate anyhow; 102 | #[macro_use] 103 | extern crate log; 104 | #[macro_use] 105 | extern crate cfg_if; 106 | 107 | #[macro_use] 108 | #[doc(hidden)] 109 | pub mod macros; 110 | 111 | pub mod error; 112 | pub mod extension; 113 | pub mod prelude; 114 | pub mod runtime; 115 | pub mod transport; 116 | pub mod utils; 117 | 118 | cfg_if! { 119 | if #[cfg(feature = "frame")]{ 120 | pub mod frame; 121 | }else{ 122 | mod frame; 123 | } 124 | } 125 | 126 | mod core; 127 | mod payload; 128 | mod spi; 129 | 130 | pub type Error = Box; 131 | pub type Result = anyhow::Result; 132 | 133 | pub use crate::core::{Client, ClientBuilder, ServerBuilder}; 134 | -------------------------------------------------------------------------------- /rsocket/src/payload/setup.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use bytes::Bytes; 4 | 5 | use super::misc::bytes_to_utf8; 6 | use crate::frame::Setup; 7 | use crate::utils::DEFAULT_MIME_TYPE; 8 | 9 | #[derive(Debug)] 10 | pub struct SetupPayload { 11 | m: Option, 12 | d: Option, 13 | keepalive: (Duration, Duration), 14 | mime_m: Option, 15 | mime_d: Option, 16 | } 17 | 18 | #[derive(Debug)] 19 | pub struct SetupPayloadBuilder { 20 | inner: SetupPayload, 21 | } 22 | 23 | impl SetupPayload { 24 | pub fn builder() -> SetupPayloadBuilder { 25 | SetupPayloadBuilder::new() 26 | } 27 | } 28 | 29 | impl SetupPayloadBuilder { 30 | fn new() -> SetupPayloadBuilder { 31 | SetupPayloadBuilder { 32 | inner: SetupPayload { 33 | m: None, 34 | d: None, 35 | keepalive: (Duration::from_secs(20), Duration::from_secs(90)), 36 | mime_m: Some(Bytes::from(DEFAULT_MIME_TYPE.to_owned())), 37 | mime_d: Some(Bytes::from(DEFAULT_MIME_TYPE.to_owned())), 38 | }, 39 | } 40 | } 41 | 42 | pub fn set_metadata(mut self, metadata: A) -> Self 43 | where 44 | A: Into>, 45 | { 46 | self.inner.m = Some(Bytes::from(metadata.into())); 47 | self 48 | } 49 | 50 | pub fn set_metadata_utf8(mut self, metadata: &str) -> Self { 51 | self.inner.m = Some(Bytes::from(String::from(metadata))); 52 | self 53 | } 54 | 55 | pub(crate) fn set_data_bytes(mut self, data: Option) -> Self { 56 | self.inner.d = data; 57 | self 58 | } 59 | 60 | pub(crate) fn set_metadata_bytes(mut self, data: Option) -> Self { 61 | self.inner.m = data; 62 | self 63 | } 64 | 65 | pub fn set_data(mut self, data: A) -> Self 66 | where 67 | A: Into>, 68 | { 69 | self.inner.d = Some(Bytes::from(data.into())); 70 | self 71 | } 72 | 73 | pub fn set_data_utf8(mut self, data: &str) -> Self { 74 | self.inner.d = Some(Bytes::from(data.to_owned())); 75 | self 76 | } 77 | 78 | pub fn set_keepalive( 79 | mut self, 80 | tick_period: Duration, 81 | ack_timeout: Duration, 82 | missed_acks: u64, 83 | ) -> Self { 84 | let lifetime_mills = (ack_timeout.as_millis() as u64) * missed_acks; 85 | self.inner.keepalive = (tick_period, Duration::from_millis(lifetime_mills)); 86 | self 87 | } 88 | 89 | pub fn set_data_mime_type(mut self, mime: impl Into) -> Self { 90 | self.inner.mime_d = Some(Bytes::from(mime.into())); 91 | self 92 | } 93 | pub fn set_metadata_mime_type(mut self, mime: impl Into) -> Self { 94 | self.inner.mime_m = Some(Bytes::from(mime.into())); 95 | self 96 | } 97 | 98 | pub fn build(self) -> SetupPayload { 99 | self.inner 100 | } 101 | } 102 | 103 | impl SetupPayload { 104 | pub fn metadata(&self) -> Option<&Bytes> { 105 | self.m.as_ref() 106 | } 107 | 108 | pub fn data(&self) -> Option<&Bytes> { 109 | self.d.as_ref() 110 | } 111 | 112 | pub fn split(self) -> (Option, Option) { 113 | (self.d, self.m) 114 | } 115 | 116 | pub fn keepalive_interval(&self) -> Duration { 117 | self.keepalive.0 118 | } 119 | 120 | pub fn keepalive_lifetime(&self) -> Duration { 121 | self.keepalive.1 122 | } 123 | 124 | pub fn metadata_mime_type(&self) -> Option<&str> { 125 | bytes_to_utf8(&self.mime_m) 126 | } 127 | 128 | pub fn data_mime_type(&self) -> Option<&str> { 129 | bytes_to_utf8(&self.mime_d) 130 | } 131 | } 132 | 133 | impl From for SetupPayload { 134 | fn from(input: Setup) -> SetupPayload { 135 | let mut bu = SetupPayload::builder(); 136 | // TODO: fill other properties. 137 | if let Some(m) = input.get_mime_data() { 138 | bu = bu.set_data_mime_type(m); 139 | } 140 | if let Some(m) = input.get_mime_metadata() { 141 | bu = bu.set_metadata_mime_type(m); 142 | } 143 | let keepalive = (input.get_keepalive(), input.get_lifetime()); 144 | let (d, m) = input.split(); 145 | bu.inner.d = d; 146 | bu.inner.m = m; 147 | let mut pa = bu.build(); 148 | pa.keepalive = keepalive; 149 | pa 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /rsocket/src/core/server.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::future::Future; 3 | use std::marker::PhantomData; 4 | use std::net::SocketAddr; 5 | use std::pin::Pin; 6 | use std::sync::Arc; 7 | 8 | use futures::{SinkExt, StreamExt}; 9 | use tokio::sync::mpsc; 10 | 11 | use crate::error::RSocketError; 12 | use crate::frame::{self, Frame}; 13 | use crate::payload::SetupPayload; 14 | use crate::runtime; 15 | use crate::spi::{RSocket, ServerResponder}; 16 | use crate::transport::{Connection, DuplexSocket, ServerTransport, Splitter, Transport, MIN_MTU}; 17 | use crate::utils::EmptyRSocket; 18 | use crate::Result; 19 | 20 | pub struct ServerBuilder { 21 | transport: Option, 22 | on_setup: Option, 23 | start_handler: Option>, 24 | mtu: usize, 25 | _c: PhantomData, 26 | } 27 | 28 | impl ServerBuilder 29 | where 30 | T: Send + Sync + ServerTransport, 31 | C: Send + Sync + Transport, 32 | { 33 | pub(crate) fn new() -> ServerBuilder { 34 | ServerBuilder { 35 | transport: None, 36 | on_setup: None, 37 | start_handler: None, 38 | mtu: 0, 39 | _c: PhantomData, 40 | } 41 | } 42 | pub fn fragment(mut self, mtu: usize) -> Self { 43 | if mtu > 0 && mtu < MIN_MTU { 44 | panic!("invalid fragment mtu: at least {}!", MIN_MTU) 45 | } 46 | self.mtu = mtu; 47 | self 48 | } 49 | 50 | pub fn acceptor(mut self, handler: ServerResponder) -> Self { 51 | self.on_setup = Some(handler); 52 | self 53 | } 54 | 55 | pub fn on_start(mut self, hanlder: Box) -> Self { 56 | self.start_handler = Some(hanlder); 57 | self 58 | } 59 | 60 | pub fn transport(mut self, transport: T) -> Self { 61 | self.transport = Some(transport); 62 | self 63 | } 64 | } 65 | 66 | impl ServerBuilder 67 | where 68 | T: Send + Sync + ServerTransport + 'static, 69 | C: Send + Sync + Transport + 'static, 70 | { 71 | pub async fn serve(mut self) -> Result<()> { 72 | let mut server_transport = self.transport.take().expect("missing transport"); 73 | // let acceptor = self.on_setup.map(|v| Acceptor::Generate(Arc::new(v))); 74 | 75 | let mtu = self.mtu; 76 | 77 | server_transport.start().await?; 78 | 79 | if let Some(mut invoke) = self.start_handler { 80 | invoke(); 81 | } 82 | 83 | let acceptor = Arc::new(self.on_setup); 84 | while let Some(next) = server_transport.next().await { 85 | match next { 86 | Ok(tp) => { 87 | let acceptor = acceptor.clone(); 88 | runtime::spawn(async move { 89 | if let Err(e) = Self::on_transport(mtu, tp, acceptor).await { 90 | error!("handle transport failed: {}", e); 91 | } 92 | }); 93 | } 94 | Err(e) => { 95 | error!("accept next transport failed: {}", e); 96 | } 97 | } 98 | } 99 | Ok(()) 100 | } 101 | 102 | #[inline] 103 | async fn on_transport(mtu: usize, tp: C, acceptor: Arc>) -> Result<()> { 104 | // Establish connection. 105 | let conn = tp.connect().await?; 106 | let (mut writer, mut reader) = conn.split(); 107 | 108 | // Create frame splitter. 109 | let splitter = if mtu != 0 { 110 | Some(Splitter::new(mtu)) 111 | } else { 112 | None 113 | }; 114 | 115 | // Init duplex socket. 116 | let (snd_tx, mut snd_rx) = mpsc::unbounded_channel::(); 117 | let mut socket = DuplexSocket::new(0, snd_tx, splitter); 118 | 119 | // Begin loop for writing frames. 120 | runtime::spawn(async move { 121 | while let Some(frame) = snd_rx.recv().await { 122 | if let Err(e) = writer.send(frame).await { 123 | error!("write frame failed: {}", e); 124 | break; 125 | } 126 | } 127 | }); 128 | 129 | let (read_tx, mut read_rx) = mpsc::unbounded_channel::(); 130 | 131 | runtime::spawn(async move { 132 | loop { 133 | match reader.next().await { 134 | Some(Ok(frame)) => { 135 | if let Err(e) = read_tx.send(frame) { 136 | error!("forward frame failed: {}", e); 137 | break; 138 | } 139 | } 140 | Some(Err(e)) => { 141 | error!("read frame failed: {}", e); 142 | break; 143 | } 144 | None => { 145 | break; 146 | } 147 | } 148 | } 149 | }); 150 | 151 | while let Some(frame) = read_rx.recv().await { 152 | if let Err(e) = socket.dispatch(frame, acceptor.as_ref().as_ref()).await { 153 | error!("dispatch frame failed: {}", e); 154 | break; 155 | } 156 | } 157 | Ok(()) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /examples/qps.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | 4 | use std::fs::File; 5 | use std::sync::{ 6 | atomic::{AtomicU32, Ordering}, 7 | Arc, 8 | }; 9 | use std::time::SystemTime; 10 | 11 | use clap::{App, Arg}; 12 | use rsocket_rust::prelude::*; 13 | use rsocket_rust::transport::{Connection, Transport}; 14 | use rsocket_rust::Result; 15 | use rsocket_rust_transport_tcp::{TcpClientTransport, UnixClientTransport}; 16 | use rsocket_rust_transport_websocket::WebsocketClientTransport; 17 | use tokio::sync::{oneshot, Notify}; 18 | 19 | async fn connect( 20 | started: oneshot::Sender, 21 | transport: A, 22 | count: u32, 23 | payload_size: usize, 24 | notify: Arc, 25 | ) -> Result<()> 26 | where 27 | A: Send + Sync + Transport + 'static, 28 | B: Send + Sync + Connection + 'static, 29 | { 30 | let client = RSocketFactory::connect() 31 | .transport(transport) 32 | .start() 33 | .await?; 34 | 35 | // simulate customize size payload. 36 | let req = Payload::builder() 37 | .set_data_utf8("_".repeat(payload_size).as_ref()) 38 | .build(); 39 | let start_time = SystemTime::now(); 40 | let counter = Arc::new(AtomicU32::new(0)); 41 | 42 | for _ in 0..count { 43 | let client = client.clone(); 44 | let counter = counter.clone(); 45 | let notify = notify.clone(); 46 | let req = req.clone(); 47 | tokio::spawn(async move { 48 | if let Err(e) = client.request_response(req).await { 49 | error!("request failed: {}", e); 50 | } 51 | let current = counter.fetch_add(1, Ordering::SeqCst) + 1; 52 | if current >= count { 53 | notify.notify_one(); 54 | } 55 | }); 56 | } 57 | started.send(start_time).unwrap(); 58 | Ok(()) 59 | } 60 | 61 | #[tokio::main] 62 | async fn main() -> Result<()> { 63 | env_logger::builder().format_timestamp_millis().init(); 64 | 65 | let cli = App::new("echo") 66 | .version("0.0.0") 67 | .author("Jeffsky ") 68 | .about("An QPS benchmark tool for RSocket.") 69 | .arg( 70 | Arg::with_name("pprof") 71 | .long("pprof") 72 | .required(false) 73 | .takes_value(false) 74 | .help("Enable pprof."), 75 | ) 76 | .arg( 77 | Arg::with_name("count") 78 | .short("c") 79 | .long("count") 80 | .required(false) 81 | .takes_value(true) 82 | .default_value("1000000") 83 | .help("Requests counts."), 84 | ) 85 | .arg( 86 | Arg::with_name("size") 87 | .short("s") 88 | .long("size") 89 | .required(false) 90 | .takes_value(true) 91 | .default_value("1024") 92 | .help("Data size."), 93 | ) 94 | .arg( 95 | Arg::with_name("URL") 96 | .required(false) 97 | .index(1) 98 | .default_value("127.0.0.1:7878") 99 | .help("Connect url"), 100 | ) 101 | .get_matches(); 102 | 103 | let count: u32 = cli 104 | .value_of("count") 105 | .map(|s| s.parse().expect("Invalid count!")) 106 | .unwrap(); 107 | let size: usize = cli 108 | .value_of("size") 109 | .map(|s| s.parse().expect("Invalid size!")) 110 | .unwrap(); 111 | 112 | let mut guard = None; 113 | if cli.is_present("pprof") { 114 | guard = Some(pprof::ProfilerGuard::new(100).unwrap()); 115 | } 116 | 117 | let addr = cli.value_of("URL").unwrap(); 118 | 119 | let notify = Arc::new(Notify::new()); 120 | let (started_tx, started_rx) = oneshot::channel::(); 121 | 122 | if addr.starts_with("ws://") { 123 | connect( 124 | started_tx, 125 | WebsocketClientTransport::from(addr), 126 | count, 127 | size, 128 | notify.clone(), 129 | ) 130 | .await?; 131 | } else if addr.starts_with("unix://") { 132 | connect( 133 | started_tx, 134 | UnixClientTransport::from(addr), 135 | count, 136 | size, 137 | notify.clone(), 138 | ) 139 | .await?; 140 | } else { 141 | connect( 142 | started_tx, 143 | TcpClientTransport::from(addr), 144 | count, 145 | size, 146 | notify.clone(), 147 | ) 148 | .await?; 149 | } 150 | notify.notified().await; 151 | let start_time = started_rx.await.unwrap(); 152 | let costs = SystemTime::now() 153 | .duration_since(start_time) 154 | .unwrap() 155 | .as_millis(); 156 | info!( 157 | "total={}, cost={}ms, qps={}", 158 | count, 159 | costs, 160 | 1000f64 * (count as f64) / (costs as f64) 161 | ); 162 | 163 | if let Some(guard) = guard { 164 | match guard.report().build() { 165 | Ok(report) => { 166 | let file = File::create("flamegraph.svg").unwrap(); 167 | report.flamegraph(file).unwrap(); 168 | } 169 | Err(_) => {} 170 | }; 171 | } 172 | 173 | Ok(()) 174 | } 175 | -------------------------------------------------------------------------------- /rsocket/src/utils.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::future::Future; 3 | use std::pin::Pin; 4 | 5 | use async_stream::stream; 6 | use async_trait::async_trait; 7 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 8 | use futures::{pin_mut, FutureExt, Sink, SinkExt, Stream, StreamExt}; 9 | use tokio::sync::mpsc; 10 | 11 | use super::spi::{Flux, RSocket}; 12 | use crate::error::RSocketError; 13 | use crate::payload::Payload; 14 | use crate::runtime; 15 | use crate::Result; 16 | 17 | pub const DEFAULT_MIME_TYPE: &str = "application/binary"; 18 | 19 | pub struct EchoRSocket; 20 | 21 | #[async_trait] 22 | impl RSocket for EchoRSocket { 23 | async fn metadata_push(&self, req: Payload) -> Result<()> { 24 | info!("{:?}", req); 25 | Ok(()) 26 | } 27 | 28 | async fn fire_and_forget(&self, req: Payload) -> Result<()> { 29 | info!("{:?}", req); 30 | Ok(()) 31 | } 32 | 33 | async fn request_response(&self, req: Payload) -> Result> { 34 | info!("{:?}", req); 35 | Ok(Some(req)) 36 | } 37 | 38 | fn request_stream(&self, req: Payload) -> Flux> { 39 | info!("{:?}", req); 40 | Box::pin(stream! { 41 | yield Ok(req); 42 | }) 43 | } 44 | 45 | fn request_channel(&self, mut reqs: Flux>) -> Flux> { 46 | let (sender, mut receiver) = mpsc::unbounded_channel(); 47 | runtime::spawn(async move { 48 | while let Some(it) = reqs.next().await { 49 | info!("{:?}", it); 50 | sender.send(it).unwrap(); 51 | } 52 | }); 53 | Box::pin(stream! { 54 | while let Some(it) = receiver.recv().await { 55 | yield it; 56 | } 57 | }) 58 | // or returns directly 59 | // reqs 60 | } 61 | } 62 | 63 | pub(crate) struct EmptyRSocket; 64 | 65 | #[async_trait] 66 | impl RSocket for EmptyRSocket { 67 | async fn metadata_push(&self, _req: Payload) -> Result<()> { 68 | Err(anyhow!("UNIMPLEMENT")) 69 | } 70 | 71 | async fn fire_and_forget(&self, _req: Payload) -> Result<()> { 72 | Err(anyhow!("UNIMPLEMENT")) 73 | } 74 | 75 | async fn request_response(&self, _req: Payload) -> Result> { 76 | Err(anyhow!("UNIMPLEMENT")) 77 | } 78 | 79 | fn request_stream(&self, _req: Payload) -> Flux> { 80 | Box::pin(stream! { 81 | yield Err(anyhow!("UNIMPLEMENT")); 82 | }) 83 | } 84 | 85 | fn request_channel(&self, _reqs: Flux>) -> Flux> { 86 | Box::pin(stream! { 87 | yield Err(anyhow!("UNIMPLEMENT")); 88 | }) 89 | } 90 | } 91 | 92 | pub trait Writeable { 93 | fn write_to(&self, bf: &mut BytesMut); 94 | fn len(&self) -> usize; 95 | fn is_empty(&self) -> bool { 96 | self.len() == 0 97 | } 98 | fn bytes(&self) -> Vec { 99 | let mut b = BytesMut::new(); 100 | self.write_to(&mut b); 101 | b.to_vec() 102 | } 103 | } 104 | 105 | #[allow(non_camel_case_types)] 106 | #[derive(Default, Clone, Copy, Debug)] 107 | pub struct u24(u32); 108 | 109 | macro_rules! ux { 110 | ($type:ident) => { 111 | impl From<$type> for u24 { 112 | fn from(n: $type) -> Self { 113 | assert!(n <= Self::MAX as $type); 114 | Self(n as u32) 115 | } 116 | } 117 | impl Into<$type> for u24 { 118 | fn into(self) -> $type { 119 | if (std::$type::MAX as u64) < (std::u16::MAX as u64) { 120 | assert!(self.0 <= (std::$type::MAX as u32)); 121 | } 122 | self.0 as $type 123 | } 124 | } 125 | }; 126 | } 127 | 128 | macro_rules! ix { 129 | ($type:ident) => { 130 | impl From<$type> for u24 { 131 | fn from(n: $type) -> Self { 132 | assert!(n >= Self::MIN as $type && n <= Self::MAX as $type); 133 | Self(n as u32) 134 | } 135 | } 136 | impl Into<$type> for u24 { 137 | fn into(self) -> $type { 138 | if (std::$type::MAX as u64) < (std::u16::MAX as u64) { 139 | assert!(self.0 <= (std::$type::MAX as u32)); 140 | } 141 | self.0 as $type 142 | } 143 | } 144 | }; 145 | } 146 | 147 | ux!(u8); 148 | ux!(u16); 149 | ux!(u32); 150 | ux!(u64); 151 | ux!(usize); 152 | ix!(i8); 153 | ix!(i16); 154 | ix!(i32); 155 | ix!(i64); 156 | ix!(isize); 157 | 158 | impl Writeable for u24 { 159 | fn write_to(&self, bf: &mut BytesMut) { 160 | bf.put_u8((0xFF & (self.0 >> 16)) as u8); 161 | bf.put_u8((0xFF & (self.0 >> 8)) as u8); 162 | bf.put_u8((0xFF & self.0) as u8); 163 | } 164 | fn len(&self) -> usize { 165 | 3 166 | } 167 | } 168 | 169 | impl u24 { 170 | pub const MAX: u32 = 0x00FF_FFFF; 171 | pub const MIN: u32 = 0; 172 | 173 | pub fn parse(b: &[u8]) -> u24 { 174 | assert!(b.len() > 2); 175 | let mut n = 0u32; 176 | n += (b[0] as u32) << 16; 177 | n += (b[1] as u32) << 8; 178 | n += b[2] as u32; 179 | u24(n) 180 | } 181 | 182 | pub fn read(bf: &mut BytesMut) -> u24 { 183 | Self::parse(bf) 184 | } 185 | 186 | pub fn read_advance(bf: &mut BytesMut) -> u24 { 187 | let raw = bf.split_to(3); 188 | Self::parse(&raw) 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /rsocket/src/transport/fragmentation.rs: -------------------------------------------------------------------------------- 1 | use std::collections::LinkedList; 2 | 3 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 4 | 5 | use crate::frame::{self, Body, Frame}; 6 | use crate::payload::Payload; 7 | 8 | pub(crate) const MIN_MTU: usize = 64; 9 | 10 | pub(crate) struct Joiner { 11 | inner: LinkedList, 12 | } 13 | 14 | #[derive(Debug, Clone)] 15 | pub(crate) struct Splitter { 16 | mtu: usize, 17 | } 18 | 19 | impl Splitter { 20 | pub(crate) fn new(mtu: usize) -> Splitter { 21 | assert!(mtu > frame::LEN_HEADER, "mtu is too small!"); 22 | Splitter { mtu } 23 | } 24 | 25 | pub(crate) fn cut(&self, input: Payload, skip: usize) -> impl Iterator { 26 | let (data, meta) = input.split(); 27 | SplitterIter { 28 | mtu: self.mtu, 29 | skip, 30 | data, 31 | meta, 32 | } 33 | } 34 | } 35 | 36 | struct SplitterIter { 37 | mtu: usize, 38 | skip: usize, 39 | data: Option, 40 | meta: Option, 41 | } 42 | 43 | impl Iterator for SplitterIter { 44 | type Item = Payload; 45 | 46 | fn next(&mut self) -> Option { 47 | if self.meta.is_none() && self.data.is_none() { 48 | return None; 49 | } 50 | let mut m: Option = None; 51 | let mut d: Option = None; 52 | let mut left = self.mtu - frame::LEN_HEADER - self.skip; 53 | if let Some(it) = &mut self.meta { 54 | let msize = it.len(); 55 | if left < msize { 56 | m = Some(it.split_to(left)); 57 | left = 0; 58 | } else { 59 | m = self.meta.take(); 60 | left -= msize; 61 | } 62 | } 63 | 64 | if left > 0 { 65 | if let Some(it) = &mut self.data { 66 | let dsize = it.len(); 67 | if left < dsize { 68 | d = Some(it.split_to(left)); 69 | } else { 70 | d = self.data.take(); 71 | } 72 | } 73 | } 74 | self.skip = 0; 75 | Some(Payload::new(d, m)) 76 | } 77 | } 78 | 79 | impl Into for Joiner { 80 | fn into(self) -> Payload { 81 | let mut bf = BytesMut::new(); 82 | let mut bf2 = BytesMut::new(); 83 | self.inner.into_iter().for_each(|it: Frame| { 84 | let (d, m) = match it.body { 85 | Body::RequestResponse(body) => body.split(), 86 | Body::RequestStream(body) => body.split(), 87 | Body::RequestChannel(body) => body.split(), 88 | Body::RequestFNF(body) => body.split(), 89 | Body::Payload(body) => body.split(), 90 | _ => (None, None), 91 | }; 92 | if let Some(raw) = d { 93 | bf.put(raw); 94 | } 95 | if let Some(raw) = m { 96 | bf2.put(raw); 97 | } 98 | }); 99 | 100 | let data = if bf.is_empty() { 101 | None 102 | } else { 103 | Some(bf.freeze()) 104 | }; 105 | let metadata = if bf2.is_empty() { 106 | None 107 | } else { 108 | Some(bf2.freeze()) 109 | }; 110 | Payload::new(data, metadata) 111 | } 112 | } 113 | 114 | impl Joiner { 115 | pub(crate) fn new() -> Joiner { 116 | Joiner { 117 | inner: LinkedList::new(), 118 | } 119 | } 120 | 121 | pub(crate) fn get_stream_id(&self) -> u32 { 122 | self.first().get_stream_id() 123 | } 124 | 125 | pub(crate) fn get_flag(&self) -> u16 { 126 | self.first().get_flag() & !Frame::FLAG_FOLLOW 127 | } 128 | 129 | pub(crate) fn first(&self) -> &Frame { 130 | self.inner.front().expect("No frames pushed!") 131 | } 132 | 133 | pub(crate) fn push(&mut self, next: Frame) { 134 | self.inner.push_back(next); 135 | } 136 | } 137 | 138 | #[cfg(test)] 139 | mod tests { 140 | 141 | use bytes::{Buf, Bytes}; 142 | 143 | use crate::frame::{self, Frame}; 144 | use crate::payload::Payload; 145 | use crate::transport::{Joiner, Splitter}; 146 | 147 | #[test] 148 | fn test_joiner() { 149 | let first = frame::Payload::builder(1, Frame::FLAG_FOLLOW) 150 | .set_data(Bytes::from("(ROOT)")) 151 | .set_metadata(Bytes::from("(ROOT)")) 152 | .build(); 153 | let mut joiner = Joiner::new(); 154 | joiner.push(first); 155 | 156 | for i in 0..10 { 157 | let flag = if i == 9 { 0u16 } else { Frame::FLAG_FOLLOW }; 158 | let next = frame::Payload::builder(1, flag) 159 | .set_data(Bytes::from(format!("(data{:04})", i))) 160 | .set_metadata(Bytes::from(format!("(data{:04})", i))) 161 | .build(); 162 | joiner.push(next); 163 | } 164 | let pa: Payload = joiner.into(); 165 | println!("payload: {:?}", pa); 166 | } 167 | 168 | #[test] 169 | fn test_splitter() { 170 | let input = Payload::builder() 171 | .set_data_utf8("helloworld") 172 | .set_metadata_utf8("foobar") 173 | .build(); 174 | let mut sp = Splitter::new(13); 175 | for (i, it) in sp.cut(input.clone(), 0).enumerate() { 176 | println!("{}: {:?}", i, it); 177 | } 178 | println!("MODE 100"); 179 | sp = Splitter::new(100); 180 | for (i, it) in sp.cut(input.clone(), 0).enumerate() { 181 | println!("{}: {:?}", i, it); 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rsocket-rust 2 | 3 | ![GitHub Workflow Status](https://github.com/rsocket/rsocket-rust/workflows/Rust/badge.svg) 4 | [![Build Status](https://travis-ci.com/rsocket/rsocket-rust.svg?branch=master)](https://travis-ci.com/rsocket/rsocket-rust) 5 | [![Crates.io](https://img.shields.io/crates/v/rsocket_rust)](https://crates.io/crates/rsocket_rust) 6 | [![Crates.io](https://img.shields.io/crates/d/rsocket_rust)](https://crates.io/crates/rsocket_rust) 7 | [![License](https://img.shields.io/github/license/rsocket/rsocket-rust.svg)](https://github.com/rsocket/rsocket-rust/blob/master/LICENSE) 8 | [![GitHub Release](https://img.shields.io/github/release-pre/rsocket/rsocket-rust.svg)](https://github.com/rsocket/rsocket-rust/releases) 9 | 10 | > rsocket-rust is an implementation of the RSocket protocol in Rust(1.39+). It's 11 | > an **alpha** version and still under active development. **Do not use it in a 12 | > production environment!** 13 | 14 | ## Example 15 | 16 | > Here are some example codes which show how RSocket works in Rust. 17 | 18 | ### Dependencies 19 | 20 | Add dependencies in your `Cargo.toml`. 21 | 22 | ```toml 23 | [dependencies] 24 | tokio = "1.0.3" 25 | rsocket_rust = "0.7" 26 | 27 | # add transport dependencies: 28 | # rsocket_rust_transport_tcp = "0.7" 29 | # rsocket_rust_transport_websocket = "0.7" 30 | ``` 31 | 32 | ### Server 33 | 34 | ```rust 35 | extern crate log; 36 | 37 | use futures::executor::block_on; 38 | use rsocket_rust::prelude::*; 39 | use rsocket_rust::utils::EchoRSocket; 40 | use rsocket_rust::Result; 41 | use rsocket_rust_transport_tcp::*; 42 | 43 | #[tokio::main] 44 | async fn main() -> Result<()> { 45 | env_logger::builder().format_timestamp_millis().init(); 46 | 47 | RSocketFactory::receive() 48 | .transport(TcpServerTransport::from("127.0.0.1:7979")) 49 | .acceptor(Box::new(|setup, _sending_socket| { 50 | info!("incoming socket: setup={:?}", setup); 51 | Ok(Box::new(block_on(async move { 52 | RSocketFactory::connect() 53 | .transport(TcpClientTransport::from("127.0.0.1:7878")) 54 | .acceptor(Box::new(|| Box::new(EchoRSocket))) 55 | .setup(Payload::from("I'm Rust!")) 56 | .start() 57 | .await 58 | .unwrap() 59 | }))) 60 | })) 61 | .serve() 62 | .await 63 | } 64 | ``` 65 | 66 | ### Client 67 | 68 | ```rust 69 | extern crate log; 70 | 71 | use rsocket_rust::prelude::*; 72 | use rsocket_rust::utils::EchoRSocket; 73 | use rsocket_rust::Result; 74 | use rsocket_rust_transport_tcp::TcpClientTransport; 75 | 76 | #[tokio::main] 77 | async fn main() -> Result<()> { 78 | env_logger::builder().format_timestamp_millis().init(); 79 | let client = RSocketFactory::connect() 80 | .transport(TcpClientTransport::from("127.0.0.1:7878")) 81 | .acceptor(Box::new(|| { 82 | // Return a responder. 83 | Box::new(EchoRSocket) 84 | })) 85 | .start() 86 | .await 87 | .expect("Connect failed!"); 88 | 89 | let req = Payload::builder().set_data_utf8("Ping!").build(); 90 | 91 | match client.request_response(req).await { 92 | Ok(res) => info!("{:?}", res), 93 | Err(e) => error!("{}", e), 94 | } 95 | 96 | Ok(()) 97 | } 98 | ``` 99 | 100 | ### Implement RSocket trait 101 | 102 | Example for access Redis([crates](https://crates.io/crates/redis)): 103 | 104 | > NOTICE: add dependency in Cargo.toml => redis = { version = "0.19.0", features 105 | > = [ "aio" ] } 106 | 107 | ```rust 108 | use std::str::FromStr; 109 | 110 | use redis::Client as RedisClient; 111 | use rsocket_rust::async_trait; 112 | use rsocket_rust::prelude::*; 113 | use rsocket_rust::Result; 114 | 115 | #[derive(Clone)] 116 | pub struct RedisDao { 117 | inner: RedisClient, 118 | } 119 | 120 | // Create RedisDao from str. 121 | // Example: RedisDao::from_str("redis://127.0.0.1").expect("Connect redis failed!"); 122 | impl FromStr for RedisDao { 123 | type Err = redis::RedisError; 124 | 125 | fn from_str(s: &str) -> std::result::Result { 126 | let client = redis::Client::open(s)?; 127 | Ok(RedisDao { inner: client }) 128 | } 129 | } 130 | 131 | #[async_trait] 132 | impl RSocket for RedisDao { 133 | async fn request_response(&self, req: Payload) -> Result> { 134 | let client = self.inner.clone(); 135 | let mut conn = client.get_async_connection().await?; 136 | let value: redis::RedisResult> = redis::cmd("GET") 137 | .arg(&[req.data_utf8()]) 138 | .query_async(&mut conn) 139 | .await; 140 | match value { 141 | Ok(Some(value)) => Ok(Some(Payload::builder().set_data_utf8(&value).build())), 142 | Ok(None) => Ok(None), 143 | Err(e) => Err(e.into()), 144 | } 145 | } 146 | 147 | async fn metadata_push(&self, _req: Payload) -> Result<()> { 148 | todo!() 149 | } 150 | 151 | async fn fire_and_forget(&self, _req: Payload) -> Result<()> { 152 | todo!() 153 | } 154 | 155 | fn request_stream(&self, _req: Payload) -> Flux> { 156 | todo!() 157 | } 158 | 159 | fn request_channel(&self, _reqs: Flux>) -> Flux> { 160 | todo!() 161 | } 162 | } 163 | ``` 164 | 165 | ## TODO 166 | 167 | - Operations 168 | - [x] METADATA_PUSH 169 | - [x] REQUEST_FNF 170 | - [x] REQUEST_RESPONSE 171 | - [x] REQUEST_STREAM 172 | - [x] REQUEST_CHANNEL 173 | - More Operations 174 | - [x] Error 175 | - [ ] Cancel 176 | - [x] Fragmentation 177 | - [ ] Resume 178 | - [x] Keepalive 179 | - QoS 180 | - [ ] RequestN 181 | - [ ] Lease 182 | - Transport 183 | - [x] TCP 184 | - [x] Websocket 185 | - [x] WASM 186 | - Reactor 187 | - [ ] ... 188 | - High Level APIs 189 | - [x] Client 190 | - [x] Server 191 | -------------------------------------------------------------------------------- /rsocket-transport-wasm/src/client.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::future::Future; 3 | use std::rc::Rc; 4 | 5 | use bytes::BytesMut; 6 | use futures_channel::{mpsc, oneshot}; 7 | use futures_util::StreamExt; 8 | use js_sys::{ArrayBuffer, Uint8Array}; 9 | use rsocket_rust::frame::Frame; 10 | use rsocket_rust::transport::Transport; 11 | use rsocket_rust::utils::Writeable; 12 | use rsocket_rust::{async_trait, error::RSocketError, Result}; 13 | use wasm_bindgen::prelude::*; 14 | use wasm_bindgen::JsCast; 15 | use web_sys::{ErrorEvent, Event, FileReader, MessageEvent, ProgressEvent, WebSocket}; 16 | 17 | use super::connection::WebsocketConnection; 18 | 19 | pub struct WebsocketClientTransport { 20 | url: String, 21 | } 22 | 23 | impl WebsocketClientTransport { 24 | #[inline] 25 | fn wait_for_open(ws: &WebSocket) -> impl Future { 26 | let (sender, receiver) = oneshot::channel(); 27 | // The Closure is only called once, so we can use Closure::once 28 | let on_open = Closure::once(move |_e: Event| { 29 | // We don't need to send a value, so we just send () 30 | sender.send(()).unwrap(); 31 | }); 32 | ws.set_onopen(Some(on_open.as_ref().unchecked_ref())); 33 | async move { 34 | // Wait for it to open 35 | receiver.await.unwrap(); 36 | // Clean up the Closure so we don't leak any memory 37 | drop(on_open); 38 | } 39 | } 40 | 41 | #[inline] 42 | fn read_binary(value: JsValue, mut incoming: mpsc::Sender) { 43 | let reader = FileReader::new().unwrap_throw(); 44 | let state = Rc::new(RefCell::new(None)); 45 | let onload = { 46 | let state = state.clone(); 47 | let reader = reader.clone(); 48 | Closure::once(move |_: ProgressEvent| { 49 | *state.borrow_mut() = None; 50 | let data: ArrayBuffer = reader.result().unwrap_throw().unchecked_into(); 51 | let raw: Vec = Uint8Array::new(&data).to_vec(); 52 | // Use data... 53 | let mut bf = BytesMut::from(&raw[..]); 54 | let msg = Frame::decode(&mut bf).unwrap(); 55 | incoming.try_send(msg).unwrap(); 56 | }) 57 | }; 58 | let onerror = { 59 | let state = state.clone(); 60 | Closure::once(move |_: ErrorEvent| { 61 | *state.borrow_mut() = None; 62 | // let err = e.error(); 63 | // let error = reader.error().unwrap_throw(); 64 | // TODO: Handle error... 65 | }) 66 | }; 67 | reader.set_onload(Some(onload.as_ref().unchecked_ref())); 68 | reader.set_onerror(Some(onerror.as_ref().unchecked_ref())); 69 | *state.borrow_mut() = Some((onload, onerror)); 70 | reader 71 | .read_as_array_buffer(value.as_ref().unchecked_ref()) 72 | .unwrap_throw(); 73 | } 74 | } 75 | 76 | #[async_trait] 77 | impl Transport for WebsocketClientTransport { 78 | type Conn = WebsocketConnection; 79 | 80 | async fn connect(self) -> Result { 81 | let (rcv_tx, rcv_rx) = mpsc::channel::(32); 82 | let (snd_tx, mut snd_rx) = mpsc::channel::(32); 83 | let (connected, connected_rx) = oneshot::channel::>(); 84 | wasm_bindgen_futures::spawn_local(async move { 85 | match WebSocket::new(&self.url) { 86 | Ok(ws) => { 87 | // on message 88 | let on_message = Closure::wrap(Box::new(move |e: MessageEvent| { 89 | let data: JsValue = e.data(); 90 | Self::read_binary(data, rcv_tx.clone()); 91 | }) 92 | as Box); 93 | ws.set_onmessage(Some(on_message.as_ref().unchecked_ref())); 94 | on_message.forget(); 95 | 96 | // on error 97 | let on_error = Closure::wrap(Box::new(move |e: ErrorEvent| { 98 | log::error!("websocket error: {}", e.message()); 99 | }) 100 | as Box); 101 | ws.set_onerror(Some(on_error.as_ref().unchecked_ref())); 102 | on_error.forget(); 103 | 104 | // on_close 105 | let on_close = Closure::once(Box::new(move |_e: Event| { 106 | log::info!("websocket closed"); 107 | }) as Box); 108 | ws.set_onclose(Some(on_close.as_ref().unchecked_ref())); 109 | on_close.forget(); 110 | 111 | Self::wait_for_open(&ws).await; 112 | 113 | connected.send(Ok(())).unwrap(); 114 | 115 | while let Some(v) = snd_rx.next().await { 116 | let mut bf = BytesMut::new(); 117 | v.write_to(&mut bf); 118 | let raw = bf.to_vec(); 119 | ws.send_with_u8_array(&raw[..]) 120 | .expect("write data into websocket failed."); 121 | } 122 | } 123 | Err(e) => { 124 | let msg = e.as_string().unwrap(); 125 | connected 126 | .send(Err(RSocketError::WithDescription(msg).into())) 127 | .unwrap(); 128 | } 129 | } 130 | }); 131 | match connected_rx.await.expect("connected channel closed") { 132 | Ok(_) => Ok(WebsocketConnection::new(snd_tx, rcv_rx)), 133 | Err(e) => Err(e), 134 | } 135 | } 136 | } 137 | 138 | impl From for WebsocketClientTransport 139 | where 140 | I: Into, 141 | { 142 | fn from(url: I) -> WebsocketClientTransport { 143 | WebsocketClientTransport { url: url.into() } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /rsocket/src/extension/composite.rs: -------------------------------------------------------------------------------- 1 | use std::collections::LinkedList; 2 | use std::convert::TryFrom; 3 | use std::result::Result; 4 | 5 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 6 | 7 | use super::mime::MimeType; 8 | use crate::error::RSocketError; 9 | use crate::utils::{u24, Writeable}; 10 | 11 | const MAX_MIME_LEN: usize = 0x7F + 1; 12 | 13 | #[derive(Debug, Clone, Eq, PartialEq, Default)] 14 | pub struct CompositeMetadata { 15 | metadatas: LinkedList, 16 | } 17 | 18 | #[derive(Debug, Clone, Eq, PartialEq)] 19 | pub struct CompositeMetadataEntry { 20 | mime_type: MimeType, 21 | metadata: Bytes, 22 | } 23 | 24 | pub struct CompositeMetadataBuilder { 25 | inner: CompositeMetadata, 26 | } 27 | 28 | impl CompositeMetadataBuilder { 29 | pub fn push(mut self, mime_type: MimeType, payload: A) -> Self 30 | where 31 | A: AsRef<[u8]>, 32 | { 33 | let mut bf = BytesMut::new(); 34 | bf.put_slice(payload.as_ref()); 35 | let m = CompositeMetadataEntry::new(mime_type, bf.freeze()); 36 | self.inner.push(m); 37 | self 38 | } 39 | 40 | pub fn push_entry(mut self, metadata: CompositeMetadataEntry) -> Self { 41 | self.inner.push(metadata); 42 | self 43 | } 44 | 45 | pub fn build(self) -> CompositeMetadata { 46 | self.inner 47 | } 48 | } 49 | 50 | impl Into> for CompositeMetadata { 51 | fn into(self) -> Vec { 52 | let mut bf = BytesMut::new(); 53 | self.write_to(&mut bf); 54 | bf.to_vec() 55 | } 56 | } 57 | 58 | impl Into for CompositeMetadata { 59 | fn into(self) -> Bytes { 60 | let mut bf = BytesMut::new(); 61 | self.write_to(&mut bf); 62 | bf.freeze() 63 | } 64 | } 65 | 66 | impl Into for CompositeMetadata { 67 | fn into(self) -> BytesMut { 68 | let mut bf = BytesMut::new(); 69 | self.write_to(&mut bf); 70 | bf 71 | } 72 | } 73 | 74 | impl Writeable for CompositeMetadata { 75 | fn write_to(&self, bf: &mut BytesMut) { 76 | for it in self.iter() { 77 | it.write_to(bf); 78 | } 79 | } 80 | 81 | fn len(&self) -> usize { 82 | let mut n = 0; 83 | for it in self.iter() { 84 | n += it.len(); 85 | } 86 | n 87 | } 88 | } 89 | 90 | impl CompositeMetadata { 91 | pub fn builder() -> CompositeMetadataBuilder { 92 | CompositeMetadataBuilder { 93 | inner: CompositeMetadata::default(), 94 | } 95 | } 96 | 97 | pub fn decode(b: &mut BytesMut) -> crate::Result { 98 | let mut metadatas = LinkedList::new(); 99 | loop { 100 | match Self::decode_once(b) { 101 | Ok(Some(v)) => metadatas.push_back(v), 102 | Ok(None) => break, 103 | Err(e) => return Err(e), 104 | } 105 | } 106 | Ok(CompositeMetadata { metadatas }) 107 | } 108 | 109 | pub fn iter(&self) -> impl Iterator { 110 | self.metadatas.iter() 111 | } 112 | 113 | #[inline] 114 | fn decode_once(bs: &mut BytesMut) -> crate::Result> { 115 | if bs.is_empty() { 116 | return Ok(None); 117 | } 118 | let first: u8 = bs.get_u8(); 119 | let mime_type = if 0x80 & first != 0 { 120 | // Well 121 | let n = first & 0x7F; 122 | MimeType::WellKnown(n) 123 | } else { 124 | // Bad 125 | let mime_len = (first as usize) + 1; 126 | if bs.len() < mime_len { 127 | return Err(RSocketError::WithDescription( 128 | "broken composite metadata: empty MIME type!".into(), 129 | ) 130 | .into()); 131 | } 132 | let front = bs.split_to(mime_len); 133 | MimeType::Normal(String::from_utf8(front.to_vec())?) 134 | }; 135 | 136 | if bs.len() < 3 { 137 | return Err(RSocketError::WithDescription( 138 | "broken composite metadata: not enough bytes!".into(), 139 | ) 140 | .into()); 141 | } 142 | let payload_size = u24::read_advance(bs).into(); 143 | if bs.len() < payload_size { 144 | let desc = format!("broken composite metadata: require {} bytes!", payload_size); 145 | return Err(RSocketError::WithDescription(desc).into()); 146 | } 147 | let metadata = bs.split_to(payload_size).freeze(); 148 | Ok(Some(CompositeMetadataEntry::new(mime_type, metadata))) 149 | } 150 | 151 | pub fn push(&mut self, metadata: CompositeMetadataEntry) { 152 | self.metadatas.push_back(metadata) 153 | } 154 | } 155 | 156 | impl CompositeMetadataEntry { 157 | pub fn new(mime_type: MimeType, metadata: Bytes) -> CompositeMetadataEntry { 158 | assert!(metadata.len() <= (u24::MAX as usize)); 159 | CompositeMetadataEntry { 160 | mime_type, 161 | metadata, 162 | } 163 | } 164 | 165 | pub fn get_mime_type(&self) -> &MimeType { 166 | &self.mime_type 167 | } 168 | 169 | pub fn get_metadata(&self) -> &Bytes { 170 | &self.metadata 171 | } 172 | 173 | pub fn get_metadata_utf8(&self) -> Option<&str> { 174 | std::str::from_utf8(&self.metadata).ok() 175 | } 176 | } 177 | 178 | impl Writeable for CompositeMetadataEntry { 179 | fn write_to(&self, bf: &mut BytesMut) { 180 | match &self.mime_type { 181 | MimeType::WellKnown(n) => { 182 | // WellKnown 183 | bf.put_u8(0x80 | n); 184 | } 185 | MimeType::Normal(s) => { 186 | // NotWellKnown 187 | let mime_type_len = s.len() as u8; 188 | assert!(mime_type_len > 0, "invalid length of MimeType!"); 189 | bf.put_u8(mime_type_len - 1); 190 | bf.extend_from_slice(s.as_ref()); 191 | } 192 | }; 193 | let metadata_len = self.metadata.len(); 194 | u24::from(metadata_len).write_to(bf); 195 | if metadata_len > 0 { 196 | bf.extend_from_slice(&self.metadata); 197 | } 198 | } 199 | 200 | fn len(&self) -> usize { 201 | // 1byte(MIME) + 3bytes(length of payload in u24) 202 | let mut amount = 4; 203 | if let MimeType::Normal(s) = &self.mime_type { 204 | amount += s.len(); 205 | } 206 | amount += self.metadata.len(); 207 | amount 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /rsocket/src/extension/mime.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::convert::TryInto; 3 | use std::fmt; 4 | 5 | use once_cell::sync::Lazy; 6 | 7 | use crate::error::RSocketError; 8 | use crate::Result; 9 | 10 | #[derive(PartialEq, Eq, Debug, Clone, Hash)] 11 | pub enum MimeType { 12 | Normal(String), 13 | WellKnown(u8), 14 | } 15 | 16 | static U8_TO_STR: Lazy> = Lazy::new(|| { 17 | let mut m = HashMap::new(); 18 | for it in list_all().iter() { 19 | m.insert(it.0, it.1); 20 | } 21 | m 22 | }); 23 | 24 | static STR_TO_U8: Lazy> = Lazy::new(|| { 25 | let mut m = HashMap::new(); 26 | for it in list_all().iter() { 27 | m.insert(it.1, it.0); 28 | } 29 | m 30 | }); 31 | 32 | impl MimeType { 33 | pub fn parse(value: u8) -> Option { 34 | U8_TO_STR.get(&value).map(|it| Self::WellKnown(value)) 35 | } 36 | 37 | pub fn as_u8(&self) -> Option { 38 | match self { 39 | Self::WellKnown(n) => Some(*n), 40 | Self::Normal(_) => None, 41 | } 42 | } 43 | 44 | pub fn as_str(&self) -> Option<&str> { 45 | match self { 46 | Self::Normal(s) => Some(s.as_ref()), 47 | Self::WellKnown(n) => U8_TO_STR.get(n).copied(), 48 | } 49 | } 50 | } 51 | 52 | impl Into for MimeType { 53 | fn into(self) -> String { 54 | match self { 55 | Self::Normal(s) => s, 56 | Self::WellKnown(n) => match U8_TO_STR.get(&n) { 57 | Some(v) => v.to_string(), 58 | None => "UNKNOWN".to_string(), 59 | }, 60 | } 61 | } 62 | } 63 | 64 | impl From<&str> for MimeType { 65 | fn from(value: &str) -> MimeType { 66 | match STR_TO_U8.get(value) { 67 | Some(v) => Self::WellKnown(*v), 68 | None => Self::Normal(value.to_owned()), 69 | } 70 | } 71 | } 72 | 73 | impl fmt::Display for MimeType { 74 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 75 | match self { 76 | Self::Normal(s) => write!(f, "{}", s), 77 | Self::WellKnown(n) => match U8_TO_STR.get(n) { 78 | Some(v) => write!(f, "{}", v), 79 | None => Err(fmt::Error), 80 | }, 81 | } 82 | } 83 | } 84 | 85 | macro_rules! mime { 86 | ($name:ident,$n:expr,$s:expr) => { 87 | const $name: (u8, &str) = ($n, $s); 88 | impl MimeType { 89 | pub const $name: Self = Self::WellKnown($n); 90 | } 91 | }; 92 | } 93 | 94 | mime!(APPLICATION_AVRO, 0x00, "application/avro"); 95 | mime!(APPLICATION_CBOR, 0x01, "application/avro"); 96 | mime!(APPLICATION_GRAPHQL, 0x02, "application/graphql"); 97 | mime!(APPLICATION_GZIP, 0x03, "application/gzip"); 98 | mime!(APPLICATION_JAVASCRIPT, 0x04, "application/javascript"); 99 | mime!(APPLICATION_JSON, 0x05, "application/json"); 100 | mime!(APPLICATION_OCTET_STREAM, 0x06, "application/octet-stream"); 101 | mime!(APPLICATION_PDF, 0x07, "application/pdf"); 102 | mime!( 103 | APPLICATION_VND_APACHE_THRIFT_BINARY, 104 | 0x08, 105 | "application/vnd.apache.thrift.binary" 106 | ); 107 | mime!( 108 | APPLICATION_VND_GOOGLE_PROTOBUF, 109 | 0x09, 110 | "application/vnd.google.protobuf" 111 | ); 112 | mime!(APPLICATION_XML, 0x0A, "application/xml"); 113 | mime!(APPLICATION_ZIP, 0x0B, "application/zip"); 114 | mime!(AUDIO_AAC, 0x0C, "audio/aac"); 115 | mime!(AUDIO_MP3, 0x0D, "audio/mp3"); 116 | mime!(AUDIO_MP4, 0x0E, "audio/mp4"); 117 | mime!(AUDIO_MPEG3, 0x0F, "audio/mpeg3"); 118 | mime!(AUDIO_MPEG, 0x10, "audio/mpeg"); 119 | mime!(AUDIO_OGG, 0x11, "audio/ogg"); 120 | mime!(AUDIO_OPUS, 0x12, "audio/opus"); 121 | mime!(AUDIO_VORBIS, 0x13, "audio/vorbis"); 122 | mime!(IMAGE_BMP, 0x14, "image/bmp"); 123 | mime!(IMAGE_GIF, 0x15, "image/gif"); 124 | mime!(IMAGE_HEIC_SEQUENCE, 0x16, "image/heic-sequence"); 125 | mime!(IMAGE_HEIC, 0x17, "image/heic"); 126 | mime!(IMAGE_HEIF_SEQUENCE, 0x18, "image/heif-sequence"); 127 | mime!(IMAGE_HEIF, 0x19, "image/heif"); 128 | mime!(IMAGE_JPEG, 0x1A, "image/jpeg"); 129 | mime!(IMAGE_PNG, 0x1B, "image/png"); 130 | mime!(IMAGE_TIFF, 0x1C, "image/tiff"); 131 | mime!(MULTIPART_MIXED, 0x1D, "multipart/mixed"); 132 | mime!(TEXT_CSS, 0x1E, "text/css"); 133 | mime!(TEXT_CSV, 0x1F, "text/csv"); 134 | mime!(TEXT_HTML, 0x20, "text/html"); 135 | mime!(TEXT_PLAIN, 0x21, "text/plain"); 136 | mime!(TEXT_XML, 0x22, "text/xml"); 137 | mime!(VIDEO_H264, 0x23, "video/H264"); 138 | mime!(VIDEO_H265, 0x24, "video/H265"); 139 | mime!(VIDEO_VP8, 0x25, "video/VP8"); 140 | mime!(APPLICATION_X_HESSIAN, 0x26, "application/x-hessian"); 141 | mime!(APPLICATION_X_JAVA_OBJECT, 0x27, "application/x-java-object"); 142 | mime!( 143 | APPLICATION_CLOUDEVENTS_JSON, 144 | 0x28, 145 | "application/cloudevents+json" 146 | ); 147 | mime!( 148 | MESSAGE_X_RSOCKET_MIME_TYPE_V0, 149 | 0x7A, 150 | "message/x.rsocket.mime-type.v0" 151 | ); 152 | mime!( 153 | MESSAGE_X_RSOCKET_ACCEPT_TIME_TYPES_V0, 154 | 0x7B, 155 | "message/x.rsocket.accept-mime-types.v0" 156 | ); 157 | mime!( 158 | MESSAGE_X_RSOCKET_AUTHENTICATION_V0, 159 | 0x7C, 160 | "message/x.rsocket.authentication.v0" 161 | ); 162 | mime!( 163 | MESSAGE_X_RSOCKET_TRACING_ZIPKIN_V0, 164 | 0x7D, 165 | "message/x.rsocket.tracing-zipkin.v0" 166 | ); 167 | mime!( 168 | MESSAGE_X_RSOCKET_ROUTING_V0, 169 | 0x7E, 170 | "message/x.rsocket.routing.v0" 171 | ); 172 | mime!( 173 | MESSAGE_X_RSOCKET_COMPOSITE_METADATA_V0, 174 | 0x7F, 175 | "message/x.rsocket.composite-metadata.v0" 176 | ); 177 | 178 | fn list_all() -> Vec<(u8, &'static str)> { 179 | vec![ 180 | APPLICATION_AVRO, 181 | APPLICATION_CBOR, 182 | APPLICATION_GRAPHQL, 183 | APPLICATION_GZIP, 184 | APPLICATION_JAVASCRIPT, 185 | APPLICATION_JSON, 186 | APPLICATION_OCTET_STREAM, 187 | APPLICATION_PDF, 188 | APPLICATION_VND_APACHE_THRIFT_BINARY, 189 | APPLICATION_VND_GOOGLE_PROTOBUF, 190 | APPLICATION_XML, 191 | APPLICATION_ZIP, 192 | AUDIO_AAC, 193 | AUDIO_MP3, 194 | AUDIO_MP4, 195 | AUDIO_MPEG3, 196 | AUDIO_MPEG, 197 | AUDIO_OGG, 198 | AUDIO_OPUS, 199 | AUDIO_VORBIS, 200 | IMAGE_BMP, 201 | IMAGE_GIF, 202 | IMAGE_HEIC_SEQUENCE, 203 | IMAGE_HEIC, 204 | IMAGE_HEIF_SEQUENCE, 205 | IMAGE_HEIF, 206 | IMAGE_JPEG, 207 | IMAGE_PNG, 208 | IMAGE_TIFF, 209 | MULTIPART_MIXED, 210 | TEXT_CSS, 211 | TEXT_CSV, 212 | TEXT_HTML, 213 | TEXT_PLAIN, 214 | TEXT_XML, 215 | VIDEO_H264, 216 | VIDEO_H265, 217 | VIDEO_VP8, 218 | APPLICATION_X_HESSIAN, 219 | APPLICATION_X_JAVA_OBJECT, 220 | APPLICATION_CLOUDEVENTS_JSON, 221 | MESSAGE_X_RSOCKET_MIME_TYPE_V0, 222 | MESSAGE_X_RSOCKET_ACCEPT_TIME_TYPES_V0, 223 | MESSAGE_X_RSOCKET_AUTHENTICATION_V0, 224 | MESSAGE_X_RSOCKET_TRACING_ZIPKIN_V0, 225 | MESSAGE_X_RSOCKET_ROUTING_V0, 226 | MESSAGE_X_RSOCKET_COMPOSITE_METADATA_V0, 227 | ] 228 | } 229 | -------------------------------------------------------------------------------- /rsocket/src/frame/setup.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 4 | 5 | use super::utils; 6 | use super::{Body, Frame, Version}; 7 | use crate::error::RSocketError; 8 | use crate::utils::{Writeable, DEFAULT_MIME_TYPE}; 9 | 10 | #[derive(Debug, Eq, PartialEq)] 11 | pub struct Setup { 12 | version: Version, 13 | keepalive: u32, 14 | lifetime: u32, 15 | token: Option, 16 | mime_metadata: Bytes, 17 | mime_data: Bytes, 18 | metadata: Option, 19 | data: Option, 20 | } 21 | 22 | pub struct SetupBuilder { 23 | stream_id: u32, 24 | flag: u16, 25 | value: Setup, 26 | } 27 | 28 | impl Setup { 29 | pub(crate) fn decode(flag: u16, b: &mut BytesMut) -> crate::Result { 30 | // Check minimal length: version(4bytes) + keepalive(4bytes) + lifetime(4bytes) 31 | if b.len() < 12 { 32 | return Err(RSocketError::InCompleteFrame.into()); 33 | } 34 | let major = b.get_u16(); 35 | let minor = b.get_u16(); 36 | let keepalive = b.get_u32(); 37 | let lifetime = b.get_u32(); 38 | let token: Option = if flag & Frame::FLAG_RESUME != 0 { 39 | if b.len() < 2 { 40 | return Err(RSocketError::InCompleteFrame.into()); 41 | } 42 | let token_length = b.get_u16() as usize; 43 | if b.len() < token_length { 44 | return Err(RSocketError::InCompleteFrame.into()); 45 | } 46 | Some(b.split_to(token_length).freeze()) 47 | } else { 48 | None 49 | }; 50 | if b.is_empty() { 51 | return Err(RSocketError::InCompleteFrame.into()); 52 | } 53 | let mut mime_type_length: usize = b[0] as usize; 54 | b.advance(1); 55 | if b.len() < mime_type_length { 56 | return Err(RSocketError::InCompleteFrame.into()); 57 | } 58 | let mime_metadata = b.split_to(mime_type_length).freeze(); 59 | if b.is_empty() { 60 | return Err(RSocketError::InCompleteFrame.into()); 61 | } 62 | mime_type_length = b[0] as usize; 63 | b.advance(1); 64 | if b.len() < mime_type_length { 65 | return Err(RSocketError::InCompleteFrame.into()); 66 | } 67 | let mime_data = b.split_to(mime_type_length).freeze(); 68 | let (metadata, data) = utils::read_payload(flag, b)?; 69 | Ok(Setup { 70 | version: Version::new(major, minor), 71 | keepalive, 72 | lifetime, 73 | token, 74 | mime_metadata, 75 | mime_data, 76 | metadata, 77 | data, 78 | }) 79 | } 80 | 81 | pub fn builder(stream_id: u32, flag: u16) -> SetupBuilder { 82 | SetupBuilder::new(stream_id, flag) 83 | } 84 | 85 | pub fn get_version(&self) -> Version { 86 | self.version 87 | } 88 | 89 | pub fn get_keepalive(&self) -> Duration { 90 | Duration::from_millis(u64::from(self.keepalive)) 91 | } 92 | 93 | pub fn get_lifetime(&self) -> Duration { 94 | Duration::from_millis(u64::from(self.lifetime)) 95 | } 96 | 97 | pub fn get_token(&self) -> Option<&Bytes> { 98 | self.token.as_ref() 99 | } 100 | 101 | pub fn get_mime_metadata(&self) -> Option<&str> { 102 | std::str::from_utf8(&self.mime_metadata).ok() 103 | } 104 | 105 | pub fn get_mime_data(&self) -> Option<&str> { 106 | std::str::from_utf8(&self.mime_data).ok() 107 | } 108 | 109 | pub fn get_metadata(&self) -> Option<&Bytes> { 110 | self.metadata.as_ref() 111 | } 112 | 113 | pub fn get_data(&self) -> Option<&Bytes> { 114 | self.data.as_ref() 115 | } 116 | 117 | pub fn split(self) -> (Option, Option) { 118 | (self.data, self.metadata) 119 | } 120 | } 121 | 122 | impl Writeable for Setup { 123 | fn len(&self) -> usize { 124 | let mut n: usize = 12; 125 | n += match &self.token { 126 | Some(v) => 2 + v.len(), 127 | None => 0, 128 | }; 129 | n += 2 + self.mime_metadata.len() + self.mime_data.len(); 130 | n += utils::calculate_payload_length(self.get_metadata(), self.get_data()); 131 | n 132 | } 133 | 134 | fn write_to(&self, bf: &mut BytesMut) { 135 | self.version.write_to(bf); 136 | bf.put_u32(self.keepalive); 137 | bf.put_u32(self.lifetime); 138 | if let Some(b) = &self.token { 139 | bf.put_u16(b.len() as u16); 140 | bf.extend_from_slice(b); 141 | } 142 | bf.put_u8(self.mime_metadata.len() as u8); 143 | bf.extend_from_slice(&self.mime_metadata); 144 | bf.put_u8(self.mime_data.len() as u8); 145 | bf.extend_from_slice(&self.mime_data); 146 | utils::write_payload(bf, self.get_metadata(), self.get_data()); 147 | } 148 | } 149 | 150 | impl SetupBuilder { 151 | fn new(stream_id: u32, flag: u16) -> SetupBuilder { 152 | SetupBuilder { 153 | stream_id, 154 | flag, 155 | value: Setup { 156 | version: Version::default(), 157 | keepalive: 30_000, 158 | lifetime: 90_000, 159 | token: None, 160 | mime_metadata: Bytes::from(DEFAULT_MIME_TYPE), 161 | mime_data: Bytes::from(DEFAULT_MIME_TYPE), 162 | metadata: None, 163 | data: None, 164 | }, 165 | } 166 | } 167 | 168 | pub fn build(self) -> Frame { 169 | Frame::new(self.stream_id, Body::Setup(self.value), self.flag) 170 | } 171 | 172 | pub fn set_data(mut self, bs: Bytes) -> Self { 173 | self.value.data = Some(bs); 174 | self 175 | } 176 | 177 | pub fn set_metadata(mut self, bs: Bytes) -> Self { 178 | self.flag |= Frame::FLAG_METADATA; 179 | self.value.metadata = Some(bs); 180 | self 181 | } 182 | 183 | pub fn set_version(mut self, major: u16, minor: u16) -> Self { 184 | self.value.version = Version::new(major, minor); 185 | self 186 | } 187 | 188 | pub fn set_keepalive(mut self, duration: Duration) -> Self { 189 | self.value.keepalive = duration.as_millis() as u32; 190 | self 191 | } 192 | 193 | pub fn set_lifetime(mut self, duration: Duration) -> Self { 194 | self.value.lifetime = duration.as_millis() as u32; 195 | self 196 | } 197 | 198 | pub fn set_token(mut self, token: Bytes) -> Self { 199 | self.value.token = Some(token); 200 | self.flag |= Frame::FLAG_RESUME; 201 | self 202 | } 203 | 204 | pub fn set_mime_metadata(mut self, mime: I) -> Self 205 | where 206 | I: Into, 207 | { 208 | let mime = mime.into(); 209 | assert!(mime.len() <= 256); 210 | self.value.mime_metadata = Bytes::from(mime); 211 | self 212 | } 213 | 214 | pub fn set_mime_data(mut self, mime: I) -> Self 215 | where 216 | I: Into, 217 | { 218 | let mime = mime.into(); 219 | assert!(mime.len() <= 256); 220 | self.value.mime_data = Bytes::from(mime); 221 | self 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /rsocket-test/tests/test_clients.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate log; 3 | 4 | use std::thread::sleep; 5 | use std::time::Duration; 6 | 7 | use futures::stream; 8 | use rsocket_rust::prelude::*; 9 | use rsocket_rust::utils::EchoRSocket; 10 | use rsocket_rust::Client; 11 | use rsocket_rust_transport_tcp::{ 12 | TcpClientTransport, TcpServerTransport, UnixClientTransport, UnixServerTransport, 13 | }; 14 | use rsocket_rust_transport_websocket::{WebsocketClientTransport, WebsocketServerTransport}; 15 | use tokio::runtime::Runtime; 16 | 17 | fn init() { 18 | let _ = env_logger::builder() 19 | .format_timestamp_millis() 20 | .is_test(true) 21 | .try_init(); 22 | } 23 | 24 | #[tokio::main] 25 | #[test] 26 | async fn test_connect_must_failed() { 27 | let result = RSocketFactory::connect() 28 | .transport(TcpClientTransport::from("tcp://127.0.0.1:6789")) 29 | .start() 30 | .await; 31 | assert_eq!(false, result.is_ok()); 32 | } 33 | 34 | #[test] 35 | fn test_websocket() { 36 | init(); 37 | 38 | let addr = "127.0.0.1:8080"; 39 | 40 | let server_runtime = Runtime::new().unwrap(); 41 | 42 | // spawn a server 43 | server_runtime.spawn(async move { 44 | RSocketFactory::receive() 45 | .transport(WebsocketServerTransport::from(addr)) 46 | .acceptor(Box::new(|setup, _socket| { 47 | info!("accept setup: {:?}", setup); 48 | Ok(Box::new(EchoRSocket)) 49 | })) 50 | .on_start(Box::new(|| { 51 | info!("+++++++ websocket echo server started! +++++++") 52 | })) 53 | .serve() 54 | .await 55 | }); 56 | 57 | sleep(Duration::from_millis(500)); 58 | 59 | let client_runtime = Runtime::new().unwrap(); 60 | 61 | client_runtime.block_on(async { 62 | let cli = RSocketFactory::connect() 63 | .acceptor(Box::new(|| Box::new(EchoRSocket))) 64 | .transport(WebsocketClientTransport::from(addr)) 65 | .setup(Payload::from("READY!")) 66 | .mime_type("text/plain", "text/plain") 67 | .start() 68 | .await 69 | .unwrap(); 70 | 71 | info!("=====> begin"); 72 | 73 | exec_metadata_push(&cli).await; 74 | exec_fire_and_forget(&cli).await; 75 | exec_request_response(&cli).await; 76 | exec_request_stream(&cli).await; 77 | exec_request_channel(&cli).await; 78 | }); 79 | } 80 | 81 | #[test] 82 | fn test_tcp() { 83 | init(); 84 | 85 | let addr = "127.0.0.1:7878"; 86 | 87 | let server_runtime = Runtime::new().unwrap(); 88 | 89 | // spawn a server 90 | server_runtime.spawn(async move { 91 | RSocketFactory::receive() 92 | .transport(TcpServerTransport::from(addr)) 93 | .acceptor(Box::new(|setup, _socket| { 94 | info!("accept setup: {:?}", setup); 95 | Ok(Box::new(EchoRSocket)) 96 | })) 97 | .on_start(Box::new(|| { 98 | info!("+++++++ tcp echo server started! +++++++") 99 | })) 100 | .serve() 101 | .await 102 | }); 103 | 104 | sleep(Duration::from_millis(500)); 105 | 106 | let client_runtime = Runtime::new().unwrap(); 107 | 108 | client_runtime.block_on(async { 109 | let cli = RSocketFactory::connect() 110 | .acceptor(Box::new(|| Box::new(EchoRSocket))) 111 | .transport(TcpClientTransport::from(addr)) 112 | .setup(Payload::from("READY!")) 113 | .mime_type("text/plain", "text/plain") 114 | .start() 115 | .await 116 | .unwrap(); 117 | 118 | exec_metadata_push(&cli).await; 119 | exec_fire_and_forget(&cli).await; 120 | exec_request_response(&cli).await; 121 | exec_request_stream(&cli).await; 122 | exec_request_channel(&cli).await; 123 | }); 124 | } 125 | 126 | #[test] 127 | fn test_unix() { 128 | init(); 129 | 130 | let addr = "/tmp/rsocket-uds.sock"; 131 | 132 | let server_runtime = Runtime::new().unwrap(); 133 | 134 | // spawn a server 135 | server_runtime.spawn(async move { 136 | if let Err(e) = RSocketFactory::receive() 137 | .transport(UnixServerTransport::from(addr)) 138 | .acceptor(Box::new(|setup, _socket| { 139 | info!("accept setup: {:?}", setup); 140 | Ok(Box::new(EchoRSocket)) 141 | })) 142 | .on_start(Box::new(|| { 143 | info!("+++++++ unix echo server started! +++++++") 144 | })) 145 | .serve() 146 | .await 147 | { 148 | error!("server stopped with error: {}", e) 149 | } 150 | 151 | // Watch signal 152 | tokio::signal::ctrl_c().await.unwrap(); 153 | info!("ctrl-c received!"); 154 | if let Err(e) = std::fs::remove_file(addr) { 155 | error!("remove unix sock file failed: {}", e); 156 | } 157 | }); 158 | 159 | sleep(Duration::from_millis(500)); 160 | 161 | let client_runtime = Runtime::new().unwrap(); 162 | 163 | client_runtime.block_on(async { 164 | let cli = RSocketFactory::connect() 165 | .acceptor(Box::new(|| Box::new(EchoRSocket))) 166 | .transport(UnixClientTransport::from(addr)) 167 | .setup(Payload::from("READY!")) 168 | .mime_type("text/plain", "text/plain") 169 | .start() 170 | .await 171 | .unwrap(); 172 | 173 | exec_metadata_push(&cli).await; 174 | exec_fire_and_forget(&cli).await; 175 | exec_request_response(&cli).await; 176 | exec_request_stream(&cli).await; 177 | exec_request_channel(&cli).await; 178 | }); 179 | } 180 | 181 | #[tokio::main] 182 | #[test] 183 | #[ignore] 184 | async fn test_request_response_err() { 185 | env_logger::builder().format_timestamp_millis().init(); 186 | 187 | let cli = RSocketFactory::connect() 188 | .transport(TcpClientTransport::from("127.0.0.1:7878")) 189 | .setup(Payload::from("READY!")) 190 | .mime_type("text/plain", "text/plain") 191 | .start() 192 | .await 193 | .unwrap(); 194 | 195 | let res = cli 196 | .request_response(Payload::from("must return error")) 197 | .await; 198 | 199 | match res { 200 | Ok(_) => panic!("should catch an error!"), 201 | Err(e) => info!("error catched: {}", e), 202 | }; 203 | } 204 | 205 | async fn exec_request_response(socket: &Client) { 206 | // request response 207 | let sending = Payload::builder() 208 | .set_data_utf8("Hello World!") 209 | .set_metadata_utf8("I Rust!") 210 | .build(); 211 | let result = socket.request_response(sending).await.unwrap(); 212 | info!("REQUEST_RESPONSE: {:?}", result); 213 | } 214 | 215 | async fn exec_metadata_push(socket: &Client) { 216 | let pa = Payload::builder().set_metadata_utf8("Hello World!").build(); 217 | // metadata push 218 | let _ = socket.metadata_push(pa).await; 219 | } 220 | 221 | async fn exec_fire_and_forget(socket: &Client) { 222 | // request fnf 223 | let fnf = Payload::from("Hello World!"); 224 | let _ = socket.fire_and_forget(fnf).await; 225 | } 226 | 227 | async fn exec_request_stream(socket: &Client) { 228 | // request stream 229 | let sending = Payload::builder() 230 | .set_data_utf8("Hello Rust!") 231 | .set_metadata_utf8("foobar") 232 | .build(); 233 | 234 | let mut results = socket.request_stream(sending); 235 | loop { 236 | match results.next().await { 237 | Some(Ok(v)) => info!("STREAM_RESPONSE OK: {:?}", v), 238 | Some(Err(e)) => error!("STREAM_RESPONSE FAILED: {:?}", e), 239 | None => break, 240 | } 241 | } 242 | } 243 | 244 | async fn exec_request_channel(socket: &Client) { 245 | let sends: Vec<_> = (0..10) 246 | .map(|n| { 247 | let p = Payload::builder() 248 | .set_data_utf8(&format!("Hello#{}", n)) 249 | .set_metadata_utf8("RUST") 250 | .build(); 251 | Ok(p) 252 | }) 253 | .collect(); 254 | let mut results = socket.request_channel(Box::pin(stream::iter(sends))); 255 | loop { 256 | match results.next().await { 257 | Some(Ok(v)) => info!("CHANNEL_RESPONSE OK: {:?}", v), 258 | Some(Err(e)) => error!("CHANNEL_RESPONSE FAILED: {:?}", e), 259 | None => break, 260 | } 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /rsocket/src/frame/mod.rs: -------------------------------------------------------------------------------- 1 | use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 | 3 | use crate::error::RSocketError; 4 | use crate::utils::Writeable; 5 | 6 | mod cancel; 7 | mod error; 8 | mod keepalive; 9 | mod lease; 10 | mod metadata_push; 11 | mod payload; 12 | mod request_channel; 13 | mod request_fnf; 14 | mod request_n; 15 | mod request_response; 16 | mod request_stream; 17 | mod resume; 18 | mod resume_ok; 19 | mod setup; 20 | mod utils; 21 | mod version; 22 | 23 | pub use cancel::Cancel; 24 | pub use error::Error; 25 | pub use keepalive::Keepalive; 26 | pub use lease::Lease; 27 | pub use metadata_push::MetadataPush; 28 | pub use payload::Payload; 29 | pub use request_channel::RequestChannel; 30 | pub use request_fnf::RequestFNF; 31 | pub use request_n::RequestN; 32 | pub use request_response::RequestResponse; 33 | pub use request_stream::RequestStream; 34 | pub use resume::Resume; 35 | pub use resume_ok::ResumeOK; 36 | pub use setup::{Setup, SetupBuilder}; 37 | pub use version::Version; 38 | 39 | pub const REQUEST_MAX: u32 = 0x7FFF_FFFF; // 2147483647 40 | 41 | pub(crate) const LEN_HEADER: usize = 6; 42 | 43 | #[derive(Debug, Eq, PartialEq)] 44 | pub enum Body { 45 | Setup(Setup), 46 | Lease(Lease), 47 | Keepalive(Keepalive), 48 | RequestFNF(RequestFNF), 49 | RequestResponse(RequestResponse), 50 | RequestStream(RequestStream), 51 | RequestChannel(RequestChannel), 52 | RequestN(RequestN), 53 | Cancel(), 54 | Payload(Payload), 55 | Error(Error), 56 | MetadataPush(MetadataPush), 57 | Resume(Resume), 58 | ResumeOK(ResumeOK), 59 | } 60 | 61 | #[derive(Debug, Eq, PartialEq)] 62 | pub struct Frame { 63 | pub(crate) stream_id: u32, 64 | pub(crate) body: Body, 65 | pub(crate) flag: u16, 66 | } 67 | 68 | impl Frame { 69 | pub const FLAG_NEXT: u16 = 0x01 << 5; 70 | pub const FLAG_COMPLETE: u16 = 0x01 << 6; 71 | pub const FLAG_FOLLOW: u16 = 0x01 << 7; 72 | pub const FLAG_METADATA: u16 = 0x01 << 8; 73 | pub const FLAG_IGNORE: u16 = 0x01 << 9; 74 | pub const FLAG_LEASE: u16 = Self::FLAG_COMPLETE; 75 | pub const FLAG_RESUME: u16 = Self::FLAG_FOLLOW; 76 | pub const FLAG_RESPOND: u16 = Self::FLAG_FOLLOW; 77 | 78 | pub const TYPE_SETUP: u16 = 0x01; 79 | pub const TYPE_LEASE: u16 = 0x02; 80 | pub const TYPE_KEEPALIVE: u16 = 0x03; 81 | pub const TYPE_REQUEST_RESPONSE: u16 = 0x04; 82 | pub const TYPE_REQUEST_FNF: u16 = 0x05; 83 | pub const TYPE_REQUEST_STREAM: u16 = 0x06; 84 | pub const TYPE_REQUEST_CHANNEL: u16 = 0x07; 85 | pub const TYPE_REQUEST_N: u16 = 0x08; 86 | pub const TYPE_CANCEL: u16 = 0x09; 87 | pub const TYPE_PAYLOAD: u16 = 0x0A; 88 | pub const TYPE_ERROR: u16 = 0x0B; 89 | pub const TYPE_METADATA_PUSH: u16 = 0x0C; 90 | pub const TYPE_RESUME: u16 = 0x0D; 91 | pub const TYPE_RESUME_OK: u16 = 0x0E; 92 | } 93 | 94 | impl Writeable for Frame { 95 | fn write_to(&self, bf: &mut BytesMut) { 96 | bf.put_u32(self.stream_id); 97 | bf.put_u16((to_frame_type(&self.body) << 10) | self.flag); 98 | match &self.body { 99 | Body::Setup(v) => v.write_to(bf), 100 | Body::RequestResponse(v) => v.write_to(bf), 101 | Body::RequestStream(v) => v.write_to(bf), 102 | Body::RequestChannel(v) => v.write_to(bf), 103 | Body::RequestFNF(v) => v.write_to(bf), 104 | Body::RequestN(v) => v.write_to(bf), 105 | Body::MetadataPush(v) => v.write_to(bf), 106 | Body::Keepalive(v) => v.write_to(bf), 107 | Body::Payload(v) => v.write_to(bf), 108 | Body::Lease(v) => v.write_to(bf), 109 | Body::Error(v) => v.write_to(bf), 110 | Body::Cancel() => (), 111 | Body::ResumeOK(v) => v.write_to(bf), 112 | Body::Resume(v) => v.write_to(bf), 113 | } 114 | } 115 | 116 | fn len(&self) -> usize { 117 | // header len 118 | LEN_HEADER 119 | + match &self.body { 120 | Body::Setup(v) => v.len(), 121 | Body::RequestResponse(v) => v.len(), 122 | Body::RequestStream(v) => v.len(), 123 | Body::RequestChannel(v) => v.len(), 124 | Body::RequestFNF(v) => v.len(), 125 | Body::RequestN(v) => v.len(), 126 | Body::MetadataPush(v) => v.len(), 127 | Body::Keepalive(v) => v.len(), 128 | Body::Payload(v) => v.len(), 129 | Body::Lease(v) => v.len(), 130 | Body::Cancel() => 0, 131 | Body::Error(v) => v.len(), 132 | Body::ResumeOK(v) => v.len(), 133 | Body::Resume(v) => v.len(), 134 | } 135 | } 136 | } 137 | 138 | impl Frame { 139 | pub fn new(stream_id: u32, body: Body, flag: u16) -> Frame { 140 | Frame { 141 | stream_id, 142 | body, 143 | flag, 144 | } 145 | } 146 | 147 | pub fn decode(b: &mut BytesMut) -> crate::Result { 148 | if b.len() < LEN_HEADER { 149 | return Err(RSocketError::InCompleteFrame.into()); 150 | } 151 | let sid = b.get_u32(); 152 | let n = b.get_u16(); 153 | let (flag, kind) = (n & 0x03FF, (n & 0xFC00) >> 10); 154 | let body = match kind { 155 | Self::TYPE_SETUP => Setup::decode(flag, b).map(Body::Setup), 156 | Self::TYPE_REQUEST_RESPONSE => { 157 | RequestResponse::decode(flag, b).map(Body::RequestResponse) 158 | } 159 | Self::TYPE_REQUEST_STREAM => RequestStream::decode(flag, b).map(Body::RequestStream), 160 | Self::TYPE_REQUEST_CHANNEL => RequestChannel::decode(flag, b).map(Body::RequestChannel), 161 | Self::TYPE_REQUEST_FNF => RequestFNF::decode(flag, b).map(Body::RequestFNF), 162 | Self::TYPE_REQUEST_N => RequestN::decode(flag, b).map(Body::RequestN), 163 | Self::TYPE_METADATA_PUSH => MetadataPush::decode(flag, b).map(Body::MetadataPush), 164 | Self::TYPE_KEEPALIVE => Keepalive::decode(flag, b).map(Body::Keepalive), 165 | Self::TYPE_PAYLOAD => Payload::decode(flag, b).map(Body::Payload), 166 | Self::TYPE_LEASE => Lease::decode(flag, b).map(Body::Lease), 167 | Self::TYPE_CANCEL => Ok(Body::Cancel()), 168 | Self::TYPE_ERROR => Error::decode(flag, b).map(Body::Error), 169 | Self::TYPE_RESUME_OK => ResumeOK::decode(flag, b).map(Body::ResumeOK), 170 | Self::TYPE_RESUME => Resume::decode(flag, b).map(Body::Resume), 171 | typ => unreachable!("invalid frame type {}!", typ), 172 | }; 173 | body.map(|it| Frame::new(sid, it, flag)) 174 | } 175 | 176 | pub(crate) fn is_followable_or_payload(&self) -> (bool, bool) { 177 | match &self.body { 178 | Body::RequestFNF(_) => (true, false), 179 | Body::RequestResponse(_) => (true, false), 180 | Body::RequestStream(_) => (true, false), 181 | Body::RequestChannel(_) => (true, false), 182 | Body::Payload(_) => (true, true), 183 | _ => (false, false), 184 | } 185 | } 186 | 187 | pub fn get_body(self) -> Body { 188 | self.body 189 | } 190 | 191 | pub fn get_body_ref(&self) -> &Body { 192 | &self.body 193 | } 194 | 195 | pub fn get_flag(&self) -> u16 { 196 | self.flag 197 | } 198 | 199 | pub fn get_stream_id(&self) -> u32 { 200 | self.stream_id 201 | } 202 | 203 | pub fn has_next(&self) -> bool { 204 | self.flag & Self::FLAG_NEXT != 0 205 | } 206 | 207 | pub fn has_complete(&self) -> bool { 208 | self.flag & Self::FLAG_COMPLETE != 0 209 | } 210 | } 211 | 212 | #[inline] 213 | fn to_frame_type(body: &Body) -> u16 { 214 | match body { 215 | Body::Setup(_) => Frame::TYPE_SETUP, 216 | Body::Lease(_) => Frame::TYPE_LEASE, 217 | Body::Keepalive(_) => Frame::TYPE_KEEPALIVE, 218 | Body::RequestResponse(_) => Frame::TYPE_REQUEST_RESPONSE, 219 | Body::RequestFNF(_) => Frame::TYPE_REQUEST_FNF, 220 | Body::RequestStream(_) => Frame::TYPE_REQUEST_STREAM, 221 | Body::RequestChannel(_) => Frame::TYPE_REQUEST_CHANNEL, 222 | Body::RequestN(_) => Frame::TYPE_REQUEST_N, 223 | Body::Cancel() => Frame::TYPE_CANCEL, 224 | Body::Payload(_) => Frame::TYPE_PAYLOAD, 225 | Body::Error(_) => Frame::TYPE_ERROR, 226 | Body::MetadataPush(_) => Frame::TYPE_METADATA_PUSH, 227 | Body::Resume(_) => Frame::TYPE_RESUME, 228 | Body::ResumeOK(_) => Frame::TYPE_RESUME_OK, 229 | } 230 | } 231 | --------------------------------------------------------------------------------