Skip to content
This repository has been archived by the owner on Jul 6, 2024. It is now read-only.

Commit

Permalink
refactor: Sync and Async Code Re-use
Browse files Browse the repository at this point in the history
Attempt to abstract sync and async requests by writing an abstraction
over the flow of data that encompasses a request. The requests fill out
a `RequestData` instance which then gets used as the source of future
transformations.

The login chain is a prime example of this. We define a series of steps
that are expressed as a series of sequences which will finally produce
the expected outcome.

The Session now produces a `Sequence` implementation which needs to be
driven by a client.

Unfortunately, due to lack of Async Trait support, the async
implementation is not as efficient as it could be. Attempt was made to
test the code on nightly, but ran into this bug
rust-lang/rust#113108
  • Loading branch information
Leander Beernaert authored and LeanderBB committed Jul 9, 2023
1 parent ad71f48 commit 69c3721
Show file tree
Hide file tree
Showing 28 changed files with 1,277 additions and 924 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "proton-api-rs"
authors = ["Leander Beernaert <[email protected]>"]
version = "0.10.2"
version = "0.11.0"
edition = "2021"
license = "AGPL-3.0-only"
description = "Unofficial implemention of proton REST API in rust"
Expand Down Expand Up @@ -30,6 +30,7 @@ ureq = {version="2.6", optional=true, features=["socks-proxy", "socks"]}
default = []
http-ureq = ["dep:ureq"]
http-reqwest = ["dep:reqwest"]
async-traits =[]

[dependencies.reqwest]
version = "0.11"
Expand All @@ -40,7 +41,6 @@ optional = true
[dev-dependencies]
env_logger = "0.10"
tokio = {version ="1", features = ["full"]}
httpmock = "0.6"
go-gpa-server = {path= "go-gpa-server"}

[[example]]
Expand All @@ -53,5 +53,5 @@ required-features = ["http-ureq"]

[[test]]
name = "session"
required-features = ["http-ureq"]
required-features = ["http-ureq", "http-reqwest"]

22 changes: 12 additions & 10 deletions examples/user_id.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
use proton_api_rs::{http, ping_async};
use proton_api_rs::domain::SecretString;
use proton_api_rs::http::Sequence;
use proton_api_rs::{http, ping};
use proton_api_rs::{Session, SessionType};
pub use tokio;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt};

#[tokio::main(worker_threads = 1)]
async fn main() {
let user_email = std::env::var("PAPI_USER_EMAIL").unwrap();
let user_password = std::env::var("PAPI_USER_PASSWORD").unwrap();
let user_password = SecretString::new(std::env::var("PAPI_USER_PASSWORD").unwrap());
let app_version = std::env::var("PAPI_APP_VERSION").unwrap();

let client = http::ClientBuilder::new()
.app_version(&app_version)
.build::<http::reqwest_client::ReqwestClient>()
.unwrap();

ping_async(&client).await.unwrap();
ping().do_async(&client).await.unwrap();

let session = match Session::login_async(&client, &user_email, &user_password, None, None)
let session = match Session::login(&user_email, &user_password, None)
.do_async(&client)
.await
.unwrap()
{
SessionType::Authenticated(c) => c,

SessionType::AwaitingTotp(mut t) => {
SessionType::AwaitingTotp(t) => {
let mut stdout = tokio::io::stdout();
let mut line_reader = tokio::io::BufReader::new(tokio::io::stdin()).lines();
let session = {
Expand All @@ -41,13 +44,12 @@ async fn main() {

let totp = line.trim_end_matches('\n');

match t.submit_totp_async(&client, totp).await {
match t.submit_totp(totp).do_async(&client).await {
Ok(ac) => {
session = Some(ac);
break;
}
Err((et, e)) => {
t = et;
Err(e) => {
eprintln!("Failed to submit totp: {e}");
continue;
}
Expand All @@ -65,8 +67,8 @@ async fn main() {
}
};

let user = session.get_user_async(&client).await.unwrap();
let user = session.get_user().do_async(&client).await.unwrap();
println!("User ID is {}", user.id);

session.logout_async(&client).await.unwrap();
session.logout().do_async(&client).await.unwrap();
}
19 changes: 10 additions & 9 deletions examples/user_id_sync.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use proton_api_rs::clientv2::{ping, SessionType};
use proton_api_rs::domain::SecretString;
use proton_api_rs::http::Sequence;
use proton_api_rs::{http, Session};
use std::io::{BufRead, Write};

fn main() {
env_logger::init();

let user_email = std::env::var("PAPI_USER_EMAIL").unwrap();
let user_password = std::env::var("PAPI_USER_PASSWORD").unwrap();
let user_password = SecretString::new(std::env::var("PAPI_USER_PASSWORD").unwrap());
let app_version = std::env::var("PAPI_APP_VERSION").unwrap();

let client = http::ClientBuilder::new()
Expand All @@ -15,12 +17,12 @@ fn main() {
.build::<http::ureq_client::UReqClient>()
.unwrap();

ping(&client).unwrap();
ping().do_sync(&client).unwrap();

let login_result = Session::login(&client, &user_email, &user_password, None, None);
let login_result = Session::login(&user_email, &user_password, None).do_sync(&client);
let session = match login_result.unwrap() {
SessionType::Authenticated(s) => s,
SessionType::AwaitingTotp(mut t) => {
SessionType::AwaitingTotp(t) => {
let mut line_reader = std::io::BufReader::new(std::io::stdin());
let session = {
let mut session = None;
Expand All @@ -38,13 +40,12 @@ fn main() {

let totp = line.trim_end_matches('\n');

match t.submit_totp(&client, totp) {
match t.submit_totp(totp).do_sync(&client) {
Ok(ac) => {
session = Some(ac);
break;
}
Err((et, e)) => {
t = et;
Err(e) => {
eprintln!("Failed to submit totp: {e}");
continue;
}
Expand All @@ -62,8 +63,8 @@ fn main() {
}
};

let user = session.get_user(&client).unwrap();
let user = session.get_user().do_sync(&client).unwrap();
println!("User ID is {}", user.id);

session.logout(&client).unwrap();
session.logout().do_sync(&client).unwrap();
}
1 change: 1 addition & 0 deletions go-gpa-server/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ fn target_path_for_go_lib() -> (PathBuf, PathBuf) {
fn build_go_lib(lib_path: &Path) {
let mut command = Command::new("go");

#[cfg(any(target_os= "linux",target_os = "android"))]
command.env("CGO_LDFLAGS", "-Wl,--build-id=none");
command.arg("build");
command.arg("-ldflags=-buildid=");
Expand Down
13 changes: 13 additions & 0 deletions go-gpa-server/go/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ typedef const char cchar_t;
import "C"
import (
"sync"
"time"
"unsafe"

"github.com/ProtonMail/go-proton-api/server"
Expand Down Expand Up @@ -104,6 +105,18 @@ func gpaCreateUser(h int, cuser *C.cchar_t, cpassword *C.cchar_t, outUserID **C.
return 0
}

//export gpaSetAuthLife
func gpaSetAuthLife(h int, seconds int) int {
srv := alloc.resolve(h)
if srv == nil {
return -1
}

srv.SetAuthLife(time.Duration(seconds) * time.Second)

return 0
}

//export CStrFree
func CStrFree(ptr *C.char) {
C.free(unsafe.Pointer(ptr))
Expand Down
10 changes: 10 additions & 0 deletions go-gpa-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ impl Server {
))
}
}

pub fn set_auth_timeout(&self, duration: std::time::Duration) -> Result<()> {
unsafe {
if go::gpaSetAuthLife(self.0, duration.as_secs() as i64) < 0 {
return Err("Failed to set auth timeout".to_string());
}

Ok(())
}
}
}

impl Drop for Server {
Expand Down
1 change: 1 addition & 0 deletions go-srp/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ fn target_path_for_go_lib(platform: Platform) -> (PathBuf, PathBuf) {
fn build_go_lib(lib_path: &Path, platform: Platform) {
let mut command = Command::new("go");

#[cfg(any(target_os= "linux",target_os = "android"))]
command.env("CGO_LDFLAGS", "-Wl,--build-id=none");
match platform {
Platform::Desktop => {}
Expand Down
30 changes: 5 additions & 25 deletions src/clientv2/client.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,10 @@
use crate::http;
use crate::http::Request;
use crate::http::{Request, RequestDesc};
use crate::requests::{CaptchaRequest, Ping};

pub fn ping<T: http::ClientSync>(client: &T) -> Result<(), http::Error> {
Ping.execute_sync::<T>(client, &http::DefaultRequestFactory {})
pub fn ping() -> impl Request {
Ping.to_request()
}

pub async fn ping_async<T: http::ClientAsync>(client: &T) -> Result<(), http::Error> {
Ping.execute_async::<T>(client, &http::DefaultRequestFactory {})
.await
}

pub fn captcha_get<T: http::ClientSync>(
client: &T,
token: &str,
force_web: bool,
) -> Result<String, http::Error> {
CaptchaRequest::new(token, force_web).execute_sync(client, &http::DefaultRequestFactory {})
}

pub async fn captcha_get_async<T: http::ClientAsync>(
client: &T,
token: &str,
force_web: bool,
) -> Result<String, http::Error> {
CaptchaRequest::new(token, force_web)
.execute_async(client, &http::DefaultRequestFactory {})
.await
pub fn captcha_get(token: &str, force_web: bool) -> impl Request {
CaptchaRequest::new(token, force_web).to_request()
}
2 changes: 0 additions & 2 deletions src/clientv2/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
mod client;
mod request_repeater;
mod session;
mod totp;

pub use client::*;
pub use request_repeater::*;
pub use session::*;
pub use totp::*;
Loading

0 comments on commit 69c3721

Please sign in to comment.