server.rs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{collections::HashSet, future::Future, io::ErrorKind, sync::Arc};
  19. use async_trait::async_trait;
  20. use futures::future::try_join_all;
  21. use parking_lot::Mutex as SyncMutex;
  22. use smol::{
  23. io::{BufReader, ReadHalf, WriteHalf},
  24. lock::{Mutex, MutexGuard},
  25. };
  26. use tinyjson::JsonValue;
  27. use tracing::{debug, info, warn};
  28. use url::Url;
  29. use super::{
  30. common::{
  31. http_read_from_stream_request, http_write_to_stream, read_from_stream, write_to_stream,
  32. INIT_BUF_SIZE,
  33. },
  34. jsonrpc::*,
  35. settings::RpcSettings,
  36. };
  37. use crate::{
  38. net::transport::{Listener, PtListener, PtStream},
  39. system::{StoppableTask, StoppableTaskPtr},
  40. util::logger::verbose,
  41. Error, Result,
  42. };
  43. /// Asynchronous trait implementing a handler for incoming JSON-RPC requests.
  44. #[async_trait]
  45. pub trait RequestHandler<T>: Sync + Send {
  46. async fn handle_request(&self, req: JsonRequest) -> JsonResult;
  47. async fn pong(&self, id: i64, _params: JsonValue) -> JsonResult {
  48. JsonResponse::new(JsonValue::String("pong".to_string()), id).into()
  49. }
  50. async fn connections_mut(&self) -> MutexGuard<'life0, HashSet<StoppableTaskPtr>>;
  51. async fn connections(&self) -> Vec<StoppableTaskPtr> {
  52. self.connections_mut().await.iter().cloned().collect()
  53. }
  54. async fn mark_connection(&self, task: StoppableTaskPtr) {
  55. self.connections_mut().await.insert(task);
  56. }
  57. async fn unmark_connection(&self, task: StoppableTaskPtr) {
  58. self.connections_mut().await.remove(&task);
  59. }
  60. async fn active_connections(&self) -> usize {
  61. self.connections_mut().await.len()
  62. }
  63. async fn stop_connections(&self) {
  64. info!(target: "rpc::server", "[RPC] Server stopped, closing connections");
  65. for (i, task) in self.connections().await.iter().enumerate() {
  66. debug!(target: "rpc::server", "Stopping connection #{i}");
  67. task.stop().await;
  68. }
  69. }
  70. }
  71. #[derive(Default)]
  72. struct ConnectionTaskState {
  73. closing: bool,
  74. tasks: HashSet<StoppableTaskPtr>,
  75. }
  76. #[derive(Default)]
  77. struct ConnectionTasks {
  78. state: SyncMutex<ConnectionTaskState>,
  79. }
  80. impl ConnectionTasks {
  81. /// Register and start a child while holding the task-set lock. This prevents
  82. /// a fast child from finishing before it has been registered and prevents
  83. /// new children from racing with connection shutdown.
  84. fn start<'a, MainFut>(
  85. self: &Arc<Self>,
  86. task: StoppableTaskPtr,
  87. main: MainFut,
  88. ex: Arc<smol::Executor<'a>>,
  89. ) where
  90. MainFut: Future<Output = Result<()>> + Send + 'a,
  91. {
  92. let mut state = self.state.lock();
  93. if state.closing {
  94. return
  95. }
  96. debug!(target: "rpc::server", "Adding background task {} to map", task.task_id);
  97. state.tasks.insert(task.clone());
  98. let tasks = self.clone();
  99. let task_ = task.clone();
  100. task.start(
  101. main,
  102. move |_| async move {
  103. debug!(
  104. target: "rpc::server",
  105. "Removing background task {} from map", task_.task_id,
  106. );
  107. tasks.state.lock().tasks.remove(&task_);
  108. },
  109. Error::DetachedTaskStopped,
  110. ex,
  111. );
  112. }
  113. fn close(&self) -> Vec<StoppableTaskPtr> {
  114. let mut state = self.state.lock();
  115. state.closing = true;
  116. state.tasks.iter().cloned().collect()
  117. }
  118. fn stop_all_nowait(&self) {
  119. for task in self.close() {
  120. task.stop_nowait();
  121. }
  122. }
  123. async fn stop_all(&self) {
  124. for task in self.close() {
  125. task.stop().await;
  126. }
  127. debug_assert!(self.state.lock().tasks.is_empty());
  128. }
  129. }
  130. struct ConnectionTasksGuard(Arc<ConnectionTasks>);
  131. impl Drop for ConnectionTasksGuard {
  132. fn drop(&mut self) {
  133. self.0.stop_all_nowait();
  134. }
  135. }
  136. /// Auxiliary function to handle a request in the background.
  137. async fn handle_request<T>(
  138. writer: Arc<Mutex<WriteHalf<Box<dyn PtStream>>>>,
  139. addr: Url,
  140. rh: Arc<impl RequestHandler<T> + 'static>,
  141. ex: Arc<smol::Executor<'_>>,
  142. tasks: Arc<ConnectionTasks>,
  143. settings: RpcSettings,
  144. req: JsonRequest,
  145. ) -> Result<()> {
  146. let req_id = req.id;
  147. // Handle disabled RPC methods
  148. let rep = if settings.is_method_disabled(&req.method) {
  149. debug!(target: "rpc::server", "RPC method {} is disabled", req.method);
  150. JsonError::new(ErrorCode::MethodNotFound, None, req.id).into()
  151. } else {
  152. rh.handle_request(req).await
  153. };
  154. match rep {
  155. JsonResult::Subscriber(subscriber) => {
  156. let task = StoppableTask::new();
  157. // Clone what needs to go in the background
  158. let addr_ = addr.clone();
  159. let writer_ = writer.clone();
  160. // Detach the subscriber so we can multiplex further requests
  161. tasks.start(
  162. task,
  163. async move {
  164. // Subscribe to the inner method subscriber
  165. let subscription = subscriber.publisher.subscribe().await;
  166. loop {
  167. // Listen for notifications
  168. let notification = subscription.receive().await;
  169. // Push notification
  170. debug!(target: "rpc::server", "{addr_} <-- {}", notification.stringify().unwrap());
  171. let notification = JsonResult::Notification(notification);
  172. let mut writer_lock = writer_.lock().await;
  173. #[allow(clippy::collapsible_else_if)]
  174. if settings.use_http() {
  175. if let Err(e) = http_write_to_stream(&mut writer_lock, &notification).await {
  176. return Err(e.into())
  177. }
  178. } else {
  179. if let Err(e) = write_to_stream(&mut writer_lock, &notification).await {
  180. return Err(e.into())
  181. }
  182. }
  183. drop(writer_lock);
  184. }
  185. },
  186. ex.clone(),
  187. );
  188. }
  189. JsonResult::SubscriberWithReply(subscriber, reply) => {
  190. // Write the response
  191. debug!(target: "rpc::server", "{addr} <-- {}", reply.stringify()?);
  192. let mut writer_lock = writer.lock().await;
  193. if settings.use_http() {
  194. http_write_to_stream(&mut writer_lock, &reply.into()).await?;
  195. } else {
  196. write_to_stream(&mut writer_lock, &reply.into()).await?;
  197. }
  198. drop(writer_lock);
  199. let task = StoppableTask::new();
  200. // Clone what needs to go in the background
  201. let addr_ = addr.clone();
  202. let writer_ = writer.clone();
  203. // Detach the subscriber so we can multiplex further requests
  204. tasks.start(
  205. task,
  206. async move {
  207. // Start the subscriber loop
  208. let subscription = subscriber.publisher.subscribe().await;
  209. loop {
  210. // Listen for notifications
  211. let notification = subscription.receive().await;
  212. // Push notification
  213. debug!(target: "rpc::server", "{addr_} <-- {}", notification.stringify().unwrap());
  214. let notification = JsonResult::Notification(notification);
  215. let mut writer_lock = writer_.lock().await;
  216. #[allow(clippy::collapsible_else_if)]
  217. if settings.use_http() {
  218. if let Err(e) = http_write_to_stream(&mut writer_lock, &notification).await {
  219. return Err(e.into())
  220. }
  221. } else {
  222. if let Err(e) = write_to_stream(&mut writer_lock, &notification).await {
  223. return Err(e.into())
  224. }
  225. }
  226. drop(writer_lock);
  227. }
  228. },
  229. ex.clone(),
  230. );
  231. }
  232. JsonResult::Request(_) | JsonResult::Notification(_) => {
  233. warn!(
  234. target: "rpc::server",
  235. "{addr}: handler returned Request/Notification for id={req_id}",
  236. );
  237. let err_rep: JsonResult = JsonError::new(
  238. ErrorCode::InternalError,
  239. Some("Handler returned a non-response variant".to_string()),
  240. req_id,
  241. )
  242. .into();
  243. let mut writer_lock = writer.lock().await;
  244. if settings.use_http() {
  245. http_write_to_stream(&mut writer_lock, &err_rep).await?;
  246. } else {
  247. write_to_stream(&mut writer_lock, &err_rep).await?;
  248. }
  249. drop(writer_lock);
  250. }
  251. JsonResult::Response(ref v) => {
  252. debug!(target: "rpc::server", "{addr} <-- {}", v.stringify()?);
  253. let mut writer_lock = writer.lock().await;
  254. if settings.use_http() {
  255. http_write_to_stream(&mut writer_lock, &rep).await?;
  256. } else {
  257. write_to_stream(&mut writer_lock, &rep).await?;
  258. }
  259. drop(writer_lock);
  260. }
  261. JsonResult::Error(ref v) => {
  262. debug!(target: "rpc::server", "{addr} <-- {}", v.stringify()?);
  263. let mut writer_lock = writer.lock().await;
  264. if settings.use_http() {
  265. http_write_to_stream(&mut writer_lock, &rep).await?;
  266. } else {
  267. write_to_stream(&mut writer_lock, &rep).await?;
  268. }
  269. drop(writer_lock);
  270. }
  271. }
  272. Ok(())
  273. }
  274. /// Accept function that should run inside a loop for accepting incoming
  275. /// JSON-RPC requests and passing them to the [`RequestHandler`].
  276. #[allow(clippy::type_complexity)]
  277. async fn accept_with_tasks<'a, T: 'a>(
  278. reader: Arc<Mutex<BufReader<ReadHalf<Box<dyn PtStream>>>>>,
  279. writer: Arc<Mutex<WriteHalf<Box<dyn PtStream>>>>,
  280. addr: Url,
  281. rh: Arc<impl RequestHandler<T> + 'static>,
  282. tasks: Arc<ConnectionTasks>,
  283. settings: RpcSettings,
  284. ex: Arc<smol::Executor<'a>>,
  285. ) -> Result<()> {
  286. // Ensure cancellation signals all children even before the connection
  287. // task's stop handler gets a chance to await them.
  288. let _tasks_guard = ConnectionTasksGuard(tasks.clone());
  289. loop {
  290. let mut buf = Vec::with_capacity(INIT_BUF_SIZE);
  291. let mut reader_lock = reader.lock().await;
  292. if settings.use_http() {
  293. let _ = http_read_from_stream_request(&mut reader_lock, &mut buf).await?;
  294. } else {
  295. let _ = read_from_stream(&mut reader_lock, &mut buf).await?;
  296. }
  297. drop(reader_lock);
  298. let line = match String::from_utf8(buf) {
  299. Ok(v) => v,
  300. Err(e) => {
  301. warn!(
  302. target: "rpc::server::accept",
  303. "[RPC SERVER] Failed parsing string from read buffer: {e}"
  304. );
  305. return Err(e.into())
  306. }
  307. };
  308. // Parse the line as JSON
  309. let val: JsonValue = match line.trim().parse() {
  310. Ok(v) => v,
  311. Err(e) => {
  312. warn!(
  313. target: "rpc::server::accept",
  314. "[RPC SERVER] Failed parsing JSON string: {e}"
  315. );
  316. return Err(e.into())
  317. }
  318. };
  319. // Cast to JsonRequest
  320. let req = match JsonRequest::try_from(&val) {
  321. Ok(v) => v,
  322. Err(e) => {
  323. warn!(
  324. target: "rpc::server::accept",
  325. "[RPC SERVER] Failed casting JSON to a JsonRequest: {e}"
  326. );
  327. return Err(e.into())
  328. }
  329. };
  330. debug!(target: "rpc::server", "{addr} --> {}", val.stringify()?);
  331. // Create a new task to handle request in the background
  332. let task = StoppableTask::new();
  333. // Detach the task
  334. tasks.start(
  335. task,
  336. handle_request(
  337. writer.clone(),
  338. addr.clone(),
  339. rh.clone(),
  340. ex.clone(),
  341. tasks.clone(),
  342. settings.clone(),
  343. req,
  344. ),
  345. ex.clone(),
  346. );
  347. }
  348. }
  349. /// Accept incoming JSON-RPC requests and stop all request and subscriber tasks
  350. /// before returning.
  351. #[allow(clippy::type_complexity)]
  352. pub async fn accept<'a, T: 'a>(
  353. reader: Arc<Mutex<BufReader<ReadHalf<Box<dyn PtStream>>>>>,
  354. writer: Arc<Mutex<WriteHalf<Box<dyn PtStream>>>>,
  355. addr: Url,
  356. rh: Arc<impl RequestHandler<T> + 'static>,
  357. settings: RpcSettings,
  358. ex: Arc<smol::Executor<'a>>,
  359. ) -> Result<()> {
  360. let tasks = Arc::new(ConnectionTasks::default());
  361. let result = accept_with_tasks(reader, writer, addr, rh, tasks.clone(), settings, ex).await;
  362. tasks.stop_all().await;
  363. result
  364. }
  365. /// Wrapper function around [`accept()`] to take the incoming connection and
  366. /// pass it forward.
  367. async fn run_accept_loop<'a, T: 'a>(
  368. listener: Box<dyn PtListener>,
  369. rh: Arc<impl RequestHandler<T> + 'static>,
  370. conn_limit: Option<usize>,
  371. settings: RpcSettings,
  372. ex: Arc<smol::Executor<'a>>,
  373. ) -> Result<()> {
  374. loop {
  375. let connection = match listener.next().await {
  376. Ok(negotiation) => negotiation.await,
  377. Err(err) => Err(err),
  378. };
  379. match connection {
  380. Ok((stream, url)) => {
  381. let rh_ = rh.clone();
  382. verbose!(target: "rpc::server", "[RPC] Server accepted conn from {url}");
  383. // Check and reserve a connection slot under the same lock so
  384. // simultaneous accepts on different listeners cannot exceed
  385. // the server-wide limit.
  386. let task = StoppableTask::new();
  387. let mut connections = rh.connections_mut().await;
  388. if let Some(limit) = conn_limit {
  389. if connections.len() >= limit {
  390. drop(connections);
  391. debug!(
  392. target: "rpc::server::run_accept_loop",
  393. "[RPC] Connection limit ({limit}) reached, rejecting {url}",
  394. );
  395. // Send a JSONRPC error before dropping the stream so
  396. // the client can tell "rejected" apart from "unreachabl;e".
  397. let err: JsonResult = JsonError::new(
  398. ErrorCode::ServerError(-32000),
  399. Some("Server connection limit reached".to_string()),
  400. 0,
  401. )
  402. .into();
  403. let (_, mut writer) = smol::io::split(stream);
  404. if settings.use_http() {
  405. let _ = http_write_to_stream(&mut writer, &err).await;
  406. } else {
  407. let _ = write_to_stream(&mut writer, &err).await;
  408. }
  409. // Writer drops here, closing the connection
  410. continue
  411. }
  412. }
  413. let (reader, writer) = smol::io::split(stream);
  414. let reader = Arc::new(Mutex::new(BufReader::new(reader)));
  415. let writer = Arc::new(Mutex::new(writer));
  416. let task_ = task.clone();
  417. let ex_ = ex.clone();
  418. let tasks = Arc::new(ConnectionTasks::default());
  419. let tasks_ = tasks.clone();
  420. // Register before starting so a connection that closes
  421. // immediately cannot finish before it is tracked.
  422. connections.insert(task.clone());
  423. task.clone().start(
  424. accept_with_tasks(
  425. reader,
  426. writer,
  427. url.clone(),
  428. rh.clone(),
  429. tasks,
  430. settings.clone(),
  431. ex_,
  432. ),
  433. |_| async move {
  434. tasks_.stop_all().await;
  435. verbose!(target: "rpc::server", "[RPC] Closed conn from {url}");
  436. rh_.clone().unmark_connection(task_.clone()).await;
  437. },
  438. Error::ChannelStopped,
  439. ex.clone(),
  440. );
  441. drop(connections);
  442. }
  443. // As per accept(2) recommendation:
  444. Err(e) if e.raw_os_error().is_some() => match e.raw_os_error().unwrap() {
  445. libc::EAGAIN | libc::ECONNABORTED | libc::EPROTO | libc::EINTR => continue,
  446. libc::ECONNRESET => {
  447. warn!(
  448. target: "rpc::server::run_accept_loop",
  449. "[RPC] Connection reset by peer in accept_loop"
  450. );
  451. continue
  452. }
  453. libc::ETIMEDOUT => {
  454. warn!(
  455. target: "rpc::server::run_accept_loop",
  456. "[RPC] Connection timed out in accept_loop"
  457. );
  458. continue
  459. }
  460. libc::EPIPE => {
  461. warn!(
  462. target: "rpc::server::run_accept_loop",
  463. "[RPC] Broken pipe in accept_loop"
  464. );
  465. continue
  466. }
  467. x => {
  468. warn!(
  469. target: "rpc::server::run_accept_loop",
  470. "[RPC] Unhandled OS Error: {e} {x}"
  471. );
  472. continue
  473. }
  474. },
  475. // In case a TLS handshake fails, we'll get this:
  476. Err(e) if e.kind() == ErrorKind::UnexpectedEof => continue,
  477. // Handle ErrorKind::Other
  478. Err(e) if e.kind() == ErrorKind::Other => {
  479. if let Some(inner) = std::error::Error::source(&e) {
  480. if let Some(inner) = inner.downcast_ref::<futures_rustls::rustls::Error>() {
  481. warn!(
  482. target: "rpc::server::run_accept_loop",
  483. "[RPC] rustls listener error: {inner:?}"
  484. );
  485. continue
  486. }
  487. }
  488. warn!(
  489. target: "rpc::server::run_accept_loop",
  490. "[RPC] Unhandled ErrorKind::Other error: {e:?}"
  491. );
  492. continue
  493. }
  494. // Errors we didn't handle above:
  495. Err(e) => {
  496. warn!(
  497. target: "rpc::server::run_accept_loop",
  498. "[RPC] Unhandled listener.next() error: {e}"
  499. );
  500. continue
  501. }
  502. }
  503. }
  504. }
  505. /// Start a JSON-RPC server bound to the given accept URLs and use the
  506. /// given [`RequestHandler`] to handle incoming requests.
  507. ///
  508. /// The supported network schemes can be prefixed with `http+` to serve
  509. /// JSON-RPC over HTTP/1.1.
  510. pub async fn listen_and_serve<'a, T: 'a>(
  511. settings: RpcSettings,
  512. rh: Arc<impl RequestHandler<T> + 'static>,
  513. conn_limit: Option<usize>,
  514. ex: Arc<smol::Executor<'a>>,
  515. ) -> Result<()> {
  516. let mut listen_urls = Vec::with_capacity(settings.listen.len());
  517. let mut listener_settings = Vec::with_capacity(settings.listen.len());
  518. for endpoint in &settings.listen {
  519. let use_http = endpoint.scheme().starts_with("http+");
  520. let mut listen_url = endpoint.clone();
  521. if use_http {
  522. let scheme = endpoint.scheme().strip_prefix("http+").unwrap();
  523. listen_url.set_scheme(scheme).map_err(|_| Error::UrlParse(endpoint.to_string()))?;
  524. }
  525. listen_urls.push(listen_url);
  526. let mut endpoint_settings = settings.clone();
  527. endpoint_settings.listen = vec![endpoint.clone()];
  528. listener_settings.push(endpoint_settings);
  529. }
  530. // Bind every socket before starting any accept loop. If one address is
  531. // invalid or unavailable, no partially-running RPC server is left behind.
  532. let listeners = Listener::listen_all(listen_urls, None, false).await?;
  533. let accept_loops =
  534. listeners.into_iter().zip(listener_settings).map(|(listener, endpoint_settings)| {
  535. run_accept_loop(listener, rh.clone(), conn_limit, endpoint_settings, ex.clone())
  536. });
  537. try_join_all(accept_loops).await.map(|_| ())
  538. }
  539. #[cfg(test)]
  540. mod tests {
  541. use super::*;
  542. use crate::{
  543. rpc::client::RpcClient,
  544. system::{msleep, Publisher},
  545. };
  546. use smol::{net::TcpListener, Executor};
  547. struct RpcServer {
  548. rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
  549. subscriber: JsonSubscriber,
  550. }
  551. #[async_trait]
  552. impl RequestHandler<()> for RpcServer {
  553. async fn handle_request(&self, req: JsonRequest) -> JsonResult {
  554. match req.method.as_str() {
  555. "ping" => return self.pong(req.id, req.params).await,
  556. "subscribe" => return self.subscriber.clone().into(),
  557. _ => panic!(),
  558. }
  559. }
  560. async fn connections_mut(&self) -> MutexGuard<'life0, HashSet<StoppableTaskPtr>> {
  561. self.rpc_connections.lock().await
  562. }
  563. }
  564. #[test]
  565. fn conn_manager() -> Result<()> {
  566. let executor = Arc::new(Executor::new());
  567. // This simulates a server and a client. Through the function, there
  568. // are some calls to sleep(), which are used for the tests, because
  569. // otherwise they execute too fast. In practice, The RPC server is
  570. // a long-running task so when polled, it should handle things in a
  571. // correct manner.
  572. smol::block_on(executor.run(async {
  573. // Find an available port
  574. let listener = TcpListener::bind("127.0.0.1:0").await?;
  575. let sockaddr = listener.local_addr()?;
  576. let settings = RpcSettings {
  577. listen: vec![Url::parse(&format!("tcp://127.0.0.1:{}", sockaddr.port()))?],
  578. disabled_methods: vec![],
  579. };
  580. drop(listener);
  581. let rpc_server = Arc::new(RpcServer {
  582. rpc_connections: Mutex::new(HashSet::new()),
  583. subscriber: JsonSubscriber::new("event"),
  584. });
  585. let rpc_server_ = rpc_server.clone();
  586. let server_task = StoppableTask::new();
  587. server_task.clone().start(
  588. listen_and_serve(settings.clone(), rpc_server.clone(), None, executor.clone()),
  589. |res| async move {
  590. match res {
  591. Ok(()) | Err(Error::RpcServerStopped) => {
  592. rpc_server_.stop_connections().await
  593. }
  594. Err(e) => panic!("{e}"),
  595. }
  596. },
  597. Error::RpcServerStopped,
  598. executor.clone(),
  599. );
  600. // Let the server spawn
  601. msleep(500).await;
  602. // Connect a client
  603. let rpc_client0 = RpcClient::new(settings.listen[0].clone(), executor.clone()).await?;
  604. msleep(500).await;
  605. assert!(rpc_server.active_connections().await == 1);
  606. // Connect another client
  607. let rpc_client1 = RpcClient::new(settings.listen[0].clone(), executor.clone()).await?;
  608. msleep(500).await;
  609. assert!(rpc_server.active_connections().await == 2);
  610. // And another one
  611. let _rpc_client2 = RpcClient::new(settings.listen[0].clone(), executor.clone()).await?;
  612. msleep(500).await;
  613. assert!(rpc_server.active_connections().await == 3);
  614. // Close the first client
  615. rpc_client0.stop().await;
  616. msleep(500).await;
  617. assert!(rpc_server.active_connections().await == 2);
  618. // Close the second client
  619. rpc_client1.stop().await;
  620. msleep(500).await;
  621. assert!(rpc_server.active_connections().await == 1);
  622. // The Listener should be stopped when we stop the server task.
  623. server_task.stop().await;
  624. assert!(RpcClient::new(settings.listen[0].clone(), executor.clone()).await.is_err());
  625. // After the server is stopped, the connections tasks should also be stopped
  626. assert!(rpc_server.active_connections().await == 0);
  627. Ok(())
  628. }))
  629. }
  630. #[test]
  631. fn subscriber_tasks_follow_connection_lifetime() -> Result<()> {
  632. let executor = Arc::new(Executor::new());
  633. smol::block_on(executor.run(async {
  634. let listener = TcpListener::bind("127.0.0.1:0").await?;
  635. let sockaddr = listener.local_addr()?;
  636. let settings = RpcSettings {
  637. listen: vec![Url::parse(&format!("tcp://127.0.0.1:{}", sockaddr.port()))?],
  638. disabled_methods: vec![],
  639. };
  640. drop(listener);
  641. let rpc_server = Arc::new(RpcServer {
  642. rpc_connections: Mutex::new(HashSet::new()),
  643. subscriber: JsonSubscriber::new("event"),
  644. });
  645. let rpc_server_ = rpc_server.clone();
  646. let server_task = StoppableTask::new();
  647. server_task.clone().start(
  648. listen_and_serve(settings.clone(), rpc_server.clone(), None, executor.clone()),
  649. |res| async move {
  650. match res {
  651. Ok(()) | Err(Error::RpcServerStopped) => {
  652. rpc_server_.stop_connections().await
  653. }
  654. Err(e) => panic!("{e}"),
  655. }
  656. },
  657. Error::RpcServerStopped,
  658. executor.clone(),
  659. );
  660. msleep(500).await;
  661. for _ in 0..32 {
  662. let client =
  663. Arc::new(RpcClient::new(settings.listen[0].clone(), executor.clone()).await?);
  664. let client_ = client.clone();
  665. let subscriber_task = executor.spawn(async move {
  666. client_
  667. .subscribe(
  668. JsonRequest::new("subscribe", JsonValue::Array(vec![])),
  669. Publisher::new(),
  670. )
  671. .await
  672. });
  673. for _ in 0..100 {
  674. if rpc_server.subscriber.publisher.active_subscriptions() == 1 {
  675. break
  676. }
  677. msleep(10).await;
  678. }
  679. assert_eq!(rpc_server.subscriber.publisher.active_subscriptions(), 1);
  680. client.stop().await;
  681. assert!(subscriber_task.await.is_err());
  682. for _ in 0..100 {
  683. if rpc_server.active_connections().await == 0 {
  684. break
  685. }
  686. msleep(10).await;
  687. }
  688. assert_eq!(rpc_server.active_connections().await, 0);
  689. assert_eq!(rpc_server.subscriber.publisher.active_subscriptions(), 0);
  690. }
  691. server_task.stop().await;
  692. assert_eq!(rpc_server.active_connections().await, 0);
  693. assert_eq!(rpc_server.subscriber.publisher.active_subscriptions(), 0);
  694. Ok(())
  695. }))
  696. }
  697. }