1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! # razor-rpc
//!
//! This crate provides a high-level remote API call interface for `razor-rpc`.
//! It is part of a modular, pluggable RPC for high throughput scenarios that supports various async runtimes.
//!
//! If you are looking for streaming interface, use [razor-stream](https://docs.rs/razor-stream) instead.
//!
//! ## Feature
//!
//! - Independent from async runtime (with plugins)
//! - With service trait very similar to grpc / tarpc (stream in API interface is not supported
//! currently)
//! - Support latest `impl Future` definition of rust since 1.75, also support legacy `async_trait`
//! wrapper
//! - Each method can have different custom error type (requires the type implements
//! [RpcErrCodec](crate::error::RpcErrCodec))
//! - based on [razor-stream](https://docs.rs/razor-stream): Full duplex in each connection, with sliding window threshold, allow maximizing throughput and lower cpu usage.
//!
//! (Warning: The API and feature is still evolving, might changed in the future)
//!
//! ## Components
//!
//! `razor-rpc` is built from a collection of crates that provide different functionalities:
//!
//! - Async runtime support by [`orb`](https://docs.rs/orb):
//! - [`orb-tokio`](https://docs.rs/orb-tokio): A runtime adapter for the `tokio` runtime.
//! - [`orb-smol`](https://docs.rs/orb-smol): A runtime adapter for the `smol` runtime.
//! - codec [`razor-rpc-codec`](https://docs.rs/razor-rpc-codec): Provides codecs for serialization, such as `msgpack`.
//! - transports:
//! - [`razor-rpc-tcp`](https://docs.rs/razor-rpc-tcp): A TCP transport implementation.
//!
//! ## Usage
//!
//! 1. Choose your async runtime, and the codec.
//! 2. Choose underlying transport, like [`razor-rpc-tcp`](https://docs.rs/razor-rpc-tcp)
//! 3. define your service trait, the client is also generated along with the trait
//! 4. impl your service trait at server-side
//! 5. Initialize ServerFacts (with configuration and runtime)
//! 6. choose request dispatch method: [crate::server::dispatch]
//! 7. Start listening for connection
//! 8. Initialize ClientFacts (with configuration, runtime, and codec)
//! 9. Setup a connection pool: [ClientPool](crate::client::ClientPool) or
//! [FailoverPool](crate::client::FailoverPool)
//!
//! ## Example
//!
//! ```rust
//! use razor_rpc::client::{endpoint_async, APIClientReq, ClientConfig};
//! use razor_rpc::server::{service, ServerConfig};
//! use razor_rpc::error::RpcError;
//! use razor_rpc_tcp::{TcpClient, TcpServer};
//! use nix::errno::Errno;
//! use std::future::Future;
//! use std::sync::Arc;
//!
//! // 1. Choose the async runtime, and the codec
//! type OurRt = orb_tokio::TokioRT;
//! type OurCodec = razor_rpc_codec::MsgpCodec;
//! // 2. Choose transport
//! type ServerProto = TcpServer<OurRt>;
//! type ClientProto = TcpClient<OurRt>;
//!
//! // 3. Define a service trait, and generate the client struct
//! #[endpoint_async(CalculatorClient)]
//! pub trait CalculatorService {
//! // Method with unit error type using impl Future
//! fn add(&self, args: (i32, i32)) -> impl Future<Output = Result<i32, RpcError<()>>> + Send;
//!
//! // Method with string error type using impl Future
//! fn div(&self, args: (i32, i32)) -> impl Future<Output = Result<i32, RpcError<String>>> + Send;
//!
//! // Method with errno error type using impl Future
//! fn might_fail_with_errno(&self, value: i32) -> impl Future<Output = Result<i32, RpcError<Errno>>> + Send;
//! }
//!
//! // 4. Server implementation, can use Arc with internal context, but we are a simple demo
//! #[derive(Clone)]
//! pub struct CalculatorServer;
//!
//! #[service]
//! impl CalculatorService for CalculatorServer {
//! async fn add(&self, args: (i32, i32)) -> Result<i32, RpcError<()>> {
//! let (a, b) = args;
//! Ok(a + b)
//! }
//!
//! async fn div(&self, args: (i32, i32)) -> Result<i32, RpcError<String>> {
//! let (a, b) = args;
//! if b == 0 {
//! Err(RpcError::User("division by zero".to_string()))
//! } else {
//! Ok(a / b)
//! }
//! }
//!
//! async fn might_fail_with_errno(&self, value: i32) -> Result<i32, RpcError<Errno>> {
//! if value < 0 {
//! Err(RpcError::User(Errno::EINVAL))
//! } else {
//! Ok(value * 2)
//! }
//! }
//! }
//!
//! async fn setup_server() -> std::io::Result<String> {
//! // 5. Server setup with default ServerFacts
//! use razor_rpc::server::{RpcServer, ServerDefault};
//! let server_config = ServerConfig::default();
//! let mut server = RpcServer::new(ServerDefault::new(server_config, OurRt::new_multi_thread(8)));
//! // 6. dispatch
//! use razor_rpc::server::dispatch::Inline;
//! let disp = Inline::<OurCodec, _>::new(CalculatorServer);
//! // 7. Start listening
//! let actual_addr = server.listen::<ServerProto, _>("127.0.0.1:8082", disp).await?;
//! Ok(actual_addr)
//! }
//!
//! async fn use_client(server_addr: &str) {
//! use razor_rpc::client::*;
//! // 8. ClientFacts
//! let mut client_config = ClientConfig::default();
//! client_config.task_timeout = 5;
//! let rt = OurRt::new_multi_thread(8);
//! type OurFacts = APIClientDefault<OurRt, OurCodec>;
//! let client_facts = OurFacts::new(client_config, rt);
//! // 9. Create client connection pool
//! let pool: ClientPool<OurFacts, ClientProto> =
//! client_facts.create_pool_async::<ClientProto>(server_addr);
//! let client = CalculatorClient::new(pool);
//! // Call methods with different error types
//! if let Ok(r) = client.add((10, 20)).await {
//! assert_eq!(r, 30);
//! }
//! // This will return a string error, but connect might fail, who knows
//! if let Err(e) = client.div((10, 0)).await {
//! println!("error occurred: {}", e);
//! }
//! }
//! ```
// re-export for macros, so that user don't need to use multiple crates
pub use ;