karyon_jsonrpc/server/
builder.rs1use std::{collections::HashMap, sync::Arc, time::Duration};
2
3use karyon_core::async_runtime::Executor;
4
5use karyon_net::ToEndpoint;
6
7#[cfg(any(feature = "tcp", feature = "tls", feature = "quic"))]
8use karyon_net::Endpoint;
9
10#[cfg(feature = "tcp")]
11use karyon_net::tcp::TcpConfig;
12
13#[cfg(feature = "quic")]
14use karyon_net::quic::ServerQuicConfig;
15
16use crate::{
17 codec::{JsonCodec, JsonRpcCodec},
18 error::Result,
19 message::{Notification, NotificationResult, JSONRPC_VERSION},
20 server::channel::NewNotification,
21 server::PubSubRPCService,
22 server::RPCService,
23 server::WsCodec,
24};
25
26#[cfg(any(feature = "tcp", feature = "tls", feature = "quic"))]
27use crate::error::Error;
28
29#[cfg(feature = "http")]
30use super::HttpConfig;
31use super::{Server, ServerConfig};
32
33#[cfg(any(feature = "tls", feature = "ws"))]
34const DEFAULT_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(10);
35
36pub struct ServerBuilder<B, W = JsonCodec> {
65 config: ServerConfig,
66 byte_codec: B,
67 ws_codec: W,
68 executor: Option<Executor>,
69}
70
71impl<B, W> ServerBuilder<B, W>
72where
73 B: JsonRpcCodec,
74 W: WsCodec,
75{
76 pub fn service(mut self, service: Arc<dyn RPCService>) -> Self {
78 self.config.services.insert(service.name(), service);
79 self
80 }
81
82 pub fn pubsub_service(mut self, service: Arc<dyn PubSubRPCService>) -> Self {
84 self.config.pubsub_services.insert(service.name(), service);
85 self
86 }
87
88 #[cfg(feature = "tcp")]
90 pub fn tcp_config(mut self, config: TcpConfig) -> Result<Self> {
91 match self.config.endpoint {
92 Endpoint::Tcp(..) | Endpoint::Tls(..) | Endpoint::Ws(..) | Endpoint::Wss(..) => {
93 self.config.tcp_config = config;
94 Ok(self)
95 }
96 _ => Err(Error::UnsupportedProtocol(self.config.endpoint.to_string())),
97 }
98 }
99
100 #[cfg(feature = "tls")]
102 pub fn tls_config(mut self, config: karyon_net::tls::ServerTlsConfig) -> Result<Self> {
103 match self.config.endpoint {
104 Endpoint::Tls(..) | Endpoint::Wss(..) => {
105 self.config.tls_config = Some(config);
106 Ok(self)
107 }
108 _ => Err(Error::UnsupportedProtocol(format!(
109 "Invalid tls config for endpoint: {}",
110 self.config.endpoint
111 ))),
112 }
113 }
114
115 #[cfg(feature = "quic")]
117 pub fn quic_config(mut self, config: ServerQuicConfig) -> Result<Self> {
118 match self.config.endpoint {
119 Endpoint::Quic(..) => {
120 self.config.quic_config = Some(config);
121 Ok(self)
122 }
123 #[cfg(feature = "http3")]
124 Endpoint::Http(..) => {
125 self.config.quic_config = Some(config);
126 Ok(self)
127 }
128 _ => Err(Error::UnsupportedProtocol(format!(
129 "Invalid quic config for endpoint: {}",
130 self.config.endpoint
131 ))),
132 }
133 }
134
135 #[cfg(feature = "http")]
137 pub fn http_config(mut self, config: HttpConfig) -> Result<Self> {
138 match self.config.endpoint {
139 Endpoint::Http(..) => {
140 self.config.http_config = config;
141 Ok(self)
142 }
143 _ => Err(Error::UnsupportedProtocol(format!(
144 "Invalid http config for endpoint: {}",
145 self.config.endpoint
146 ))),
147 }
148 }
149
150 pub fn with_executor(mut self, ex: Executor) -> Self {
152 self.executor = Some(ex);
153 self
154 }
155
156 pub fn read_timeout(mut self, duration: Duration) -> Self {
159 self.config.read_timeout = Some(duration);
160 self
161 }
162
163 #[cfg(any(feature = "tls", feature = "ws"))]
166 pub fn handshake_timeout(mut self, duration: Duration) -> Self {
167 self.config.handshake_timeout = duration;
168 self
169 }
170
171 pub fn with_notification_encoder(
174 mut self,
175 encoder: fn(NewNotification) -> Notification,
176 ) -> Self {
177 self.config.notification_encoder = encoder;
178 self
179 }
180
181 #[cfg(feature = "ws")]
184 pub fn with_ws_codec<W2: WsCodec>(self, ws_codec: W2) -> ServerBuilder<B, W2> {
185 ServerBuilder {
186 config: self.config,
187 byte_codec: self.byte_codec,
188 ws_codec,
189 executor: self.executor,
190 }
191 }
192
193 pub async fn build(self) -> Result<Arc<Server>> {
195 Server::init(self.config, self.executor, self.byte_codec, self.ws_codec).await
196 }
197}
198
199impl<B: JsonRpcCodec> ServerBuilder<B, JsonCodec> {
200 pub fn new_with_codec(
204 endpoint: impl ToEndpoint,
205 codec: B,
206 ) -> Result<ServerBuilder<B, JsonCodec>> {
207 let endpoint = endpoint.to_endpoint()?;
208 Ok(ServerBuilder {
209 config: ServerConfig {
210 endpoint,
211 services: HashMap::new(),
212 pubsub_services: HashMap::new(),
213 #[cfg(feature = "tcp")]
214 tcp_config: Default::default(),
215 #[cfg(feature = "tls")]
216 tls_config: None,
217 #[cfg(feature = "quic")]
218 quic_config: None,
219 notification_encoder: default_notification_encoder,
220 #[cfg(feature = "http")]
221 http_config: HttpConfig::default(),
222 read_timeout: None,
223 #[cfg(any(feature = "tls", feature = "ws"))]
224 handshake_timeout: DEFAULT_HANDSHAKE_TIMEOUT,
225 },
226 byte_codec: codec,
227 ws_codec: JsonCodec::default(),
228 executor: None,
229 })
230 }
231}
232
233impl ServerBuilder<JsonCodec, JsonCodec> {
234 pub fn new(endpoint: impl ToEndpoint) -> Result<ServerBuilder<JsonCodec, JsonCodec>> {
236 Self::new_with_codec(endpoint, JsonCodec::default())
237 }
238}
239
240fn default_notification_encoder(nt: NewNotification) -> Notification {
241 let params = Some(serde_json::json!(NotificationResult {
242 subscription: nt.sub_id,
243 result: Some(nt.result),
244 }));
245
246 Notification {
247 jsonrpc: JSONRPC_VERSION.to_string(),
248 method: nt.method,
249 params,
250 }
251}