fetch user profile (wip)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use crate::services::cursor::start_cursor_tracking;
|
||||
use crate::{models::app_data::AppData, services::cursor::start_cursor_tracking, state::FDOLL};
|
||||
use tauri::async_runtime;
|
||||
use tracing_subscriber;
|
||||
|
||||
@@ -6,6 +6,7 @@ static APP_HANDLE: std::sync::OnceLock<tauri::AppHandle<tauri::Wry>> = std::sync
|
||||
|
||||
mod app;
|
||||
mod models;
|
||||
mod remotes;
|
||||
mod services;
|
||||
mod state;
|
||||
mod utilities;
|
||||
@@ -44,13 +45,22 @@ fn register_app_events(event: tauri::RunEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn get_app_data() -> Result<AppData, String> {
|
||||
let guard = lock_r!(FDOLL);
|
||||
return Ok(guard.app_data.clone());
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_positioner::init())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.invoke_handler(tauri::generate_handler![start_cursor_tracking])
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
start_cursor_tracking,
|
||||
get_app_data
|
||||
])
|
||||
.setup(|app| {
|
||||
APP_HANDLE
|
||||
.set(app.handle().to_owned())
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug, TS)]
|
||||
#[ts(export)]
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct AuthConfig {
|
||||
pub audience: String,
|
||||
pub auth_url: String,
|
||||
@@ -10,8 +8,7 @@ pub struct AuthConfig {
|
||||
pub redirect_host: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug, TS)]
|
||||
#[ts(export)]
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct AppConfig {
|
||||
pub api_base_url: Option<String>,
|
||||
pub auth: AuthConfig,
|
||||
|
||||
10
src-tauri/src/models/app_data.rs
Normal file
10
src-tauri/src/models/app_data.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::remotes::user::UserProfile;
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug, TS)]
|
||||
#[ts(export)]
|
||||
pub struct AppData {
|
||||
pub user: Option<UserProfile>,
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod app_config;
|
||||
pub mod app_data;
|
||||
|
||||
1
src-tauri/src/remotes/mod.rs
Normal file
1
src-tauri/src/remotes/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod user;
|
||||
51
src-tauri/src/remotes/user.rs
Normal file
51
src-tauri/src/remotes/user.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use reqwest::{Client, Error};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::{lock_r, services::auth::with_auth, state::FDOLL};
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct UserProfile {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
pub username: String,
|
||||
pub created_at: String,
|
||||
pub last_login_at: String,
|
||||
}
|
||||
|
||||
pub struct UserRemote {
|
||||
pub base_url: String,
|
||||
pub client: Client,
|
||||
}
|
||||
|
||||
impl UserRemote {
|
||||
pub fn new() -> Self {
|
||||
let guard = lock_r!(FDOLL);
|
||||
Self {
|
||||
base_url: guard
|
||||
.app_config
|
||||
.api_base_url
|
||||
.as_ref()
|
||||
.expect("App configuration error")
|
||||
.clone(),
|
||||
client: guard
|
||||
.clients
|
||||
.as_ref()
|
||||
.expect("App configuration error")
|
||||
.http_client
|
||||
.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_user(&self, user_id: Option<&str>) -> Result<UserProfile, Error> {
|
||||
let url = format!("{}/users/{}", self.base_url, user_id.unwrap_or("me"));
|
||||
let resp = with_auth(self.client.get(url)).await.send().await?;
|
||||
let user = resp.json().await?;
|
||||
Ok(user)
|
||||
}
|
||||
|
||||
// TODO: Add other endpoints as methods
|
||||
}
|
||||
@@ -6,18 +6,21 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tauri::Emitter;
|
||||
use tracing::{error, info, warn};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::get_app_handle;
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
#[derive(Clone, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct CursorPosition {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
#[derive(Clone, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct CursorPositions {
|
||||
pub raw: CursorPosition,
|
||||
pub mapped: CursorPosition,
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
// in app-core/src/state.rs
|
||||
use crate::{
|
||||
lock_w,
|
||||
models::app_config::{AppConfig, AuthConfig},
|
||||
models::{
|
||||
app_config::{AppConfig, AuthConfig},
|
||||
app_data::AppData,
|
||||
},
|
||||
remotes::user::UserRemote,
|
||||
services::auth::{load_auth_pass, AuthPass},
|
||||
APP_HANDLE,
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::{
|
||||
env,
|
||||
sync::{Arc, LazyLock, RwLock},
|
||||
};
|
||||
use tauri::async_runtime;
|
||||
use tauri::{async_runtime, Emitter};
|
||||
use tracing::{info, warn};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
@@ -29,6 +35,9 @@ pub struct AppState {
|
||||
pub clients: Option<Clients>,
|
||||
pub auth_pass: Option<AuthPass>,
|
||||
pub oauth_flow: OAuthFlowTracker,
|
||||
|
||||
// exposed to the frontend
|
||||
pub app_data: AppData,
|
||||
}
|
||||
|
||||
// Global application state
|
||||
@@ -81,8 +90,34 @@ pub fn init_fdoll_state() {
|
||||
async_runtime::spawn(async move {
|
||||
crate::services::ws::init_ws_client().await;
|
||||
});
|
||||
|
||||
// TODO: seems like even under `has_auth` token may not be present when init app data
|
||||
async_runtime::spawn(async move {
|
||||
info!("Initializing user data");
|
||||
init_app_data().await;
|
||||
});
|
||||
}
|
||||
|
||||
info!("Initialized FDOLL state (WebSocket client initializing asynchronously)");
|
||||
info!("Initialized FDOLL state (WebSocket client & user data initializing asynchronously)");
|
||||
}
|
||||
}
|
||||
|
||||
/// To be called in init state or need to refresh data.
|
||||
/// Populate user data in app state from the server.
|
||||
pub async fn init_app_data() {
|
||||
let user_remote = UserRemote::new();
|
||||
let user = user_remote
|
||||
.get_user(None)
|
||||
.await
|
||||
.expect("TODO: handle user profile fetch failure");
|
||||
{
|
||||
let mut guard = lock_w!(FDOLL);
|
||||
guard.app_data.user = Some(user);
|
||||
APP_HANDLE
|
||||
.get()
|
||||
// TODO: magic constants
|
||||
.expect("App handle not initialized")
|
||||
.emit("app-data-refreshed", json!(guard.app_data))
|
||||
.expect("TODO: handle event emit fail");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user