chore: move client folders (#948)
@@ -0,0 +1,4 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
[package]
|
||||
name = "AFFiNE"
|
||||
version = "0.0.0"
|
||||
description = "Development Tool for BlockSuite"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
edition = "2021"
|
||||
rust-version = "1.57"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
bytes = "1.3.0"
|
||||
ipc_types = { path = "./types" }
|
||||
futures = "^0.3.25"
|
||||
js-sys = "0.3.60"
|
||||
jwst = { path = "../src-OctoBase/libs/jwst" }
|
||||
jwst-storage = { path = "../src-OctoBase/libs/jwst-storage", features = [
|
||||
"sqlite",
|
||||
] }
|
||||
cloud-database = { path = "../src-OctoBase/libs/cloud-database", features = [
|
||||
"sqlite",
|
||||
] }
|
||||
project-root = "0.2.2"
|
||||
schemars = "0.8.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
dotenvy = "0.15.6"
|
||||
tauri = { version = "1.2", features = ["api-all", "devtools"] }
|
||||
tokio = { version = "1.23.0", features = ["rt", "macros"] }
|
||||
lib0 = "0.12.0"
|
||||
moka = { version = "0.9.6", features = ["future"] }
|
||||
yrs = { path = "../src-OctoBase/libs/vendors/y-crdt/yrs" }
|
||||
y-sync = { path = "../src-OctoBase/libs/vendors/y-sync" }
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||
default = ["custom-protocol"]
|
||||
# this feature is used used for production builds where `devPath` points to the filesystem
|
||||
# DO NOT remove this
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
||||
[profile.release.package.wry]
|
||||
debug = true
|
||||
debug-assertions = true
|
||||
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
use ipc_types::{
|
||||
blob::IBlobParameters, document::IDocumentParameters, user::IUserParameters,
|
||||
workspace::IWorkspaceParameters,
|
||||
};
|
||||
/**
|
||||
* convert serde to jsonschema: https://imfeld.dev/writing/generating_typescript_types_from_rust
|
||||
* with way to optimize
|
||||
* convert jsonschema to ts: https://github.com/bcherny/json-schema-to-typescript
|
||||
*/
|
||||
use project_root::get_project_root;
|
||||
use schemars::{schema_for, JsonSchema};
|
||||
use std::{
|
||||
fs::write,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
fn generate<T>(path: PathBuf)
|
||||
where
|
||||
T: ?Sized + JsonSchema, // Sized or ?Sized are both ok, click https://zhuanlan.zhihu.com/p/21820917 to learn why
|
||||
{
|
||||
let schema = schema_for!(T);
|
||||
let output = serde_json::to_string_pretty(&schema).unwrap();
|
||||
write(path, output).expect("can not write json-schema file")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let project_root = &get_project_root().unwrap();
|
||||
let mono_repo_root = Path::join(project_root, "../..");
|
||||
let data_center_ipc_type_folder = Path::join(
|
||||
&mono_repo_root,
|
||||
"packages/data-center/src/provider/tauri-ipc/ipc/types",
|
||||
);
|
||||
generate::<IDocumentParameters>(Path::join(&data_center_ipc_type_folder, "document.json"));
|
||||
generate::<IWorkspaceParameters>(Path::join(&data_center_ipc_type_folder, "workspace.json"));
|
||||
generate::<IBlobParameters>(Path::join(&data_center_ipc_type_folder, "blob.json"));
|
||||
generate::<IUserParameters>(Path::join(&data_center_ipc_type_folder, "user.json"));
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 947 B |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 85 KiB |
@@ -0,0 +1 @@
|
||||
tab_spaces = 2
|
||||
@@ -0,0 +1,25 @@
|
||||
pub mod blob;
|
||||
pub mod workspace;
|
||||
pub mod document;
|
||||
pub mod user;
|
||||
|
||||
use blob::*;
|
||||
use workspace::*;
|
||||
use document::*;
|
||||
use user::*;
|
||||
|
||||
pub fn invoke_handler() -> impl Fn(tauri::Invoke) + Send + Sync + 'static {
|
||||
tauri::generate_handler![
|
||||
update_y_document,
|
||||
create_workspace,
|
||||
update_workspace,
|
||||
get_workspaces,
|
||||
get_workspace,
|
||||
create_user,
|
||||
get_user,
|
||||
create_doc,
|
||||
get_doc,
|
||||
put_blob,
|
||||
get_blob
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
use bytes::Bytes;
|
||||
use futures::{
|
||||
stream::{self},
|
||||
StreamExt,
|
||||
};
|
||||
|
||||
use ipc_types::blob::{GetBlob, PutBlob};
|
||||
use jwst::BlobStorage;
|
||||
|
||||
use crate::state::AppState;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn put_blob<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: PutBlob,
|
||||
) -> Result<String, String> {
|
||||
let blob_storage = &state.0.lock().await.blob_storage;
|
||||
if let Ok(path) = blob_storage
|
||||
.put_blob(
|
||||
// TODO: ask octobase to accept blob directly or wrap/await tauri command to create a real stream, so we don't need to construct stream manually
|
||||
parameters.workspace_id,
|
||||
stream::iter::<Vec<Bytes>>(vec![Bytes::from(parameters.blob)]),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(path)
|
||||
} else {
|
||||
Err("Failed to create".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_blob<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: GetBlob,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
let GetBlob { workspace_id, id } = parameters;
|
||||
// TODO: check user permission? Or just assume there will only be one user
|
||||
let blob_storage = &state.0.lock().await.blob_storage;
|
||||
if let Ok(mut file_stream) = blob_storage.get_blob(workspace_id.clone(), id.clone()).await {
|
||||
// Read all of the chunks into a vector.
|
||||
let mut stream_contents = Vec::new();
|
||||
let mut error_message = "".to_string();
|
||||
while let Some(chunk) = file_stream.next().await {
|
||||
match chunk {
|
||||
Ok(chunk_bytes) => stream_contents.extend_from_slice(&chunk_bytes),
|
||||
Err(err) => {
|
||||
error_message = format!(
|
||||
"Failed to read blob file {}/{} from stream, error: {}",
|
||||
workspace_id.clone().unwrap_or_default().to_string(),
|
||||
id,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if error_message.len() > 0 {
|
||||
return Err(error_message);
|
||||
}
|
||||
Ok(stream_contents)
|
||||
} else {
|
||||
Err(format!(
|
||||
"Failed to read blob file {}/{} ",
|
||||
workspace_id.unwrap_or_default().to_string(),
|
||||
id
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
use ipc_types::document::{
|
||||
CreateDocumentParameter, GetDocumentParameter, GetDocumentResponse, YDocumentUpdate,
|
||||
};
|
||||
use jwst::DocStorage;
|
||||
use jwst::Workspace as OctoBaseWorkspace;
|
||||
use lib0::any::Any;
|
||||
|
||||
use crate::state::AppState;
|
||||
|
||||
#[tauri::command]
|
||||
/// get yDoc created by create_workspace, using same id
|
||||
pub async fn create_doc<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: CreateDocumentParameter,
|
||||
) -> Result<(), String> {
|
||||
let workspace_doc = OctoBaseWorkspace::new(parameters.workspace_id.clone());
|
||||
|
||||
workspace_doc.with_trx(|mut workspace_doc_transaction| {
|
||||
workspace_doc_transaction.set_metadata(
|
||||
"name",
|
||||
Any::String(parameters.workspace_name.clone().into_boxed_str()),
|
||||
);
|
||||
});
|
||||
if let Err(error_message) = &state
|
||||
.0
|
||||
.lock()
|
||||
.await
|
||||
.doc_db
|
||||
.write_doc(parameters.workspace_id.clone(), workspace_doc.doc())
|
||||
.await
|
||||
{
|
||||
Err(format!(
|
||||
"Failed to write_doc during create_workspace with error {}",
|
||||
error_message.to_string()
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
/// get yDoc created by create_workspace, using same id
|
||||
pub async fn get_doc<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: GetDocumentParameter,
|
||||
) -> Result<GetDocumentResponse, String> {
|
||||
// TODO: check user permission
|
||||
let state = &state.0.lock().await;
|
||||
let doc_db = &state.doc_db;
|
||||
|
||||
if let Ok(all_updates_of_workspace) = doc_db.all(¶meters.id).await {
|
||||
let all_updates = all_updates_of_workspace
|
||||
.iter()
|
||||
.map(|model| model.blob.clone())
|
||||
.collect::<Vec<Vec<u8>>>();
|
||||
Ok(GetDocumentResponse {
|
||||
updates: all_updates,
|
||||
})
|
||||
} else {
|
||||
Err(format!(
|
||||
"Failed to get yDoc from workspace {}",
|
||||
parameters.id
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn update_y_document<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: YDocumentUpdate,
|
||||
) -> Result<bool, String> {
|
||||
let state = &state.0.lock().await;
|
||||
let doc_db = &state.doc_db;
|
||||
|
||||
doc_db
|
||||
.replace_with(¶meters.id.clone(), parameters.update)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
use cloud_database::{CreateUser, User};
|
||||
use ipc_types::{document::CreateDocumentParameter, user::GetUserParameters};
|
||||
|
||||
use crate::state::AppState;
|
||||
|
||||
use super::document::create_doc;
|
||||
|
||||
#[tauri::command]
|
||||
/// create new user and a private workspace
|
||||
pub async fn create_user<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: CreateUser,
|
||||
) -> Result<User, String> {
|
||||
let new_user_result = &state
|
||||
.0
|
||||
.lock()
|
||||
.await
|
||||
.metadata_db
|
||||
.create_user(parameters.clone())
|
||||
.await;
|
||||
match new_user_result {
|
||||
Ok(new_user_option) => match new_user_option {
|
||||
Some((new_user, new_workspace)) => {
|
||||
// a new private workspace is created, we have to create a yDoc for it
|
||||
create_doc(
|
||||
state,
|
||||
CreateDocumentParameter {
|
||||
workspace_id: new_workspace.id.clone(),
|
||||
workspace_name: parameters.name.clone(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
Ok(new_user.clone())
|
||||
}
|
||||
None => Err("User creation failed".to_string()),
|
||||
},
|
||||
Err(error_message) => Err(error_message.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
/// get the only one user in local sqlite
|
||||
pub async fn get_user<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: GetUserParameters,
|
||||
) -> Result<User, String> {
|
||||
let db = &state.0.lock().await.metadata_db;
|
||||
match db.get_user_by_email(¶meters.email).await.ok().unwrap() {
|
||||
Some(user) => Ok(user),
|
||||
None => Err("User not found".to_string()),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
use ipc_types::{
|
||||
document::CreateDocumentParameter,
|
||||
workspace::{
|
||||
CreateWorkspace, CreateWorkspaceResult, GetWorkspace, GetWorkspaceResult, GetWorkspaces,
|
||||
GetWorkspacesResult, UpdateWorkspace,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::state::AppState;
|
||||
|
||||
use super::document::create_doc;
|
||||
|
||||
#[tauri::command]
|
||||
/// create yDoc for a workspace
|
||||
pub async fn get_workspaces<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: GetWorkspaces,
|
||||
) -> Result<GetWorkspacesResult, String> {
|
||||
match &state
|
||||
.0
|
||||
.lock()
|
||||
.await
|
||||
.metadata_db
|
||||
.get_user_workspaces(parameters.user_id.to_string())
|
||||
.await
|
||||
{
|
||||
Ok(user_workspaces) => Ok(GetWorkspacesResult {
|
||||
workspaces: user_workspaces.clone(),
|
||||
}),
|
||||
Err(error_message) => Err(error_message.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
/// create yDoc for a workspace
|
||||
pub async fn get_workspace<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: GetWorkspace,
|
||||
) -> Result<GetWorkspaceResult, String> {
|
||||
match &state
|
||||
.0
|
||||
.lock()
|
||||
.await
|
||||
.metadata_db
|
||||
.get_workspace_by_id(parameters.id)
|
||||
.await
|
||||
{
|
||||
Ok(user_workspace_option) => match user_workspace_option {
|
||||
Some(user_workspace) => Ok(GetWorkspaceResult {
|
||||
workspace: user_workspace.clone(),
|
||||
}),
|
||||
None => Err("Get workspace has no result".to_string()),
|
||||
},
|
||||
Err(error_message) => Err(error_message.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
/// create yDoc for a workspace
|
||||
pub async fn create_workspace<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: CreateWorkspace,
|
||||
) -> Result<CreateWorkspaceResult, String> {
|
||||
let new_workspace_result = &state
|
||||
.0
|
||||
.lock()
|
||||
.await
|
||||
.metadata_db
|
||||
.create_normal_workspace(parameters.user_id.to_string())
|
||||
.await;
|
||||
match new_workspace_result {
|
||||
Ok(new_workspace) => {
|
||||
create_doc(
|
||||
state,
|
||||
CreateDocumentParameter {
|
||||
workspace_id: new_workspace.id.clone(),
|
||||
workspace_name: parameters.name.clone(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
Ok(CreateWorkspaceResult {
|
||||
id: new_workspace.id.clone(),
|
||||
name: parameters.name,
|
||||
})
|
||||
}
|
||||
Err(error_message) => Err(format!(
|
||||
"Failed to create_workspace with error {}",
|
||||
error_message.to_string()
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn update_workspace<'s>(
|
||||
state: tauri::State<'s, AppState>,
|
||||
parameters: UpdateWorkspace,
|
||||
) -> Result<bool, String> {
|
||||
// TODO: check user permission
|
||||
// No thing to update now. The avatar is update in YDoc using websocket or yrs.update
|
||||
Ok(true)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#![cfg_attr(
|
||||
all(not(debug_assertions), target_os = "windows"),
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
mod commands;
|
||||
mod state;
|
||||
use dotenvy::dotenv;
|
||||
use state::AppState;
|
||||
use std::env;
|
||||
use tauri::TitleBarStyle;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tauri::async_runtime::set(tokio::runtime::Handle::current());
|
||||
dotenv().ok();
|
||||
let preload = include_str!("../../public/preload/index.js");
|
||||
let is_dev = env::var("NODE_ENV").unwrap_or_default() == "development";
|
||||
let initial_path = if is_dev {
|
||||
"index.html"
|
||||
} else {
|
||||
"affine-out/index.html"
|
||||
};
|
||||
tauri::Builder::default()
|
||||
.manage(AppState(Mutex::new(
|
||||
state::AppStateRaw::new().await.unwrap(),
|
||||
)))
|
||||
// manually create window here, instead of in the tauri.conf.json, to add `initialization_script` here
|
||||
.setup(move |app| {
|
||||
let _window =
|
||||
tauri::WindowBuilder::new(app, "label", tauri::WindowUrl::App(initial_path.into()))
|
||||
.title("AFFiNE")
|
||||
.inner_size(1000.0, 800.0)
|
||||
.title_bar_style(TitleBarStyle::Overlay)
|
||||
.hidden_title(true)
|
||||
.initialization_script(&preload)
|
||||
.build()?;
|
||||
#[cfg(debug_assertions)]
|
||||
_window.open_devtools();
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(commands::invoke_handler())
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use cloud_database::SqliteDBContext;
|
||||
use jwst::Workspace;
|
||||
use jwst_storage::{BlobAutoStorage, DocAutoStorage};
|
||||
use std::{fs, path::Path};
|
||||
use tauri::api::path::document_dir;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
pub struct AppStateRaw {
|
||||
pub doc_db: DocAutoStorage,
|
||||
pub blob_storage: BlobAutoStorage,
|
||||
pub metadata_db: SqliteDBContext,
|
||||
}
|
||||
|
||||
impl AppStateRaw {
|
||||
pub async fn new() -> Option<AppStateRaw> {
|
||||
let affine_document_path = Path::new(&document_dir()?.into_os_string()).join("affine");
|
||||
let metadata_db_env = format!(
|
||||
"sqlite://{}?mode=rwc",
|
||||
affine_document_path
|
||||
.join("metadata")
|
||||
.with_extension("db")
|
||||
.display()
|
||||
);
|
||||
let blob_db_env = format!(
|
||||
"sqlite://{}?mode=rwc",
|
||||
affine_document_path
|
||||
.join("blob")
|
||||
.with_extension("db")
|
||||
.display()
|
||||
);
|
||||
let doc_db_env = format!(
|
||||
"sqlite://{}?mode=rwc",
|
||||
affine_document_path
|
||||
.join("doc")
|
||||
.with_extension("db")
|
||||
.display()
|
||||
);
|
||||
fs::create_dir_all(affine_document_path.clone()).unwrap();
|
||||
|
||||
Some(Self {
|
||||
doc_db: DocAutoStorage::init_pool(&doc_db_env).await.unwrap(),
|
||||
blob_storage: BlobAutoStorage::init_pool(&blob_db_env).await.unwrap(),
|
||||
metadata_db: SqliteDBContext::new(metadata_db_env).await,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AppState(pub Mutex<AppStateRaw>); // need pub, otherwise will be "field `0` of struct `types::state::AppState` is private"
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev:prerequisite",
|
||||
"beforeBuildCommand": "pnpm build:preload && pnpm build:affine",
|
||||
"devPath": "http://localhost:8080",
|
||||
"distDir": "../public",
|
||||
"withGlobalTauri": false
|
||||
},
|
||||
"package": {
|
||||
"productName": "AFFiNE",
|
||||
"version": "0.0.2"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": true,
|
||||
"fs": {
|
||||
"all": true,
|
||||
"scope": ["$RESOURCE", "$RESOURCE/*", "$APP/*"]
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"identifier": "com.affine.client",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
}
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "ipc_types"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
jwst-storage = { path = "../../src-OctoBase/libs/jwst-storage", features = [
|
||||
"sqlite",
|
||||
] }
|
||||
cloud-database = { path = "../../src-OctoBase/libs/cloud-database", features = [
|
||||
"sqlite",
|
||||
] }
|
||||
project-root = "0.2.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
schemars = "0.8.3"
|
||||
@@ -0,0 +1,20 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PutBlob {
|
||||
pub workspace_id: Option<String>,
|
||||
pub blob: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GetBlob {
|
||||
pub workspace_id: Option<String>,
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum IBlobParameters {
|
||||
Put(PutBlob),
|
||||
Get(GetBlob),
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct YDocumentUpdate {
|
||||
pub update: Vec<u8>,
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GetDocumentParameter {
|
||||
pub id: String,
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct CreateDocumentParameter {
|
||||
pub workspace_id: String,
|
||||
pub workspace_name: String,
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GetDocumentResponse {
|
||||
pub updates: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum IDocumentParameters {
|
||||
YDocumentUpdate(YDocumentUpdate),
|
||||
CreateDocumentParameter(CreateDocumentParameter),
|
||||
GetDocumentParameter(GetDocumentParameter),
|
||||
GetDocumentResponse(GetDocumentResponse),
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#[allow(unused_imports)]
|
||||
extern crate serde;
|
||||
extern crate schemars;
|
||||
extern crate jwst_storage;
|
||||
extern crate cloud_database;
|
||||
|
||||
pub mod blob;
|
||||
pub mod document;
|
||||
pub mod workspace;
|
||||
pub mod user;
|
||||
@@ -0,0 +1,15 @@
|
||||
use cloud_database::{CreateUser, User};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GetUserParameters {
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum IUserParameters {
|
||||
CreateUser(CreateUser),
|
||||
User(User),
|
||||
GetUserParameters(GetUserParameters),
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
use cloud_database::{WorkspaceWithPermission, WorkspaceDetail};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct CreateWorkspace {
|
||||
pub user_id: String,
|
||||
/**
|
||||
* only set name, avatar is update in datacenter to yDoc directly
|
||||
*/
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GetWorkspaces {
|
||||
pub user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GetWorkspace {
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct CreateWorkspaceResult {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GetWorkspacesResult {
|
||||
pub workspaces: Vec<WorkspaceWithPermission>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GetWorkspaceResult {
|
||||
pub workspace: WorkspaceDetail,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct UpdateWorkspace {
|
||||
pub id: i64,
|
||||
pub public: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum IWorkspaceParameters {
|
||||
CreateWorkspace(CreateWorkspace),
|
||||
GetWorkspace(GetWorkspace),
|
||||
GetWorkspaces(GetWorkspaces),
|
||||
GetWorkspaceResult(GetWorkspaceResult),
|
||||
GetWorkspacesResult(GetWorkspacesResult),
|
||||
UpdateWorkspace(UpdateWorkspace),
|
||||
CreateWorkspaceResult(CreateWorkspaceResult),
|
||||
}
|
||||