Struct bonsaidb::client::AsyncClient
source · pub struct AsyncClient { /* private fields */ }
Expand description
Client for connecting to a BonsaiDb server.
How this type automatically reconnects
This type is designed to automatically reconnect if the underlying network
connection has been lost. When a disconnect happens, the error that caused
the disconnection will be returned to at least one requestor. If multiple
pending requests are outstanding, all remaining pending requests will have
an Error::Disconnected
returned. This allows the application to detect when a networking issue has
arisen.
If the disconnect happens while the client is completely idle, the next request will report the disconnection error. The subsequent request will cause the client to begin reconnecting again.
When unauthenticated, this reconnection behavior is mostly transparent –
disconnection errors can be shown to the user, and service will be restored
automatically. However, when dealing with authentication, the client does
not store credentials to be able to send them again when reconnecting. This
means that the existing client handles will lose their authentication when
the network connection is broken. The current authentication status can be
checked using HasSession::session()
.
Connecting via QUIC
The URL scheme to connect via QUIC is bonsaidb
. If no port is specified,
port 5645 is assumed.
With a valid TLS certificate
let client = AsyncClient::build(Url::parse("bonsaidb://my-server.com")?).build()?;
With a Self-Signed Pinned Certificate
When using install_self_signed_certificate()
, clients will need the
contents of the pinned-certificate.der
file within the database. It can be
specified when building the client:
let certificate =
Certificate::from_der(std::fs::read("mydb.bonsaidb/pinned-certificate.der")?)?;
let client = AsyncClient::build(Url::parse("bonsaidb://localhost")?)
.with_certificate(certificate)
.build()?;
Connecting via WebSockets
WebSockets are built atop the HTTP protocol. There are two URL schemes for WebSockets:
ws
: Insecure WebSockets. Port 80 is assumed if no port is specified.wss
: Secure WebSockets. Port 443 is assumed if no port is specified.
Without TLS
let client = AsyncClient::build(Url::parse("ws://localhost")?).build()?;
With TLS
let client = AsyncClient::build(Url::parse("wss://my-server.com")?).build()?;
Using a Api
Our user guide has a section on creating and
using
an Api
.
// `bonsaidb_core` is re-exported to `bonsaidb::core` or `bonsaidb_client::core`.
use bonsaidb_core::api::{Api, ApiName, Infallible};
use bonsaidb_core::schema::Qualified;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct Ping;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Pong;
impl Api for Ping {
type Error = Infallible;
type Response = Pong;
fn name() -> ApiName {
ApiName::private("ping")
}
}
let client = AsyncClient::build(Url::parse("bonsaidb://localhost")?).build()?;
let Pong = client.send_api_request(&Ping).await?;
Receiving out-of-band messages from the server
If the server sends a message that isn’t in response to a request, the client will invoke it’s api callback:
let client = AsyncClient::build(Url::parse("bonsaidb://localhost")?)
.with_api_callback(ApiCallback::<Ping>::new(|result: Pong| async move {
println!("Received out-of-band Pong");
}))
.build()?;
Implementations§
source§impl AsyncClient
impl AsyncClient
sourcepub fn new(url: Url) -> Result<AsyncClient, Error>
pub fn new(url: Url) -> Result<AsyncClient, Error>
Initialize a client connecting to url
. This client can be shared by
cloning it. All requests are done asynchronously over the same
connection.
If the client has an error connecting, the first request made will
present that error. If the client disconnects while processing requests,
all requests being processed will exit and return
Error::Disconnected
.
The client will automatically try reconnecting.
The goal of this design of this reconnection strategy is to make it easier to build resilliant apps. By allowing existing Client instances to recover and reconnect, each component of the apps built can adopt a “retry-to-recover” design, or “abort-and-fail” depending on how critical the database is to operation.
sourcepub async fn send_api_request<Api>(
&self,
request: &Api
) -> Result<<Api as Api>::Response, ApiError<<Api as Api>::Error>>where
Api: Api,
pub async fn send_api_request<Api>(
&self,
request: &Api
) -> Result<<Api as Api>::Response, ApiError<<Api as Api>::Error>>where
Api: Api,
Sends an api request
.
sourcepub fn effective_permissions(&self) -> Option<Permissions>
pub fn effective_permissions(&self) -> Option<Permissions>
Returns the current effective permissions for the client. Returns None if unauthenticated.
sourcepub fn set_request_timeout(&mut self, timeout: impl Into<Duration>)
pub fn set_request_timeout(&mut self, timeout: impl Into<Duration>)
Sets this instance’s request timeout.
Each client has its own timeout. When cloning a client, this timeout setting will be copied to the clone.
Trait Implementations§
source§impl AsyncStorageConnection for AsyncClient
impl AsyncStorageConnection for AsyncClient
§type Authenticated = AsyncClient
type Authenticated = AsyncClient
StorageConnection
type returned from authentication calls.§type Database = AsyncRemoteDatabase
type Database = AsyncRemoteDatabase
source§fn admin<'life0, 'async_trait>(
&'life0 self
) -> Pin<Box<dyn Future<Output = <AsyncClient as AsyncStorageConnection>::Database> + Send + 'async_trait>>where
'life0: 'async_trait,
AsyncClient: 'async_trait,
fn admin<'life0, 'async_trait>(
&'life0 self
) -> Pin<Box<dyn Future<Output = <AsyncClient as AsyncStorageConnection>::Database> + Send + 'async_trait>>where
'life0: 'async_trait,
AsyncClient: 'async_trait,
source§fn create_database_with_schema<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
schema: SchemaName,
only_if_needed: bool
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
AsyncClient: 'async_trait,
fn create_database_with_schema<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
schema: SchemaName,
only_if_needed: bool
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
AsyncClient: 'async_trait,
source§fn database<'life0, 'life1, 'async_trait, DB>(
&'life0 self,
name: &'life1 str
) -> Pin<Box<dyn Future<Output = Result<<AsyncClient as AsyncStorageConnection>::Database, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
DB: 'async_trait + Schema,
AsyncClient: 'async_trait,
fn database<'life0, 'life1, 'async_trait, DB>(
&'life0 self,
name: &'life1 str
) -> Pin<Box<dyn Future<Output = Result<<AsyncClient as AsyncStorageConnection>::Database, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
DB: 'async_trait + Schema,
AsyncClient: 'async_trait,
name
with schema DB
.source§fn delete_database<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
AsyncClient: 'async_trait,
fn delete_database<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
AsyncClient: 'async_trait,
name
. Read moresource§fn list_databases<'life0, 'async_trait>(
&'life0 self
) -> Pin<Box<dyn Future<Output = Result<Vec<Database>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
AsyncClient: 'async_trait,
fn list_databases<'life0, 'async_trait>(
&'life0 self
) -> Pin<Box<dyn Future<Output = Result<Vec<Database>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
AsyncClient: 'async_trait,
source§fn list_available_schemas<'life0, 'async_trait>(
&'life0 self
) -> Pin<Box<dyn Future<Output = Result<Vec<SchemaSummary>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
AsyncClient: 'async_trait,
fn list_available_schemas<'life0, 'async_trait>(
&'life0 self
) -> Pin<Box<dyn Future<Output = Result<Vec<SchemaSummary>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
AsyncClient: 'async_trait,
SchemaName
s registered with this storage.source§fn create_user<'life0, 'life1, 'async_trait>(
&'life0 self,
username: &'life1 str
) -> Pin<Box<dyn Future<Output = Result<u64, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
AsyncClient: 'async_trait,
fn create_user<'life0, 'life1, 'async_trait>(
&'life0 self,
username: &'life1 str
) -> Pin<Box<dyn Future<Output = Result<u64, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
AsyncClient: 'async_trait,
source§fn delete_user<'user, 'life0, 'async_trait, U>(
&'life0 self,
user: U
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'user: 'async_trait,
'life0: 'async_trait,
U: 'async_trait + Nameable<'user, u64> + Send + Sync,
AsyncClient: 'async_trait,
fn delete_user<'user, 'life0, 'async_trait, U>(
&'life0 self,
user: U
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'user: 'async_trait,
'life0: 'async_trait,
U: 'async_trait + Nameable<'user, u64> + Send + Sync,
AsyncClient: 'async_trait,
source§fn set_user_password<'user, 'life0, 'async_trait, U>(
&'life0 self,
user: U,
password: SensitiveString
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'user: 'async_trait,
'life0: 'async_trait,
U: 'async_trait + Nameable<'user, u64> + Send + Sync,
AsyncClient: 'async_trait,
fn set_user_password<'user, 'life0, 'async_trait, U>(
&'life0 self,
user: U,
password: SensitiveString
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'user: 'async_trait,
'life0: 'async_trait,
U: 'async_trait + Nameable<'user, u64> + Send + Sync,
AsyncClient: 'async_trait,
source§fn authenticate<'life0, 'async_trait>(
&'life0 self,
authentication: Authentication
) -> Pin<Box<dyn Future<Output = Result<<AsyncClient as AsyncStorageConnection>::Authenticated, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
AsyncClient: 'async_trait,
fn authenticate<'life0, 'async_trait>(
&'life0 self,
authentication: Authentication
) -> Pin<Box<dyn Future<Output = Result<<AsyncClient as AsyncStorageConnection>::Authenticated, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
AsyncClient: 'async_trait,
AuthenticationToken
. If
successful, the returned instance will have the permissions from
identity
.source§fn assume_identity<'life0, 'life1, 'async_trait>(
&'life0 self,
identity: IdentityReference<'life1>
) -> Pin<Box<dyn Future<Output = Result<<AsyncClient as AsyncStorageConnection>::Authenticated, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
AsyncClient: 'async_trait,
fn assume_identity<'life0, 'life1, 'async_trait>(
&'life0 self,
identity: IdentityReference<'life1>
) -> Pin<Box<dyn Future<Output = Result<<AsyncClient as AsyncStorageConnection>::Authenticated, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
AsyncClient: 'async_trait,
identity
. If successful, the returned instance will have
the merged permissions of the current authentication session and the
permissions from identity
.source§fn add_permission_group_to_user<'user, 'group, 'life0, 'async_trait, U, G>(
&'life0 self,
user: U,
permission_group: G
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
fn add_permission_group_to_user<'user, 'group, 'life0, 'async_trait, U, G>( &'life0 self, user: U, permission_group: G ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
source§fn remove_permission_group_from_user<'user, 'group, 'life0, 'async_trait, U, G>(
&'life0 self,
user: U,
permission_group: G
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
fn remove_permission_group_from_user<'user, 'group, 'life0, 'async_trait, U, G>( &'life0 self, user: U, permission_group: G ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
source§fn add_role_to_user<'user, 'group, 'life0, 'async_trait, U, G>(
&'life0 self,
user: U,
role: G
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
fn add_role_to_user<'user, 'group, 'life0, 'async_trait, U, G>( &'life0 self, user: U, role: G ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
source§fn remove_role_from_user<'user, 'group, 'life0, 'async_trait, U, G>(
&'life0 self,
user: U,
role: G
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
fn remove_role_from_user<'user, 'group, 'life0, 'async_trait, U, G>( &'life0 self, user: U, role: G ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
source§fn create_database<'life0, 'life1, 'async_trait, DB>(
&'life0 self,
name: &'life1 str,
only_if_needed: bool
) -> Pin<Box<dyn Future<Output = Result<Self::Database, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
DB: 'async_trait + Schema,
Self: 'async_trait,
fn create_database<'life0, 'life1, 'async_trait, DB>(
&'life0 self,
name: &'life1 str,
only_if_needed: bool
) -> Pin<Box<dyn Future<Output = Result<Self::Database, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
DB: 'async_trait + Schema,
Self: 'async_trait,
source§fn authenticate_with_token<'life0, 'life1, 'async_trait>(
&'life0 self,
id: u64,
token: &'life1 SensitiveString
) -> Pin<Box<dyn Future<Output = Result<<Self::Authenticated as AsyncStorageConnection>::Authenticated, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn authenticate_with_token<'life0, 'life1, 'async_trait>(
&'life0 self,
id: u64,
token: &'life1 SensitiveString
) -> Pin<Box<dyn Future<Output = Result<<Self::Authenticated as AsyncStorageConnection>::Authenticated, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
AuthenticationToken
. If
successful, the returned instance will have the permissions from
identity
.source§fn authenticate_with_password<'name, 'life0, 'async_trait, User>(
&'life0 self,
user: User,
password: SensitiveString
) -> Pin<Box<dyn Future<Output = Result<Self::Authenticated, Error>> + Send + 'async_trait>>
fn authenticate_with_password<'name, 'life0, 'async_trait, User>( &'life0 self, user: User, password: SensitiveString ) -> Pin<Box<dyn Future<Output = Result<Self::Authenticated, Error>> + Send + 'async_trait>>
User
using a password. If
successful, the returned instance will have the permissions from
identity
.source§impl Clone for AsyncClient
impl Clone for AsyncClient
source§fn clone(&self) -> AsyncClient
fn clone(&self) -> AsyncClient
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl Debug for AsyncClient
impl Debug for AsyncClient
source§impl Drop for AsyncClient
impl Drop for AsyncClient
source§impl From<AsyncClient> for BlockingClient
impl From<AsyncClient> for BlockingClient
source§fn from(client: AsyncClient) -> BlockingClient
fn from(client: AsyncClient) -> BlockingClient
source§impl From<BlockingClient> for AsyncClient
impl From<BlockingClient> for AsyncClient
source§fn from(client: BlockingClient) -> AsyncClient
fn from(client: BlockingClient) -> AsyncClient
source§impl HasSession for AsyncClient
impl HasSession for AsyncClient
source§fn allowed_to<'a, R, P>(&self, resource_name: R, action: &P) -> bool
fn allowed_to<'a, R, P>(&self, resource_name: R, action: &P) -> bool
action
is permitted against resource_name
.source§fn check_permission<'a, R, P>(
&self,
resource_name: R,
action: &P
) -> Result<(), Error>
fn check_permission<'a, R, P>( &self, resource_name: R, action: &P ) -> Result<(), Error>
action
is permitted against resource_name
. If permission
is denied, returns a PermissionDenied
error.source§impl PartialEq for AsyncClient
impl PartialEq for AsyncClient
source§fn eq(&self, other: &AsyncClient) -> bool
fn eq(&self, other: &AsyncClient) -> bool
self
and other
values to be equal, and is used
by ==
.