mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-25 18:49:38 +00:00
sync creds now
This commit is contained in:
@@ -24,6 +24,7 @@ pub async fn main_window_thread(
|
||||
for (window_name, window) in app.windows() {
|
||||
if window_name == MAIN_WINDOW_NAME {
|
||||
let result = handle_main_window(
|
||||
&app,
|
||||
&window,
|
||||
&app_data_root,
|
||||
&storyteller_creds_manager,
|
||||
@@ -40,6 +41,7 @@ pub async fn main_window_thread(
|
||||
}
|
||||
|
||||
pub async fn handle_main_window(
|
||||
app: &AppHandle,
|
||||
window: &Window,
|
||||
app_data_root: &AppDataRoot,
|
||||
storyteller_creds_manager: &StorytellerCredentialManager,
|
||||
@@ -48,7 +50,7 @@ pub async fn handle_main_window(
|
||||
) -> AnyhowResult<()> {
|
||||
loop {
|
||||
log_errors(persist_window_resize_task(window, app_data_root, window_size_slot).await);
|
||||
//log_errors(persist_storyteller_cookies_task(window, app_data_root, storyteller_creds_manager, app_startup_time).await);
|
||||
log_errors(persist_storyteller_cookies_task(app, storyteller_creds_manager, app_startup_time).await);
|
||||
tokio::time::sleep(std::time::Duration::from_millis(1_000)).await;
|
||||
}
|
||||
}
|
||||
|
||||
+41
-46
@@ -1,18 +1,21 @@
|
||||
use crate::state::app_startup_time::AppStartupTime;
|
||||
use crate::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::state::storyteller::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use crate::threads::sora_session_login_thread::LOGIN_WINDOW_NAME;
|
||||
use anyhow::anyhow;
|
||||
use chrono::TimeDelta;
|
||||
use errors::AnyhowResult;
|
||||
use log::{debug, error, info};
|
||||
use once_cell::sync::Lazy;
|
||||
use reqwest::Url;
|
||||
use std::fs;
|
||||
use chrono::TimeDelta;
|
||||
use std::sync::LockResult;
|
||||
use storyteller_client::credentials::storyteller_avt_cookie::StorytellerAvtCookie;
|
||||
use storyteller_client::credentials::storyteller_credential_set::StorytellerCredentialSet;
|
||||
use storyteller_client::credentials::storyteller_session_cookie::StorytellerSessionCookie;
|
||||
use tauri::{AppHandle, Manager, Webview, Window};
|
||||
use crate::state::app_startup_time::AppStartupTime;
|
||||
use tauri_plugin_http::reqwest_cookie_store::CookieStore;
|
||||
use tauri_plugin_http::Http;
|
||||
|
||||
const MAIN_WEBVIEW_NAME: &str = "main";
|
||||
|
||||
@@ -29,82 +32,74 @@ const SESSION_COOKIE_NAME : &str = "session";
|
||||
const RACE_CONDITION_WAIT_TIME: TimeDelta = TimeDelta::milliseconds(5000);
|
||||
|
||||
pub async fn persist_storyteller_cookies_task(
|
||||
window: &Window,
|
||||
app_data_root: &AppDataRoot,
|
||||
app: &AppHandle,
|
||||
storyteller_credential_manager: &StorytellerCredentialManager,
|
||||
app_startup_time: &AppStartupTime,
|
||||
) -> AnyhowResult<()> {
|
||||
|
||||
if app_startup_time.time_delta_since() < RACE_CONDITION_WAIT_TIME {
|
||||
// NB: There's an issue when the "main window thread" inquires about the
|
||||
// webview cookies shortly after app startup. When it attempts to dump the
|
||||
// cookies within a few milliseconds of app launch, it deadlocks and the
|
||||
// app never launches correctly. The entire webview goes blank and the app
|
||||
// freezes. This hack seems to fix the problem.
|
||||
return Ok(())
|
||||
}
|
||||
//if app_startup_time.time_delta_since() < RACE_CONDITION_WAIT_TIME {
|
||||
// // NB: There's an issue when the "main window thread" inquires about the
|
||||
// // webview cookies shortly after app startup. When it attempts to dump the
|
||||
// // cookies within a few milliseconds of app launch, it deadlocks and the
|
||||
// // app never launches correctly. The entire webview goes blank and the app
|
||||
// // freezes. This hack seems to fix the problem.
|
||||
// return Ok(())
|
||||
//}
|
||||
|
||||
for webview in window.webviews() {
|
||||
let label = webview.label();
|
||||
if label == MAIN_WEBVIEW_NAME {
|
||||
persist_webview_cookies(&webview, app_data_root, storyteller_credential_manager).await?;
|
||||
break;
|
||||
let maybe_http = app.try_state::<Http>();
|
||||
|
||||
let http = match maybe_http {
|
||||
None => {
|
||||
error!("No HTTP plugin found");
|
||||
return Err(anyhow!("No HTTP plugin found"));
|
||||
}
|
||||
Some(http) => http,
|
||||
};
|
||||
|
||||
match http.cookies_jar.store.lock() {
|
||||
Err(err) => {
|
||||
error!("Failed to lock cookie jar: {:?}", err);
|
||||
return Err(anyhow!("Failed to lock cookie jar"));
|
||||
}
|
||||
Ok(cookie_jar) => {
|
||||
sync_tauri_credentials(&cookie_jar, storyteller_credential_manager)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn persist_webview_cookies(
|
||||
webview: &Webview,
|
||||
app_data_root: &AppDataRoot,
|
||||
fn sync_tauri_credentials(
|
||||
cookie_store: &CookieStore,
|
||||
storyteller_credential_manager: &StorytellerCredentialManager,
|
||||
) -> AnyhowResult<()> {
|
||||
let current_webview_credentials = get_storyteller_cookies(webview).await?;
|
||||
let current_http_plugin_credentials = get_credentials_from_cookie_store(cookie_store)?;
|
||||
|
||||
if current_webview_credentials.is_empty() {
|
||||
// TODO: handle logout / cookie deletion
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut replace_credentials = true;
|
||||
|
||||
let maybe_old_credentials = storyteller_credential_manager.get_credentials()?;
|
||||
|
||||
if let Some(old_credentials) = maybe_old_credentials {
|
||||
if old_credentials.equals(¤t_webview_credentials) {
|
||||
if old_credentials.equals(¤t_http_plugin_credentials) {
|
||||
replace_credentials = false;
|
||||
}
|
||||
}
|
||||
|
||||
if replace_credentials {
|
||||
info!("Writing ArtCraft credentials to disk...");
|
||||
storyteller_credential_manager.set_credentials(¤t_webview_credentials)?;
|
||||
storyteller_credential_manager.persist_all_to_disk()?;
|
||||
info!("Syncing ArtCraft credentials ...");
|
||||
storyteller_credential_manager.set_credentials(¤t_http_plugin_credentials)?;
|
||||
// NB: tauri-plugin-http stores the credentials on disk, so we can defer to that for now.
|
||||
//storyteller_credential_manager.persist_all_to_disk()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_storyteller_cookies(webview: &Webview) -> AnyhowResult<StorytellerCredentialSet> {
|
||||
debug!("Getting storyteller cookies...");
|
||||
|
||||
//// FIXME: THIS IS A TOTAL HACK. / DO NOT REMOVE.
|
||||
//// NB: If we don't call a method on the webview, the very next call to get cookies will deadlock.
|
||||
//if let Ok(url) = webview.url() {
|
||||
// debug!("For url: {:?}", url);
|
||||
//}
|
||||
|
||||
let cookies = webview.cookies_for_url(STORYTELLER_ROOT_COOKIE_URL.clone())?;
|
||||
|
||||
info!("Got storyteller cookies: {:?}", cookies);
|
||||
info!("Got storyteller cookies: {:?}", cookies.len());
|
||||
info!("Got storyteller location: {:?}", webview.url());
|
||||
|
||||
pub fn get_credentials_from_cookie_store(cookie_jar: &CookieStore) -> AnyhowResult<StorytellerCredentialSet> {
|
||||
let mut avt_cookie = None;
|
||||
let mut session_cookie = None;
|
||||
|
||||
for cookie in cookies.into_iter() {
|
||||
for cookie in cookie_jar.iter_unexpired() {
|
||||
if let Some(avt) = StorytellerAvtCookie::maybe_from_cookie(&cookie) {
|
||||
avt_cookie = Some(avt);
|
||||
} else if let Some(session) = StorytellerSessionCookie::maybe_from_cookie(&cookie) {
|
||||
|
||||
+8
-6
@@ -12,18 +12,20 @@ use tauri::{
|
||||
|
||||
pub use error::{Error, Result};
|
||||
|
||||
mod commands;
|
||||
mod error;
|
||||
// NB(bt): We're making everything public so we can access it.
|
||||
pub mod commands;
|
||||
pub mod error;
|
||||
#[cfg(feature = "cookies")]
|
||||
mod reqwest_cookie_store;
|
||||
mod scope;
|
||||
pub mod reqwest_cookie_store;
|
||||
pub mod scope;
|
||||
|
||||
#[cfg(feature = "cookies")]
|
||||
const COOKIES_FILENAME: &str = ".cookies";
|
||||
|
||||
pub(crate) struct Http {
|
||||
// NB(bt): We've vendored in this library so we can poke at the cookie data store.
|
||||
pub struct Http {
|
||||
#[cfg(feature = "cookies")]
|
||||
cookies_jar: std::sync::Arc<crate::reqwest_cookie_store::CookieStoreMutex>,
|
||||
pub cookies_jar: std::sync::Arc<crate::reqwest_cookie_store::CookieStoreMutex>,
|
||||
}
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
|
||||
@@ -9,7 +9,8 @@ use std::{
|
||||
sync::{mpsc::Receiver, Mutex},
|
||||
};
|
||||
|
||||
use cookie_store::{CookieStore, RawCookie, RawCookieParseError};
|
||||
// NB(bt): Re-export these for reuse
|
||||
pub use cookie_store::{CookieStore, RawCookie, RawCookieParseError};
|
||||
use reqwest::header::HeaderValue;
|
||||
|
||||
fn set_cookies(
|
||||
@@ -46,8 +47,9 @@ fn cookies(cookie_store: &CookieStore, url: &url::Url) -> Option<HeaderValue> {
|
||||
#[derive(Debug)]
|
||||
pub struct CookieStoreMutex {
|
||||
pub path: PathBuf,
|
||||
store: Mutex<CookieStore>,
|
||||
save_task: Mutex<Option<CancellableTask>>,
|
||||
// NB(bt): We've made both of these public so we can access them.
|
||||
pub store: Mutex<CookieStore>,
|
||||
pub save_task: Mutex<Option<CancellableTask>>,
|
||||
}
|
||||
|
||||
impl CookieStoreMutex {
|
||||
|
||||
Reference in New Issue
Block a user