Crate dco3

source ·
Expand description

§dco3 - DRACOON API wrapper in Rust

dco3 is an async wrapper around API calls in DRACOON. DRACOON is a cloud service provider - more information can be found on https://dracoon.com. The name is based on several other projects pointing to oxide (Rust) and DRACOON.

§Usage

All API calls are implemented by the Dracoon struct. It can be created by using the builder() method.

In order to access specific API calls, the Dracoon struct needs to be in the Connected state. This can be achieved by calling the connect method. To use specific endpoints, you need to import relevant traits. Currently, the following traits are implemented:

§Example

use dco3::{Dracoon, OAuth2Flow, User};

#[tokio::main]
async fn main() {
   let dracoon = Dracoon::builder()
      .with_base_url("https://dracoon.team")
      .with_client_id("client_id")
      .with_client_secret("client_secret")
      .build()
      .unwrap()
      .connect(OAuth2Flow::password_flow("username", "password"))
      .await
      .unwrap();

  let user_info = dracoon.user.get_user_account().await.unwrap();
  println!("User info: {:?}", user_info);
}

§Authentication

All supported OAuth2 flows are implemented.

§Password Flow

use dco3::{Dracoon, OAuth2Flow};

#[tokio::main]
async fn main() {

   // you can instantiate the required flow by using the `OAuth2Flow` enum
   let password_flow = OAuth2Flow::password_flow("username", "password");

   let dracoon = Dracoon::builder()
      .with_base_url("https://dracoon.team")
      .with_client_id("client_id")
      .with_client_secret("client_secret")
      .build()
      .unwrap()
      .connect(password_flow)
      .await
      .unwrap();
}

§Authorization Code Flow

use dco3::{Dracoon, OAuth2Flow};

#[tokio::main]
async fn main() {

   let mut dracoon = Dracoon::builder()
      .with_base_url("https://dracoon.team")
      .with_client_id("client_id")
      .with_client_secret("client_secret")
      .with_redirect_uri("https://redirect.uri")
      .build()
      .unwrap();

   // initiate the authorization code flow
   let authorize_url = dracoon.get_authorize_url();

   // get auth code
   let auth_code = "some_auth_code";

   // you can instantiate the required flow by using the `OAuth2Flow` enum
   let auth_code_flow = OAuth2Flow::authorization_code(auth_code);

   let dracoon = dracoon.connect(auth_code_flow).await.unwrap();
}

§Refresh Token

use dco3::{Dracoon, OAuth2Flow};

#[tokio::main]
async fn main() {

  let refresh_token = "some_refresh_token";

  let dracoon = Dracoon::builder()
    .with_base_url("https://dracoon.team")
    .with_client_id("client_id")
    .with_client_secret("client_secret")
    .build()
    .unwrap()
    .connect(OAuth2Flow::refresh_token(refresh_token))
    .await
    .unwrap();

}

§Simple

use dco3::{Dracoon, OAuth2Flow};

#[tokio::main]
async fn main() {

 // you can also pass the access token directly
 let dracoon = Dracoon::builder()
  .with_base_url("https://dracoon.team")
  .with_client_id("client_id")
  .with_client_secret("client_secret")
  .build()
  .unwrap()
  .connect(OAuth2Flow::simple("access_token"))
  .await
  .unwrap();

 // be aware that the access token refresh will *not* work
 // once the token is expired, you need to pass a new token

}

§Error handling

All errors are wrapped in the DracoonClientError enum.

Most errrors are related to general usage (like missing parameters).

All API errors are wrapped in the DracoonClientError::Http variant. The variant contains response with relevant status code and message.

You can check if the underlying error message if a specific API error by using the is_* methods.

use dco3::{Dracoon, OAuth2Flow, Nodes};

#[tokio::main]

async fn main() {

 let dracoon = Dracoon::builder()
   .with_base_url("https://dracoon.team")
   .with_client_id("client_id")
   .with_client_secret("client_secret")
   .build()
   .unwrap()
   .connect(OAuth2Flow::PasswordFlow("username".into(), "password".into()))
   .await
   .unwrap();

let node = dracoon.nodes.get_node(123).await;

match node {
 Ok(node) => println!("Node info: {:?}", node),
Err(err) => {
 if err.is_not_found() {
    println!("Node not found");
    } else {
         println!("Error: {:?}", err);
           }
        }
      }
 }

If you need more information about the error, you can use the get_http_error method.

use dco3::{Dracoon, OAuth2Flow, Nodes};

#[tokio::main]

async fn main() {

 let dracoon = Dracoon::builder()
   .with_base_url("https://dracoon.team")
   .with_client_id("client_id")
   .with_client_secret("client_secret")
   .build()
   .unwrap()
   .connect(OAuth2Flow::PasswordFlow("username".into(), "password".into()))
   .await
   .unwrap();

let node = dracoon.nodes.get_node(123).await;

match node {
 Ok(node) => println!("Node info: {:?}", node),
Err(err) => {
  if let Some(http_err) = err.get_http_error() {
   // check error type
  if http_err.is_not_found() {
   // do something
   println!("Node not found");
   // check error message
  println!("Error message: {}", http_err.error_message());
   // access error details
  println!("Error details: {}", http_err.debug_info().unwrap());
    }
   }
  }
 }
}

§Retries

The client will automatically retry failed requests. You can configure the retry behavior by passing your config during client creation.

Default values are: 5 retries, min delay 600ms, max delay 20s. Keep in mind that you cannot set arbitrary values - for all values, minimum and maximum values are defined.


use dco3::{Dracoon, OAuth2Flow};

#[tokio::main]
async fn main() {

 let dracoon = Dracoon::builder()
  .with_base_url("https://dracoon.team")
  .with_client_id("client_id")
  .with_client_secret("client_secret")
  .with_max_retries(3)
  .with_min_retry_delay(400)
  .with_max_retry_delay(1000)
  .build();

}

§Building requests

All API calls are implemented as traits. Each API call that requires a sepcific payload has a corresponding builder. To access the builder, you can call the builder() method.

let room = CreateRoomRequest::builder("My Room")
           .with_parent_id(123)
           .with_admin_ids(vec![1, 2, 3])
           .build();

let room = dracoon.nodes.create_room(room).await.unwrap();

Some requests do not have any complicated fields - in these cases, use the new() method.


// this takes a mandatory name and optional expiration
let group = CreateGroupRequest::new("My Group", None);
let group = dracoon.groups.create_group(group).await.unwrap();

§Pagination

GET endpoints are limited to 500 returned items - therefore you must paginate the content to fetch remaining items.


// This fetches the first 500 nodes without any param
 let mut nodes = dracoon.nodes.get_nodes(None, None, None).await.unwrap();

// Iterate over the remaining nodes
 for offset in (0..nodes.range.total).step_by(500) {
 let params = ListAllParams::builder()
  .with_offset(offset)
  .build();
 let next_nodes = dracoon.nodes.get_nodes(None, None, Some(params)).await.unwrap();
 
  nodes.items.extend(next_nodes.items);

};

§Cryptography support

All API calls (specifically up- and downloads) support encryption and decryption. In order to use encryption, you can pass the encryption password while building the client.

 use dco3::{Dracoon, OAuth2Flow};
 #[tokio::main]
 async fn main() {
 let dracoon = Dracoon::builder()
  .with_base_url("https://dracoon.team")
  .with_client_id("client_id")
  .with_client_secret("client_secret")
  .with_encryption_password("my secret")
  .build()
  .unwrap()
  .connect(OAuth2Flow::password_flow("username", "password"))
  .await
  .unwrap();
// keypair is now set and can be fetched without passing a secret
let kp = dracoon.get_keypair(None).await.unwrap();

It is also possible to pass the encryption secret after connecting by using the get_keypair method.

 use dco3::{Dracoon, OAuth2Flow};
 #[tokio::main]
 async fn main() {
 let dracoon = Dracoon::builder()
  .with_base_url("https://dracoon.team")
  .with_client_id("client_id")
  .with_client_secret("client_secret")
  .build()
  .unwrap()
  .connect(OAuth2Flow::password_flow("username", "password"))
  .await
  .unwrap();
// check and provide the keypair by passing the encryption secret
let secret = "my secret".to_string();
let kp = dracoon.get_keypair(Some(secret)).await.unwrap();

§Provisioning

In order to use the provisioning API to manage customers of a tenant, you can instantiate a client with the Provisioning state. All API calls are implemented in the CustomerProvisioning trait.


use dco3::{Dracoon, OAuth2Flow, CustomerProvisioning};

#[tokio::main]
async fn main() {
// the client only requires passing the base url and a provisioning token
// other API calls are *not* supported in this state.
let dracoon = Dracoon::builder()
   .with_base_url("https://dracoon.team")
   .with_provisioning_token("some_token")
   .build_provisioning()
   .unwrap();

// the client is now in the provisioning state and can be used to manage customers
let customers = dracoon.provisioning.get_customers(None).await.unwrap();

}

§Examples

For an example client implementation, see the dccmd-rs repository.

Re-exports§

Modules§

Structs§

  • DRACOON struct - implements all API calls via traits
  • Builder for the Dracoon struct. Requires a base url, client id and client secret. Optionally, a redirect uri can be provided. For convenience, use the Dracoon builder method.