Skip to content

Commit

Permalink
fix: token refresh on local (#4650)
Browse files Browse the repository at this point in the history
* fix: refresh user token on local

* chore: add test
  • Loading branch information
appflowy committed Feb 14, 2024
1 parent b356927 commit e81a2ff
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 43 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Release Notes
## Version 0.4.7 - 02/08/2024
## Version 0.4.8 - 02/13/2024
### Bug Fixes
- Fixed a possible error when loading workspaces

Expand Down
2 changes: 1 addition & 1 deletion frontend/Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
CARGO_MAKE_CRATE_NAME = "dart-ffi"
LIB_NAME = "dart_ffi"
APPFLOWY_VERSION = "0.4.7"
APPFLOWY_VERSION = "0.4.8"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
PRODUCT_NAME = "AppFlowy"
MACOSX_DEPLOYMENT_TARGET = "11.0"
Expand Down
2 changes: 1 addition & 1 deletion frontend/appflowy_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.4.7
version: 0.4.8

environment:
flutter: ">=3.18.0-0.2.pre"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use crate::util::unzip_history_user_db;
use event_integration::user_event::user_localhost_af_cloud;
use event_integration::EventIntegrationTest;
use flowy_core::DEFAULT_NAME;
use std::time::Duration;

#[tokio::test]
async fn import_appflowy_data_folder_into_new_view_test() {
let import_container_name = "040_local".to_string();
let (cleaner, user_db_path) =
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
let (imported_af_folder_cleaner, imported_af_data_path) =
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();

user_localhost_af_cloud().await;
let test =
EventIntegrationTest::new_with_user_data_path(user_db_path.clone(), DEFAULT_NAME.to_string())
.await;
// In the 040_local, the structure is:
// workspace:
// view: Document1
// view: Document2
// view: Grid1
// view: Grid2
// Sleep for 2 seconds to wait for the initial workspace to be created
tokio::time::sleep(Duration::from_secs(5)).await;

test
.import_appflowy_data(
imported_af_data_path.to_str().unwrap().to_string(),
Some(import_container_name.clone()),
)
.await
.unwrap();

// after import, the structure is:
// workspace:
// view: Getting Started
// view: 040_local
// view: Document1
// view: Document2
// view: Grid1
// view: Grid2
let views = test.get_all_workspace_views().await;
assert_eq!(views.len(), 2);
assert_eq!(views[1].name, import_container_name);

drop(cleaner);
drop(imported_af_folder_cleaner);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod auth_test;
mod helper;
mod import_af_data_local_test;
mod user_awareness_test;
mod user_profile_test;
112 changes: 72 additions & 40 deletions frontend/rust-lib/flowy-user/src/user_manager/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::{Arc, Weak};
use tokio::sync::{Mutex, RwLock};
use tokio_stream::StreamExt;
use tracing::{debug, error, event, info, instrument};
use tracing::{debug, error, event, info, instrument, warn};

use lib_dispatch::prelude::af_spawn;
use lib_infra::box_any::BoxAny;
Expand Down Expand Up @@ -152,56 +152,88 @@ impl UserManager {
user.email
);

self.prepare_user(&session).await;
self.prepare_backup(&session).await;

// Set the token if the current cloud service using token to authenticate
// Currently, only the AppFlowy cloud using token to init the client api.
if let Err(err) = self.cloud_services.set_token(&user.token) {
error!("Set token failed: {}", err);
}
// TODO(nathan): using trait to separate the init process for different cloud service
if user.authenticator.is_appflowy_cloud() {
if let Err(err) = self.cloud_services.set_token(&user.token) {
error!("Set token failed: {}", err);
}

// Subscribe the token state
let weak_cloud_services = Arc::downgrade(&self.cloud_services);
let weak_authenticate_user = Arc::downgrade(&self.authenticate_user);
let weak_pool = Arc::downgrade(&self.db_pool(user.uid)?);
let cloned_session = session.clone();
if let Some(mut token_state_rx) = self.cloud_services.subscribe_token_state() {
event!(tracing::Level::DEBUG, "Listen token state change");
let user_uid = user.uid;
let local_token = user.token.clone();
af_spawn(async move {
while let Some(token_state) = token_state_rx.next().await {
debug!("Token state changed: {:?}", token_state);
match token_state {
UserTokenState::Refresh { token: new_token } => {
// Only save the token if the token is different from the current token
if new_token != local_token {
if let Some(conn) = weak_pool.upgrade().and_then(|pool| pool.get().ok()) {
// Save the new token
if let Err(err) = save_user_token(user_uid, conn, new_token) {
error!("Save user token failed: {}", err);
// Subscribe the token state
let weak_cloud_services = Arc::downgrade(&self.cloud_services);
let weak_authenticate_user = Arc::downgrade(&self.authenticate_user);
let weak_pool = Arc::downgrade(&self.db_pool(user.uid)?);
let cloned_session = session.clone();
if let Some(mut token_state_rx) = self.cloud_services.subscribe_token_state() {
event!(tracing::Level::DEBUG, "Listen token state change");
let user_uid = user.uid;
let local_token = user.token.clone();
af_spawn(async move {
while let Some(token_state) = token_state_rx.next().await {
debug!("Token state changed: {:?}", token_state);
match token_state {
UserTokenState::Refresh { token: new_token } => {
// Only save the token if the token is different from the current token
if new_token != local_token {
if let Some(conn) = weak_pool.upgrade().and_then(|pool| pool.get().ok()) {
// Save the new token
if let Err(err) = save_user_token(user_uid, conn, new_token) {
error!("Save user token failed: {}", err);
}
}
}
}
},
UserTokenState::Invalid => {
// Force user to sign out when the token is invalid
if let (Some(cloud_services), Some(authenticate_user), Some(conn)) = (
weak_cloud_services.upgrade(),
weak_authenticate_user.upgrade(),
weak_pool.upgrade().and_then(|pool| pool.get().ok()),
) {
},
UserTokenState::Invalid => {
// Attempt to upgrade the weak reference for cloud_services
let cloud_services = match weak_cloud_services.upgrade() {
Some(cloud_services) => cloud_services,
None => {
error!("Failed to upgrade weak reference for cloud_services");
return; // Exit early if the upgrade fails
},
};

// Attempt to upgrade the weak reference for authenticate_user
let authenticate_user = match weak_authenticate_user.upgrade() {
Some(authenticate_user) => authenticate_user,
None => {
warn!("Failed to upgrade weak reference for authenticate_user");
return; // Exit early if the upgrade fails
},
};

// Attempt to upgrade the weak reference for pool and then get a connection
let conn = match weak_pool.upgrade() {
Some(pool) => match pool.get() {
Ok(conn) => conn,
Err(_) => {
warn!("Failed to get connection from pool");
return; // Exit early if getting connection fails
},
},
None => {
warn!("Failed to upgrade weak reference for pool");
return; // Exit early if the upgrade fails
},
};

// If all upgrades succeed, proceed with the sign_out operation
if let Err(err) =
sign_out(&cloud_services, &cloned_session, &authenticate_user, conn).await
{
error!("Sign out when token invalid failed: {:?}", err);
}
}
},
// Force user to sign out when the token is invalid
},
}
}
}
});
});
}
}
self.prepare_user(&session).await;
self.prepare_backup(&session).await;

// Do the user data migration if needed
event!(tracing::Level::INFO, "Prepare user data migration");
Expand Down Expand Up @@ -270,7 +302,7 @@ impl UserManager {
///
/// A sign-in notification is also sent after a successful sign-in.
///
#[tracing::instrument(level = "debug", skip(self, params))]
#[tracing::instrument(level = "info", skip(self, params))]
pub async fn sign_in(
&self,
params: SignInParams,
Expand Down

0 comments on commit e81a2ff

Please sign in to comment.