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§

§

impl AsyncClient

pub fn build(url: Url) -> Builder<Async>

Returns a builder for a new client connecting to url.

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.

pub async fn send_api_request<Api>( &self, request: &Api ) -> impl Future<Output = Result<<Api as Api>::Response, ApiError<<Api as Api>::Error>>>where Api: Api,

Sends an api request.

pub fn effective_permissions(&self) -> Option<Permissions>

Returns the current effective permissions for the client. Returns None if unauthenticated.

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§

§

impl AsyncStorageConnection for AsyncClient

§

type Authenticated = AsyncClient

The StorageConnection type returned from authentication calls.
§

type Database = AsyncRemoteDatabase

The type that represents a database for this implementation.
§

fn admin<'life0, 'async_trait>( &'life0 self ) -> Pin<Box<dyn Future<Output = <AsyncClient as AsyncStorageConnection>::Database> + Send + 'async_trait, Global>>where 'life0: 'async_trait, AsyncClient: 'async_trait,

Returns the currently authenticated session, if any.
§

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, Global>>where 'life0: 'async_trait, 'life1: 'async_trait, AsyncClient: 'async_trait,

Creates a database named name using the SchemaName schema. Read more
§

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, Global>>where 'life0: 'async_trait, 'life1: 'async_trait, DB: 'async_trait + Schema, AsyncClient: 'async_trait,

Returns a reference to database name with schema DB.
§

fn delete_database<'life0, 'life1, 'async_trait>( &'life0 self, name: &'life1 str ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait, Global>>where 'life0: 'async_trait, 'life1: 'async_trait, AsyncClient: 'async_trait,

Deletes a database named name. Read more
§

fn list_databases<'life0, 'async_trait>( &'life0 self ) -> Pin<Box<dyn Future<Output = Result<Vec<Database, Global>, Error>> + Send + 'async_trait, Global>>where 'life0: 'async_trait, AsyncClient: 'async_trait,

Lists the databases in this storage.
§

fn list_available_schemas<'life0, 'async_trait>( &'life0 self ) -> Pin<Box<dyn Future<Output = Result<Vec<SchemaSummary, Global>, Error>> + Send + 'async_trait, Global>>where 'life0: 'async_trait, AsyncClient: 'async_trait,

Lists the SchemaNames registered with this storage.
§

fn create_user<'life0, 'life1, 'async_trait>( &'life0 self, username: &'life1 str ) -> Pin<Box<dyn Future<Output = Result<u64, Error>> + Send + 'async_trait, Global>>where 'life0: 'async_trait, 'life1: 'async_trait, AsyncClient: 'async_trait,

Creates a user.
§

fn delete_user<'user, 'life0, 'async_trait, U>( &'life0 self, user: U ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait, Global>>where 'user: 'async_trait, 'life0: 'async_trait, U: 'async_trait + Nameable<'user, u64> + Send + Sync, AsyncClient: 'async_trait,

Deletes a user.
§

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, Global>>where 'user: 'async_trait, 'life0: 'async_trait, U: 'async_trait + Nameable<'user, u64> + Send + Sync, AsyncClient: 'async_trait,

Sets a user’s password.
§

fn authenticate<'life0, 'async_trait>( &'life0 self, authentication: Authentication ) -> Pin<Box<dyn Future<Output = Result<<AsyncClient as AsyncStorageConnection>::Authenticated, Error>> + Send + 'async_trait, Global>>where 'life0: 'async_trait, AsyncClient: 'async_trait,

Authenticates using an AuthenticationToken. If successful, the returned instance will have the permissions from identity.
§

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, Global>>where 'life0: 'async_trait, 'life1: 'async_trait, AsyncClient: 'async_trait,

Assumes the identity. If successful, the returned instance will have the merged permissions of the current authentication session and the permissions from identity.
§

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, Global>>where 'user: 'async_trait, 'group: 'async_trait, 'life0: 'async_trait, U: 'async_trait + Nameable<'user, u64> + Send + Sync, G: 'async_trait + Nameable<'group, u64> + Send + Sync, AsyncClient: 'async_trait,

Adds a user to a permission group.
§

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, Global>>where 'user: 'async_trait, 'group: 'async_trait, 'life0: 'async_trait, U: 'async_trait + Nameable<'user, u64> + Send + Sync, G: 'async_trait + Nameable<'group, u64> + Send + Sync, AsyncClient: 'async_trait,

Removes a user from a permission group.
§

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, Global>>where 'user: 'async_trait, 'group: 'async_trait, 'life0: 'async_trait, U: 'async_trait + Nameable<'user, u64> + Send + Sync, G: 'async_trait + Nameable<'group, u64> + Send + Sync, AsyncClient: 'async_trait,

Adds a user to a permission group.
§

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, Global>>where 'user: 'async_trait, 'group: 'async_trait, 'life0: 'async_trait, U: 'async_trait + Nameable<'user, u64> + Send + Sync, G: 'async_trait + Nameable<'group, u64> + Send + Sync, AsyncClient: 'async_trait,

Removes a user from a permission group.
§

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, Global>>where 'life0: 'async_trait, 'life1: 'async_trait, DB: 'async_trait + Schema, Self: 'async_trait,

Creates a database named name with the Schema provided. Read more
§

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, Global>>where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Authenticates using an AuthenticationToken. If successful, the returned instance will have the permissions from identity.
§

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, Global>>where 'name: 'async_trait, 'life0: 'async_trait, User: 'async_trait + Nameable<'name, u64> + Send, Self: 'async_trait,

Authenticates a User using a password. If successful, the returned instance will have the permissions from identity.
§

impl Clone for AsyncClient

§

fn clone(&self) -> AsyncClient

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
§

impl Debug for AsyncClient

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl Drop for AsyncClient

§

fn drop(&mut self)

Executes the destructor for this type. Read more
§

impl From<AsyncClient> for BlockingClient

§

fn from(client: AsyncClient) -> BlockingClient

Converts to this type from the input type.
§

impl From<BlockingClient> for AsyncClient

§

fn from(client: BlockingClient) -> AsyncClient

Converts to this type from the input type.
§

impl HasSession for AsyncClient

§

fn session(&self) -> Option<&Session>

Returns the currently authenticated session, if any.
§

fn allowed_to<'a, R, P>(&self, resource_name: R, action: &P) -> boolwhere R: AsRef<[Identifier<'a>]>, P: Action,

Checks if action is permitted against resource_name.
§

fn check_permission<'a, R, P>( &self, resource_name: R, action: &P ) -> Result<(), Error>where R: AsRef<[Identifier<'a>]>, P: Action,

Checks if action is permitted against resource_name. If permission is denied, returns a PermissionDenied error.
§

impl PartialEq<AsyncClient> for AsyncClient

§

fn eq(&self, other: &AsyncClient) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere T: 'a,

§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

§

impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere T: 'a,

§

fn implicit( self, class: Class, constructed: bool, tag: u32 ) -> TaggedParser<'a, Implicit, Self, E>

source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for Twhere V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more