Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor libiam #78

Merged
merged 1 commit into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions libiam/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ tokio = { version = "1.25.0", features = ["rt"] }
futures = "0.3.26"
async-trait = "0.1.64"
jsonwebtoken = "9.1.0"
anyhow = "1.0.86"
22 changes: 22 additions & 0 deletions libiam/src/api/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use super::Api;
use anyhow::Result;
use reqwest::Method;
use serde::{Deserialize, Serialize};

pub mod login {
use super::*;

#[derive(Debug, Serialize)]
pub struct Request<'a> {
pub token: &'a str,
}

#[derive(Debug, Deserialize)]
pub struct Response {
pub token: String,
}
}

pub async fn login(api: &Api, req: &login::Request<'_>) -> Result<login::Response> {
api.request(Method::POST, "/v1/apps/login", Some(req)).await
}
86 changes: 86 additions & 0 deletions libiam/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
pub mod app;
pub mod user;

use reqwest::{header::AUTHORIZATION, Client, Method, Url};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use thiserror::Error;
use tokio::runtime::Handle;

#[derive(Debug)]
pub struct Api {
client: Client,
base: Url,
handle: Handle,
token: Option<String>,
}

impl Api {
pub fn new(base: &str, token: Option<String>) -> anyhow::Result<Self> {
Ok(Self {
client: Client::new(),
base: Url::parse(base)?,
handle: Handle::current(),
token,
})
}

pub fn with_token(&self, token: String) -> Self {
Self {
client: self.client.clone(),
base: self.base.clone(),
handle: self.handle.clone(),
token: Some(token),
}
}

#[inline]
async fn request<Req, Res>(
&self,
method: Method,
path: &str,
req: Option<&Req>,
) -> anyhow::Result<Res>
where
Req: Serialize,
Res: DeserializeOwned + Send + 'static,
{
let mut r = self.client.request(method, self.base.join(path).unwrap());

if let Some(token) = &self.token {
r = r.header(AUTHORIZATION, &format!("Bearer {}", token));
}

if let Some(req) = req {
r = r.json(req)
}

self.handle
.spawn(async move {
let res: ErrorOr<Res> = r.send().await?.json().await?;

match res {
ErrorOr::Error(error) => {
tracing::error!("iam error: {error:?}");
Err(error.into())
}
ErrorOr::Data(res) => anyhow::Ok(res),
}
})
.await
.unwrap()
}
}

#[derive(Debug, Deserialize, Error)]
#[error("{error}")]
pub struct Error {
pub code: String,
pub error: String,
}

#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum ErrorOr<T> {
Error(Error),
Data(T),
}
56 changes: 56 additions & 0 deletions libiam/src/api/user.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use super::Api;
use anyhow::Result;
use reqwest::Method;
use serde::{Deserialize, Serialize};

pub mod register {
use super::*;

#[derive(Debug, Serialize)]
pub struct Request<'a> {
pub name: &'a str,
pub email: &'a str,
pub password: &'a str,
}

#[derive(Debug, Deserialize)]
pub struct Response {
pub id: String,
}
}

pub async fn register(api: &Api, req: &register::Request<'_>) -> Result<register::Response> {
api.request(Method::POST, "/v1/users/register", Some(req))
.await
}

pub mod login {
use super::*;

#[derive(Debug, Serialize)]
pub struct Request<'a> {
pub email: &'a str,
pub password: &'a str,
}

#[derive(Debug, Deserialize)]
pub struct Response {
pub token: String,
}
}

pub async fn login(api: &Api, req: &login::Request<'_>) -> Result<login::Response> {
api.request(Method::POST, "/v1/users/login", Some(req))
.await
}

pub mod get_user {
use iam_common::user::UserInfo;

pub type Response = UserInfo;
}

pub async fn get_user(api: &Api, id: &str) -> Result<get_user::Response> {
api.request(Method::GET, &format!("/v1/users/{id}"), None::<&()>)
.await
}
59 changes: 11 additions & 48 deletions libiam/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
use std::sync::Arc;

use iam_common::user::UserInfo;
use reqwest::Client;
use serde::Deserialize;
use serde_json::json;

use crate::{
error::{unwrap_res, ErrorMessage, Result},
utils::{create_client, Either},
api::{self, Api},
Iam,
};
use iam_common::user::UserInfo;
use std::sync::Arc;

#[derive(Debug)]
pub struct AppInner {
secret: String,
token: String,
iam: Iam,
client: Client,
api: Api,
}

#[derive(Debug, Clone)]
Expand All @@ -25,41 +18,20 @@ pub struct App {
}

impl App {
pub async fn login(iam: &Iam, secret: &str) -> Result<Self> {
#[derive(Debug, Deserialize)]
struct Response {
token: String,
}

tracing::debug!(secret, "app logging into iam");

let res = Client::new()
.post(iam.get_url("/v1/apps/login"))
.json(&json!({
"token": secret,
}))
.send()
pub async fn login(iam: &Iam, secret: &str) -> anyhow::Result<Self> {
let token = api::app::login(&iam.inner.api, &api::app::login::Request { token: secret })
.await?
.json::<Either<Response, ErrorMessage>>()
.await?;

let res = unwrap_res(res)?;
.token;

Ok(Self {
inner: Arc::new(AppInner {
secret: secret.to_owned(),
client: create_client(&res.token),
token: res.token,
iam: iam.clone(),
token: token.clone(),
api: iam.inner.api.with_token(token),
}),
})
}

#[inline]
fn client(&self) -> &Client {
&self.inner.client
}

pub fn token(&self) -> &str {
&self.inner.token
}
Expand All @@ -69,17 +41,8 @@ impl App {
id
}

pub async fn get_user_info(&self, id: &str) -> Result<UserInfo> {
let res = self
.client()
.get(self.inner.iam.get_url(&format!("/v1/users/{}/", id)))
.send()
.await?
.json::<Either<UserInfo, ErrorMessage>>()
.await?;

let res = unwrap_res(res)?;

pub async fn get_user_info(&self, id: &str) -> anyhow::Result<UserInfo> {
let res = api::user::get_user(&self.inner.api, id).await?;
Ok(res)
}
}
30 changes: 0 additions & 30 deletions libiam/src/error.rs

This file was deleted.

12 changes: 6 additions & 6 deletions libiam/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
pub mod api;
mod app;
mod error;
pub mod testing;
mod user;
mod utils;

use api::Api;
use std::sync::Arc;

pub use app::App;
Expand All @@ -12,7 +12,7 @@ pub use user::User;

#[derive(Debug)]
pub struct IamInner {
base_url: String,
api: Api,
}

#[derive(Debug, Clone)]
Expand All @@ -24,12 +24,12 @@ impl Iam {
pub fn new(base_url: &str) -> Self {
Self {
inner: Arc::new(IamInner {
base_url: base_url.to_owned(),
api: Api::new(base_url, None).unwrap(),
}),
}
}

pub(crate) fn get_url(&self, path: &str) -> String {
format!("{}{}", self.inner.base_url, path)
pub fn api(&self) -> &Api {
&self.inner.api
}
}
Loading
Loading