1use std::{
2 fmt::Display,
3 sync::Arc,
4};
5
6use anyhow::{
7 Result,
8 bail,
9};
10use serde::{
11 Serialize,
12 de::DeserializeOwned,
13};
14use tokio_util::sync::CancellationToken;
15use url::Url;
16pub use wsio_core as core;
17
18mod builder;
19mod config;
20mod runtime;
21pub mod session;
22
23use crate::{
24 builder::WsIoClientBuilder,
25 core::traits::task::spawner::TaskSpawner,
26 runtime::WsIoClientRuntime,
27 session::WsIoClientSession,
28};
29
30#[derive(Clone)]
32pub struct WsIoClient(Arc<WsIoClientRuntime>);
33
34impl WsIoClient {
35 pub fn builder<U>(url: U) -> Result<WsIoClientBuilder>
37 where
38 U: TryInto<Url>,
39 U::Error: Display,
40 {
41 let url = match url.try_into() {
42 Ok(url) => url,
43 Err(err) => bail!("Invalid URL: {err}"),
44 };
45
46 if url.scheme() == "wss"
47 && !cfg!(any(
48 feature = "tls-native",
49 feature = "tls-rustls-native",
50 feature = "tls-rustls-webpki",
51 ))
52 {
53 bail!("TLS is required for wss:// URLs, but no TLS feature is enabled");
54 }
55
56 WsIoClientBuilder::new(url)
57 }
58
59 pub fn cancel_token(&self) -> Arc<CancellationToken> {
60 self.0.cancel_token()
61 }
62
63 pub async fn connect(&self) {
64 self.0.connect().await
65 }
66
67 pub async fn disconnect(&self) {
68 self.0.disconnect().await
69 }
70
71 pub async fn emit<D: Serialize>(&self, event: impl AsRef<str>, data: Option<&D>) -> Result<()> {
72 self.0.emit(event.as_ref(), data).await
73 }
74
75 #[inline]
76 pub fn is_session_ready(&self) -> bool {
77 self.0.is_session_ready()
78 }
79
80 #[inline]
81 pub fn off(&self, event: impl AsRef<str>) {
82 self.0.off(event.as_ref());
83 }
84
85 #[inline]
86 pub fn off_by_handler_id(&self, event: impl AsRef<str>, handler_id: u32) {
87 self.0.off_by_handler_id(event.as_ref(), handler_id);
88 }
89
90 #[inline]
91 pub fn on<H, Fut, D>(&self, event: impl AsRef<str>, handler: H) -> u32
92 where
93 H: Fn(Arc<WsIoClientSession>, Arc<D>) -> Fut + Send + Sync + 'static,
94 Fut: Future<Output = Result<()>> + Send + 'static,
95 D: DeserializeOwned + Send + Sync + 'static,
96 {
97 self.0.on(event.as_ref(), handler)
98 }
99
100 #[inline]
101 pub fn spawn_task<F: Future<Output = Result<()>> + Send + 'static>(&self, future: F) {
102 self.0.spawn_task(future);
103 }
104}