fix: fix some bugs (#145)
* chore: update * chore: pub error code * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update max frame size * chore: update max frame size * chore: ws buffer size * chore: update
This commit is contained in:
parent
9c911a3a94
commit
937e3bd9b2
|
|
@ -545,6 +545,7 @@ dependencies = [
|
||||||
"token",
|
"token",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
|
"tokio-tungstenite",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-actix-web",
|
"tracing-actix-web",
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ scraper = "0.17.1"
|
||||||
client-api = { path = "libs/client-api", features = ["collab-sync"] }
|
client-api = { path = "libs/client-api", features = ["collab-sync"] }
|
||||||
opener = "0.6.1"
|
opener = "0.6.1"
|
||||||
image = "0.23.14"
|
image = "0.23.14"
|
||||||
|
tokio-tungstenite = { version = "0.20.1", features = ["native-tls"] }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "appflowy_cloud"
|
name = "appflowy_cloud"
|
||||||
|
|
|
||||||
|
|
@ -218,16 +218,16 @@ impl ErrorCode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct AFErrorSerde {
|
struct AppErrorSerde {
|
||||||
code: ErrorCode,
|
code: ErrorCode,
|
||||||
msg: String,
|
message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&AppError> for AFErrorSerde {
|
impl From<&AppError> for AppErrorSerde {
|
||||||
fn from(value: &AppError) -> Self {
|
fn from(value: &AppError) -> Self {
|
||||||
Self {
|
Self {
|
||||||
code: value.code(),
|
code: value.code(),
|
||||||
msg: value.to_string(),
|
message: value.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -239,6 +239,6 @@ impl actix_web::error::ResponseError for AppError {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_response(&self) -> actix_web::HttpResponse {
|
fn error_response(&self) -> actix_web::HttpResponse {
|
||||||
actix_web::HttpResponse::Ok().json(AFErrorSerde::from(self))
|
actix_web::HttpResponse::Ok().json(AppErrorSerde::from(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use realtime_entity::collab_msg::{CollabSinkMessage, MsgId};
|
||||||
use tokio::spawn;
|
use tokio::spawn;
|
||||||
use tokio::sync::{mpsc, oneshot, watch, Mutex};
|
use tokio::sync::{mpsc, oneshot, watch, Mutex};
|
||||||
use tokio::time::{interval, Instant, Interval};
|
use tokio::time::{interval, Instant, Interval};
|
||||||
use tracing::{debug, error, trace, warn};
|
use tracing::{debug, error, event, trace, warn};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum SinkState {
|
pub enum SinkState {
|
||||||
|
|
@ -251,6 +251,12 @@ where
|
||||||
while let Some(pending_msg) = pending_msg_queue.pop() {
|
while let Some(pending_msg) = pending_msg_queue.pop() {
|
||||||
if !sending_msg.merge(pending_msg, &self.config.maximum_payload_size) {
|
if !sending_msg.merge(pending_msg, &self.config.maximum_payload_size) {
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
event!(
|
||||||
|
tracing::Level::TRACE,
|
||||||
|
"Did merge message: {}",
|
||||||
|
sending_msg.get_msg()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,9 +79,9 @@ impl Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip_all, err)]
|
#[instrument(level = "debug", skip_all, err)]
|
||||||
pub fn restore_token(&self, token: &str) -> Result<(), AppError> {
|
pub fn restore_token(&self, token: &str) -> Result<(), AppResponseError> {
|
||||||
if token.is_empty() {
|
if token.is_empty() {
|
||||||
return Err(AppError::OAuthError("Empty token".to_string()));
|
return Err(AppError::OAuthError("Empty token".to_string()).into());
|
||||||
}
|
}
|
||||||
let token = serde_json::from_str::<AccessTokenResponse>(token)?;
|
let token = serde_json::from_str::<AccessTokenResponse>(token)?;
|
||||||
self.token.write().set(token);
|
self.token.write().set(token);
|
||||||
|
|
@ -95,12 +95,12 @@ impl Client {
|
||||||
/// string representation of the access token. If the lock cannot be acquired or
|
/// string representation of the access token. If the lock cannot be acquired or
|
||||||
/// the token is not present, an error is returned.
|
/// the token is not present, an error is returned.
|
||||||
#[instrument(level = "debug", skip_all, err)]
|
#[instrument(level = "debug", skip_all, err)]
|
||||||
pub fn get_token(&self) -> Result<String, AppError> {
|
pub fn get_token(&self) -> Result<String, AppResponseError> {
|
||||||
let token_str = self
|
let token_str = self
|
||||||
.token
|
.token
|
||||||
.read()
|
.read()
|
||||||
.try_get()
|
.try_get()
|
||||||
.map_err(|err| AppError::OAuthError(err.to_string()))?;
|
.map_err(|err| AppResponseError::from(AppError::OAuthError(err.to_string())))?;
|
||||||
Ok(token_str)
|
Ok(token_str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,7 +174,7 @@ impl Client {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// - `Ok(String)`: A `String` containing the constructed authorization URL if the specified provider is available.
|
/// - `Ok(String)`: A `String` containing the constructed authorization URL if the specified provider is available.
|
||||||
/// - `Err(AppError)`: An `AppError` indicating either the OAuth provider is invalid or other issues occurred while fetching settings.
|
/// - `Err(AppResponseError)`: An `AppResponseError` indicating either the OAuth provider is invalid or other issues occurred while fetching settings.
|
||||||
///
|
///
|
||||||
#[instrument(level = "debug", skip_all, err)]
|
#[instrument(level = "debug", skip_all, err)]
|
||||||
pub async fn generate_oauth_url_with_provider(
|
pub async fn generate_oauth_url_with_provider(
|
||||||
|
|
@ -340,13 +340,15 @@ impl Client {
|
||||||
/// - `Err(AppError)`: An `AppError` indicating either an inability to read the token or that the user is not logged in.
|
/// - `Err(AppError)`: An `AppError` indicating either an inability to read the token or that the user is not logged in.
|
||||||
///
|
///
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn token_expires_at(&self) -> Result<i64, AppError> {
|
pub fn token_expires_at(&self) -> Result<i64, AppResponseError> {
|
||||||
match &self.token.try_read() {
|
match &self.token.try_read() {
|
||||||
None => Err(AppError::Unhandled("Failed to read token".to_string())),
|
None => Err(AppError::Unhandled("Failed to read token".to_string()).into()),
|
||||||
Some(token) => Ok(
|
Some(token) => Ok(
|
||||||
token
|
token
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(AppError::NotLoggedIn("fail to get expires_at".to_string()))?
|
.ok_or(AppResponseError::from(AppError::NotLoggedIn(
|
||||||
|
"fail to get expires_at".to_string(),
|
||||||
|
)))?
|
||||||
.expires_at,
|
.expires_at,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
@ -358,17 +360,17 @@ impl Client {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// - `Ok(String)`: A `String` containing the access token.
|
/// - `Ok(String)`: A `String` containing the access token.
|
||||||
/// - `Err(AppError)`: An `AppError` indicating either an inability to read the token or that the user is not logged in.
|
/// - `Err(AppResponseError)`: An `AppResponseError` indicating either an inability to read the token or that the user is not logged in.
|
||||||
///
|
///
|
||||||
pub fn access_token(&self) -> Result<String, AppError> {
|
pub fn access_token(&self) -> Result<String, AppResponseError> {
|
||||||
match &self.token.try_read_for(Duration::from_secs(2)) {
|
match &self.token.try_read_for(Duration::from_secs(2)) {
|
||||||
None => Err(AppError::Unhandled("Failed to read token".to_string())),
|
None => Err(AppError::Unhandled("Failed to read token".to_string()).into()),
|
||||||
Some(token) => Ok(
|
Some(token) => Ok(
|
||||||
token
|
token
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(AppError::NotLoggedIn(
|
.ok_or(AppResponseError::from(AppError::NotLoggedIn(
|
||||||
"fail to get access token. Token is empty".to_string(),
|
"fail to get access token. Token is empty".to_string(),
|
||||||
))?
|
)))?
|
||||||
.access_token
|
.access_token
|
||||||
.clone(),
|
.clone(),
|
||||||
),
|
),
|
||||||
|
|
@ -562,7 +564,6 @@ impl Client {
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
event!(tracing::Level::ERROR, "refresh token failed: {}", err);
|
event!(tracing::Level::ERROR, "refresh token failed: {}", err);
|
||||||
self.token.write().unset();
|
|
||||||
Err(AppResponseError::from(err))
|
Err(AppResponseError::from(err))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ pub use http::*;
|
||||||
|
|
||||||
pub mod error {
|
pub mod error {
|
||||||
pub use shared_entity::response::AppResponseError;
|
pub use shared_entity::response::AppResponseError;
|
||||||
|
pub use shared_entity::response::ErrorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export all dto entities that will be used in the frontend application
|
// Export all dto entities that will be used in the frontend application
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,15 @@ impl WSClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send<M: Into<Message>>(&self, msg: M) -> Result<(), WSError> {
|
||||||
|
self.sender.send(msg.into()).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sender(&self) -> Sender<Message> {
|
||||||
|
self.sender.clone()
|
||||||
|
}
|
||||||
|
|
||||||
async fn set_state(&self, state: ConnectState) {
|
async fn set_state(&self, state: ConnectState) {
|
||||||
self.state_notify.lock().set_state(state);
|
self.state_notify.lock().set_state(state);
|
||||||
}
|
}
|
||||||
|
|
@ -246,7 +255,7 @@ struct RetryCondition {
|
||||||
impl Condition<WSError> for RetryCondition {
|
impl Condition<WSError> for RetryCondition {
|
||||||
fn should_retry(&mut self, error: &WSError) -> bool {
|
fn should_retry(&mut self, error: &WSError) -> bool {
|
||||||
if let WSError::AuthError(err) = error {
|
if let WSError::AuthError(err) = error {
|
||||||
debug!("WSClient auth error: {}, stop retry connn", err);
|
debug!("WSClient auth error: {}, stop retry connect", err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ use std::pin::Pin;
|
||||||
use crate::ws::WSError;
|
use crate::ws::WSError;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio_retry::Action;
|
use tokio_retry::Action;
|
||||||
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
|
use tokio_tungstenite::tungstenite::protocol::WebSocketConfig;
|
||||||
|
use tokio_tungstenite::{connect_async_with_config, MaybeTlsStream, WebSocketStream};
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
pub(crate) struct ConnectAction {
|
pub(crate) struct ConnectAction {
|
||||||
|
|
@ -26,7 +27,17 @@ impl Action for ConnectAction {
|
||||||
let cloned_addr = self.addr.clone();
|
let cloned_addr = self.addr.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
info!("🔵websocket start connecting: {}", cloned_addr);
|
info!("🔵websocket start connecting: {}", cloned_addr);
|
||||||
match connect_async(&cloned_addr).await {
|
match connect_async_with_config(
|
||||||
|
&cloned_addr,
|
||||||
|
Some(WebSocketConfig {
|
||||||
|
max_message_size: Some(65_536), // 64KB
|
||||||
|
max_frame_size: Some(65_536), // 64KB
|
||||||
|
..WebSocketConfig::default()
|
||||||
|
}),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok((stream, _response)) => {
|
Ok((stream, _response)) => {
|
||||||
info!("🟢websocket connect success");
|
info!("🟢websocket connect success");
|
||||||
Ok(stream)
|
Ok(stream)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use app_error::{AppError, ErrorCode};
|
use app_error::AppError;
|
||||||
|
pub use app_error::ErrorCode;
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
#[cfg(feature = "cloud")]
|
#[cfg(feature = "cloud")]
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ pub async fn establish_ws_connection(
|
||||||
);
|
);
|
||||||
|
|
||||||
match ws::WsResponseBuilder::new(client, &request, payload)
|
match ws::WsResponseBuilder::new(client, &request, payload)
|
||||||
.frame_size(MAX_FRAME_SIZE)
|
.frame_size(MAX_FRAME_SIZE * 10)
|
||||||
.start()
|
.start()
|
||||||
{
|
{
|
||||||
Ok(response) => Ok(response),
|
Ok(response) => Ok(response),
|
||||||
|
|
|
||||||
|
|
@ -282,7 +282,7 @@ where
|
||||||
oid: &str,
|
oid: &str,
|
||||||
user_uuid: &Uuid,
|
user_uuid: &Uuid,
|
||||||
method: Method,
|
method: Method,
|
||||||
_path: Path<Url>,
|
_path: &Path<Url>,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
let can_access = self
|
let can_access = self
|
||||||
.0
|
.0
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ pub trait HttpAccessControlService: Send + Sync {
|
||||||
oid: &str,
|
oid: &str,
|
||||||
user_uuid: &Uuid,
|
user_uuid: &Uuid,
|
||||||
method: Method,
|
method: Method,
|
||||||
path: Path<Url>,
|
path: &Path<Url>,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +82,7 @@ where
|
||||||
oid: &str,
|
oid: &str,
|
||||||
user_uuid: &Uuid,
|
user_uuid: &Uuid,
|
||||||
method: Method,
|
method: Method,
|
||||||
path: Path<Url>,
|
path: &Path<Url>,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
self
|
self
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
@ -211,7 +211,11 @@ where
|
||||||
.check_workspace_permission(&workspace_id, &user_uuid, method.clone())
|
.check_workspace_permission(&workspace_id, &user_uuid, method.clone())
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
error!("workspace access control: {:?}", err);
|
error!(
|
||||||
|
"workspace access control: {}, with path:{}",
|
||||||
|
err,
|
||||||
|
path.as_str()
|
||||||
|
);
|
||||||
return Err(Error::from(err));
|
return Err(Error::from(err));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -221,10 +225,14 @@ where
|
||||||
if let Some(collab_object_id) = collab_object_id {
|
if let Some(collab_object_id) = collab_object_id {
|
||||||
if let Some(acs) = services.get(&AccessResource::Collab) {
|
if let Some(acs) = services.get(&AccessResource::Collab) {
|
||||||
if let Err(err) = acs
|
if let Err(err) = acs
|
||||||
.check_collab_permission(&collab_object_id, &user_uuid, method, path)
|
.check_collab_permission(&collab_object_id, &user_uuid, method, &path)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
error!("collab access control: {:?}", err);
|
error!(
|
||||||
|
"collab access control: {:?}, with path:{}",
|
||||||
|
err,
|
||||||
|
path.as_str()
|
||||||
|
);
|
||||||
return Err(Error::from(err));
|
return Err(Error::from(err));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use client_api::ws::{ConnectState, WSClient, WSClientConfig};
|
|
||||||
|
|
||||||
use crate::user::utils::generate_unique_registered_user_client;
|
use crate::user::utils::generate_unique_registered_user_client;
|
||||||
|
use client_api::ws::{ConnectState, WSClient, WSClientConfig};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn realtime_connect_test() {
|
async fn realtime_connect_test() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue