feat: Endpoint for server info (#835)

* feat: provide endpoint so that client can detect server information

* feat: add server info endpoint
This commit is contained in:
Khor Shu Heng 2024-09-29 11:01:22 +08:00 committed by GitHub
parent bbe459a323
commit 47a1aae75c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 79 additions and 3 deletions

View File

@ -1,6 +1,8 @@
use crate::notify::{ClientToken, TokenStateReceiver}; use crate::notify::{ClientToken, TokenStateReceiver};
use app_error::AppError; use app_error::AppError;
use app_error::ErrorCode;
use client_api_entity::auth_dto::DeleteUserQuery; use client_api_entity::auth_dto::DeleteUserQuery;
use client_api_entity::server_info_dto::ServerInfoResponseItem;
use client_api_entity::workspace_dto::FolderView; use client_api_entity::workspace_dto::FolderView;
use client_api_entity::workspace_dto::QueryWorkspaceFolder; use client_api_entity::workspace_dto::QueryWorkspaceFolder;
use client_api_entity::workspace_dto::QueryWorkspaceParam; use client_api_entity::workspace_dto::QueryWorkspaceParam;
@ -11,6 +13,7 @@ use gotrue::grant::PasswordGrant;
use gotrue::grant::{Grant, RefreshTokenGrant}; use gotrue::grant::{Grant, RefreshTokenGrant};
use gotrue::params::MagicLinkParams; use gotrue::params::MagicLinkParams;
use gotrue::params::{AdminUserParams, GenerateLinkParams}; use gotrue::params::{AdminUserParams, GenerateLinkParams};
use reqwest::StatusCode;
use shared_entity::dto::workspace_dto::{CreateWorkspaceParam, PatchWorkspaceParam}; use shared_entity::dto::workspace_dto::{CreateWorkspaceParam, PatchWorkspaceParam};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
#[cfg(feature = "enable_brotli")] #[cfg(feature = "enable_brotli")]
@ -967,6 +970,26 @@ impl Client {
.into_data() .into_data()
} }
#[instrument(level = "info", skip_all)]
pub async fn get_server_info(&self) -> Result<ServerInfoResponseItem, AppResponseError> {
let url = format!("{}/api/server", self.base_url);
let resp = self
.http_client_with_auth(Method::GET, &url)
.await?
.send()
.await?;
if resp.status() == StatusCode::NOT_FOUND {
Err(AppResponseError::new(
ErrorCode::Unhandled,
"server info not implemented",
))
} else {
AppResponse::<ServerInfoResponseItem>::from_response(resp)
.await?
.into_data()
}
}
// Refresh token if given timestamp is close to the token expiration time // Refresh token if given timestamp is close to the token expiration time
pub async fn refresh_if_expired(&self, ts: i64, reason: &str) -> Result<(), AppResponseError> { pub async fn refresh_if_expired(&self, ts: i64, reason: &str) -> Result<(), AppResponseError> {
let expires_at = self.token_expires_at()?; let expires_at = self.token_expires_at()?;

View File

@ -20,11 +20,18 @@ database-entity.workspace = true
collab-entity = { workspace = true } collab-entity = { workspace = true }
app-error = { workspace = true } app-error = { workspace = true }
chrono = "0.4.31" chrono = "0.4.31"
appflowy-ai-client = { workspace = true, default-features = false, features = ["dto"] } appflowy-ai-client = { workspace = true, default-features = false, features = [
"dto",
] }
pin-project = "1.1.5" pin-project = "1.1.5"
actix-web = { version = "4.4.1", default-features = false, features = ["http2"], optional = true } actix-web = { version = "4.4.1", default-features = false, features = [
validator = { version = "0.16", features = ["validator_derive", "derive"], optional = true } "http2",
], optional = true }
validator = { version = "0.16", features = [
"validator_derive",
"derive",
], optional = true }
futures = "0.3.30" futures = "0.3.30"
bytes = "1.6.0" bytes = "1.6.0"
log = "0.4.21" log = "0.4.21"

View File

@ -5,4 +5,5 @@ pub mod billing_dto;
pub mod history_dto; pub mod history_dto;
pub mod publish_dto; pub mod publish_dto;
pub mod search_dto; pub mod search_dto;
pub mod server_info_dto;
pub mod workspace_dto; pub mod workspace_dto;

View File

@ -0,0 +1,13 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum SupportedClientFeatures {
// Supports Collab Params serialization using Protobuf
CollabParamsProtobuf,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ServerInfoResponseItem {
pub supported_client_features: Vec<SupportedClientFeatures>,
pub minimum_supported_client_version: Option<String>,
}

View File

@ -6,6 +6,7 @@ pub mod access_request;
pub mod history; pub mod history;
pub mod metrics; pub mod metrics;
pub mod search; pub mod search;
pub mod server_info;
pub mod template; pub mod template;
pub mod user; pub mod user;
pub mod util; pub mod util;

18
src/api/server_info.rs Normal file
View File

@ -0,0 +1,18 @@
use actix_web::{web, Scope};
use shared_entity::dto::server_info_dto::ServerInfoResponseItem;
use shared_entity::response::{AppResponse, JsonAppResponse};
pub fn server_info_scope() -> Scope {
web::scope("/api/server").service(web::resource("").route(web::get().to(server_info_handler)))
}
async fn server_info_handler() -> actix_web::Result<JsonAppResponse<ServerInfoResponseItem>> {
Ok(
AppResponse::Ok()
.with_data(ServerInfoResponseItem {
supported_client_features: vec![],
minimum_supported_client_version: None,
})
.into(),
)
}

View File

@ -49,6 +49,7 @@ use crate::api::file_storage::file_storage_scope;
use crate::api::history::history_scope; use crate::api::history::history_scope;
use crate::api::metrics::metrics_scope; use crate::api::metrics::metrics_scope;
use crate::api::search::search_scope; use crate::api::search::search_scope;
use crate::api::server_info::server_info_scope;
use crate::api::template::template_scope; use crate::api::template::template_scope;
use crate::api::user::user_scope; use crate::api::user::user_scope;
use crate::api::workspace::{collab_scope, workspace_scope}; use crate::api::workspace::{collab_scope, workspace_scope};
@ -159,6 +160,7 @@ pub async fn run_actix_server(
// .wrap(DecryptPayloadMiddleware) // .wrap(DecryptPayloadMiddleware)
.wrap(access_control.clone()) .wrap(access_control.clone())
.wrap(RequestIdMiddleware) .wrap(RequestIdMiddleware)
.service(server_info_scope())
.service(user_scope()) .service(user_scope())
.service(workspace_scope()) .service(workspace_scope())
.service(collab_scope()) .service(collab_scope())

View File

@ -4,6 +4,7 @@ mod collab_history;
mod file_test; mod file_test;
mod gotrue; mod gotrue;
mod search; mod search;
mod server_info;
mod sql_test; mod sql_test;
mod user; mod user;
mod websocket; mod websocket;

View File

@ -0,0 +1,9 @@
use client_api_test::generate_unique_registered_user_client;
#[tokio::test]
async fn test_get_server_info() {
let (c, _) = generate_unique_registered_user_client().await;
c.get_server_info()
.await
.expect("Failed to get server info");
}

1
tests/server_info/mod.rs Normal file
View File

@ -0,0 +1 @@
mod info;