surrealdb/api/engine/remote/ws/
mod.rs

1//! WebSocket engine
2
3#[cfg(not(target_arch = "wasm32"))]
4pub(crate) mod native;
5#[cfg(target_arch = "wasm32")]
6pub(crate) mod wasm;
7
8use crate::api;
9use crate::api::conn::DbResponse;
10use crate::api::conn::Method;
11use crate::api::err::Error;
12use crate::api::Connect;
13use crate::api::Result;
14use crate::api::Surreal;
15use crate::dbs::Notification;
16use crate::dbs::Status;
17use crate::opt::IntoEndpoint;
18use crate::sql::Strand;
19use crate::sql::Value;
20use serde::Deserialize;
21use std::marker::PhantomData;
22use std::time::Duration;
23
24pub(crate) const PATH: &str = "rpc";
25const PING_INTERVAL: Duration = Duration::from_secs(5);
26const PING_METHOD: &str = "ping";
27
28/// The WS scheme used to connect to `ws://` endpoints
29#[derive(Debug)]
30pub struct Ws;
31
32/// The WSS scheme used to connect to `wss://` endpoints
33#[derive(Debug)]
34pub struct Wss;
35
36/// A WebSocket client for communicating with the server via WebSockets
37#[derive(Debug, Clone)]
38pub struct Client {
39	pub(crate) id: i64,
40	method: Method,
41}
42
43impl Surreal<Client> {
44	/// Connects to a specific database endpoint, saving the connection on the static client
45	///
46	/// # Examples
47	///
48	/// ```no_run
49	/// use once_cell::sync::Lazy;
50	/// use surrealdb::Surreal;
51	/// use surrealdb::engine::remote::ws::Client;
52	/// use surrealdb::engine::remote::ws::Ws;
53	///
54	/// static DB: Lazy<Surreal<Client>> = Lazy::new(Surreal::init);
55	///
56	/// # #[tokio::main]
57	/// # async fn main() -> surrealdb::Result<()> {
58	/// DB.connect::<Ws>("localhost:8000").await?;
59	/// # Ok(())
60	/// # }
61	/// ```
62	pub fn connect<P>(
63		&self,
64		address: impl IntoEndpoint<P, Client = Client>,
65	) -> Connect<Client, ()> {
66		Connect {
67			router: self.router.clone(),
68			address: address.into_endpoint(),
69			capacity: 0,
70			client: PhantomData,
71			response_type: PhantomData,
72		}
73	}
74}
75
76#[derive(Clone, Debug, Deserialize)]
77pub(crate) struct Failure {
78	pub(crate) code: i64,
79	pub(crate) message: String,
80}
81
82#[derive(Debug, Deserialize)]
83pub(crate) enum Data {
84	Other(Value),
85	Query(Vec<QueryMethodResponse>),
86	Live(Notification),
87}
88
89type ServerResult = std::result::Result<Data, Failure>;
90
91impl From<Failure> for Error {
92	fn from(failure: Failure) -> Self {
93		match failure.code {
94			-32600 => Self::InvalidRequest(failure.message),
95			-32602 => Self::InvalidParams(failure.message),
96			-32603 => Self::InternalError(failure.message),
97			-32700 => Self::ParseError(failure.message),
98			_ => Self::Query(failure.message),
99		}
100	}
101}
102
103#[derive(Debug, Deserialize)]
104pub(crate) struct QueryMethodResponse {
105	#[allow(dead_code)]
106	time: String,
107	status: Status,
108	result: Value,
109}
110
111impl DbResponse {
112	fn from(result: ServerResult) -> Result<Self> {
113		match result.map_err(Error::from)? {
114			Data::Other(value) => Ok(DbResponse::Other(value)),
115			Data::Query(results) => Ok(DbResponse::Query(api::Response(
116				results
117					.into_iter()
118					.map(|response| match response.status {
119						Status::Ok => Ok(response.result),
120						Status::Err => match response.result {
121							Value::Strand(Strand(message)) => Err(Error::Query(message).into()),
122							message => Err(Error::Query(message.to_string()).into()),
123						},
124					})
125					.enumerate()
126					.collect(),
127			))),
128			// Live notifications don't call this method
129			Data::Live(..) => unreachable!(),
130		}
131	}
132}
133
134#[derive(Debug, Deserialize)]
135pub(crate) struct Response {
136	id: Option<Value>,
137	pub(crate) result: ServerResult,
138}