mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
config document kv store
This commit is contained in:
parent
eb601932ea
commit
cb4398eab0
@ -2,7 +2,5 @@
|
||||
CREATE TABLE IF NOT EXISTS doc_table(
|
||||
id uuid NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
-- data bytea NOT NULL DEFAULT '',
|
||||
data TEXT NOT NULL DEFAULT '',
|
||||
rev_id bigint NOT NULL DEFAULT 0
|
||||
);
|
@ -42,7 +42,7 @@ impl Application {
|
||||
pub fn run(listener: TcpListener, app_ctx: AppContext) -> Result<Server, std::io::Error> {
|
||||
let domain = domain();
|
||||
let secret: String = secret();
|
||||
actix_rt::spawn(period_check(app_ctx.pg_pool.clone()));
|
||||
actix_rt::spawn(period_check(app_ctx.persistence.pg_pool()));
|
||||
|
||||
let server = HttpServer::new(move || {
|
||||
App::new()
|
||||
@ -54,16 +54,17 @@ pub fn run(listener: TcpListener, app_ctx: AppContext) -> Result<Server, std::io
|
||||
.service(ws_scope())
|
||||
.service(user_scope())
|
||||
.app_data(app_ctx.ws_server.clone())
|
||||
.app_data(app_ctx.pg_pool.clone())
|
||||
.app_data(app_ctx.persistence.clone())
|
||||
.app_data(Data::new(app_ctx.persistence.pg_pool()))
|
||||
.app_data(app_ctx.ws_receivers.clone())
|
||||
.app_data(app_ctx.document_mng.clone())
|
||||
})
|
||||
.listen(listener)?
|
||||
.run();
|
||||
Ok(server)
|
||||
}
|
||||
|
||||
async fn period_check(_pool: Data<PgPool>) {
|
||||
#[allow(dead_code)]
|
||||
async fn period_check(_pool: PgPool) {
|
||||
let mut i = interval(Duration::from_secs(60));
|
||||
loop {
|
||||
i.tick().await;
|
||||
|
@ -1,10 +1,11 @@
|
||||
use crate::services::{
|
||||
document::manager::DocumentManager,
|
||||
kv_store::{KVStore, PostgresKV},
|
||||
web_socket::{WSServer, WebSocketReceivers},
|
||||
};
|
||||
use actix::Addr;
|
||||
use actix_web::web::Data;
|
||||
|
||||
use crate::services::document::{controller::make_document_ws_receiver, persistence::DocumentKVPersistence};
|
||||
use lib_ws::WSModule;
|
||||
use sqlx::PgPool;
|
||||
use std::sync::Arc;
|
||||
@ -12,30 +13,41 @@ use std::sync::Arc;
|
||||
#[derive(Clone)]
|
||||
pub struct AppContext {
|
||||
pub ws_server: Data<Addr<WSServer>>,
|
||||
pub pg_pool: Data<PgPool>,
|
||||
pub persistence: Data<Arc<FlowyPersistence>>,
|
||||
pub ws_receivers: Data<WebSocketReceivers>,
|
||||
pub document_mng: Data<Arc<DocumentManager>>,
|
||||
pub kv_store: Data<Arc<dyn KVStore>>,
|
||||
}
|
||||
|
||||
impl AppContext {
|
||||
pub fn new(ws_server: Addr<WSServer>, db_pool: PgPool) -> Self {
|
||||
pub fn new(ws_server: Addr<WSServer>, pg_pool: PgPool) -> Self {
|
||||
let ws_server = Data::new(ws_server);
|
||||
let pg_pool = Data::new(db_pool);
|
||||
|
||||
let mut ws_receivers = WebSocketReceivers::new();
|
||||
let document_mng = Arc::new(DocumentManager::new(pg_pool.clone()));
|
||||
ws_receivers.set(WSModule::Doc, document_mng.clone());
|
||||
let kv_store = Arc::new(PostgresKV {
|
||||
pg_pool: pg_pool.clone(),
|
||||
});
|
||||
|
||||
let kv_store = make_document_kv_store(pg_pool.clone());
|
||||
let persistence = Arc::new(FlowyPersistence { pg_pool, kv_store });
|
||||
|
||||
let document_ws_receiver = make_document_ws_receiver(persistence.clone());
|
||||
ws_receivers.set(WSModule::Doc, document_ws_receiver);
|
||||
AppContext {
|
||||
ws_server,
|
||||
pg_pool,
|
||||
persistence: Data::new(persistence),
|
||||
ws_receivers: Data::new(ws_receivers),
|
||||
document_mng: Data::new(document_mng),
|
||||
kv_store: Data::new(kv_store),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_document_kv_store(pg_pool: PgPool) -> Arc<DocumentKVPersistence> {
|
||||
let kv_impl = Arc::new(PostgresKV { pg_pool });
|
||||
Arc::new(DocumentKVPersistence::new(kv_impl))
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FlowyPersistence {
|
||||
pg_pool: PgPool,
|
||||
kv_store: Arc<DocumentKVPersistence>,
|
||||
}
|
||||
|
||||
impl FlowyPersistence {
|
||||
pub fn pg_pool(&self) -> PgPool { self.pg_pool.clone() }
|
||||
|
||||
pub fn kv_store(&self) -> Arc<DocumentKVPersistence> { self.kv_store.clone() }
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
use flowy_collaboration::protobuf::Doc;
|
||||
|
||||
pub(crate) const DOC_TABLE: &str = "doc_table";
|
||||
|
||||
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||
pub struct DocTable {
|
||||
pub(crate) id: uuid::Uuid,
|
||||
pub(crate) data: String,
|
||||
pub(crate) rev_id: i64,
|
||||
}
|
||||
|
||||
impl std::convert::From<DocTable> for Doc {
|
||||
fn from(table: DocTable) -> Self {
|
||||
let mut doc = Doc::new();
|
||||
doc.set_id(table.id.to_string());
|
||||
doc.set_data(table.data);
|
||||
doc.set_rev_id(table.rev_id);
|
||||
doc
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
pub mod doc;
|
||||
pub mod logged_user;
|
||||
pub mod token;
|
||||
pub mod user;
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::services::document::{create_doc_with_transaction, delete_doc};
|
||||
|
||||
use crate::{
|
||||
entities::logged_user::LoggedUser,
|
||||
services::core::{trash::read_trash_ids, view::persistence::*},
|
||||
services::{
|
||||
core::{trash::read_trash_ids, view::persistence::*},
|
||||
document::persistence::{create_doc_with_transaction, delete_doc},
|
||||
},
|
||||
util::sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
|
||||
};
|
||||
use backend_service::errors::{invalid_params, ServerError};
|
||||
|
@ -1,9 +1,6 @@
|
||||
use crate::{
|
||||
entities::logged_user::LoggedUser,
|
||||
services::{
|
||||
core::view::{create_view, delete_view, persistence::check_view_ids, read_view, update_view},
|
||||
document::manager::DocumentManager,
|
||||
},
|
||||
services::core::view::{create_view, delete_view, persistence::check_view_ids, read_view, update_view},
|
||||
util::serde_ext::parse_from_payload,
|
||||
};
|
||||
use actix_web::{
|
||||
@ -20,13 +17,8 @@ use flowy_core_data_model::{
|
||||
protobuf::{CreateViewParams, QueryViewRequest, UpdateViewParams, ViewIdentifier},
|
||||
};
|
||||
use sqlx::PgPool;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub async fn create_handler(
|
||||
payload: Payload,
|
||||
pool: Data<PgPool>,
|
||||
_doc_biz: Data<Arc<DocumentManager>>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
pub async fn create_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
|
||||
let params: CreateViewParams = parse_from_payload(payload).await?;
|
||||
let mut transaction = pool
|
||||
.begin()
|
||||
|
@ -1,46 +1,53 @@
|
||||
use crate::services::{
|
||||
document::{
|
||||
create_doc,
|
||||
read_doc,
|
||||
update_doc,
|
||||
persistence::{create_doc, read_doc, update_doc},
|
||||
ws_actor::{DocumentWebSocketActor, WSActorMessage},
|
||||
},
|
||||
web_socket::{WSClientData, WebSocketReceiver},
|
||||
};
|
||||
use actix_web::web::Data;
|
||||
|
||||
use backend_service::errors::ServerError;
|
||||
|
||||
use crate::context::FlowyPersistence;
|
||||
use flowy_collaboration::{
|
||||
core::sync::{ServerDocManager, ServerDocPersistence},
|
||||
core::sync::{DocumentPersistence, ServerDocumentManager},
|
||||
entities::doc::Doc,
|
||||
errors::CollaborateError,
|
||||
protobuf::{CreateDocParams, DocIdentifier, UpdateDocParams},
|
||||
};
|
||||
use lib_infra::future::FutureResultSend;
|
||||
use lib_ot::{revision::Revision, rich_text::RichTextDelta};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use std::{convert::TryInto, sync::Arc};
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
pub struct DocumentManager {
|
||||
ws_sender: mpsc::Sender<WSActorMessage>,
|
||||
pg_pool: Data<PgPool>,
|
||||
pub fn make_document_ws_receiver(persistence: Arc<FlowyPersistence>) -> Arc<DocumentWebSocketReceiver> {
|
||||
let document_persistence = Arc::new(DocumentPersistenceImpl(persistence.clone()));
|
||||
let document_manager = Arc::new(ServerDocumentManager::new(document_persistence));
|
||||
|
||||
let (ws_sender, rx) = tokio::sync::mpsc::channel(100);
|
||||
let actor = DocumentWebSocketActor::new(rx, document_manager);
|
||||
tokio::task::spawn(actor.run());
|
||||
|
||||
Arc::new(DocumentWebSocketReceiver::new(persistence, ws_sender))
|
||||
}
|
||||
|
||||
impl DocumentManager {
|
||||
pub fn new(pg_pool: Data<PgPool>) -> Self {
|
||||
let inner = Arc::new(ServerDocManager::new(Arc::new(DocPersistenceImpl(pg_pool.clone()))));
|
||||
let (ws_sender, rx) = mpsc::channel(100);
|
||||
let actor = DocumentWebSocketActor::new(rx, inner);
|
||||
tokio::task::spawn(actor.run());
|
||||
Self { ws_sender, pg_pool }
|
||||
pub struct DocumentWebSocketReceiver {
|
||||
ws_sender: mpsc::Sender<WSActorMessage>,
|
||||
persistence: Arc<FlowyPersistence>,
|
||||
}
|
||||
|
||||
impl DocumentWebSocketReceiver {
|
||||
pub fn new(persistence: Arc<FlowyPersistence>, ws_sender: mpsc::Sender<WSActorMessage>) -> Self {
|
||||
Self { ws_sender, persistence }
|
||||
}
|
||||
}
|
||||
|
||||
impl WebSocketReceiver for DocumentManager {
|
||||
impl WebSocketReceiver for DocumentWebSocketReceiver {
|
||||
fn receive(&self, data: WSClientData) {
|
||||
let (ret, rx) = oneshot::channel();
|
||||
let sender = self.ws_sender.clone();
|
||||
let pool = self.pg_pool.clone();
|
||||
let pool = self.persistence.pg_pool();
|
||||
|
||||
actix_rt::spawn(async move {
|
||||
let msg = WSActorMessage::ClientData {
|
||||
@ -60,10 +67,10 @@ impl WebSocketReceiver for DocumentManager {
|
||||
}
|
||||
}
|
||||
|
||||
struct DocPersistenceImpl(Data<PgPool>);
|
||||
impl ServerDocPersistence for DocPersistenceImpl {
|
||||
struct DocumentPersistenceImpl(Arc<FlowyPersistence>);
|
||||
impl DocumentPersistence for DocumentPersistenceImpl {
|
||||
fn update_doc(&self, doc_id: &str, rev_id: i64, delta: RichTextDelta) -> FutureResultSend<(), CollaborateError> {
|
||||
let pg_pool = self.0.clone();
|
||||
let pg_pool = self.0.pg_pool();
|
||||
let mut params = UpdateDocParams::new();
|
||||
let doc_json = delta.to_json();
|
||||
params.set_doc_id(doc_id.to_string());
|
||||
@ -71,7 +78,7 @@ impl ServerDocPersistence for DocPersistenceImpl {
|
||||
params.set_rev_id(rev_id);
|
||||
|
||||
FutureResultSend::new(async move {
|
||||
let _ = update_doc(pg_pool.get_ref(), params)
|
||||
let _ = update_doc(&pg_pool, params)
|
||||
.await
|
||||
.map_err(server_error_to_collaborate_error)?;
|
||||
Ok(())
|
||||
@ -83,9 +90,9 @@ impl ServerDocPersistence for DocPersistenceImpl {
|
||||
doc_id: doc_id.to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
let pg_pool = self.0.clone();
|
||||
let pg_pool = self.0.pg_pool();
|
||||
FutureResultSend::new(async move {
|
||||
let mut pb_doc = read_doc(pg_pool.get_ref(), params)
|
||||
let mut pb_doc = read_doc(&pg_pool, params)
|
||||
.await
|
||||
.map_err(server_error_to_collaborate_error)?;
|
||||
let doc = (&mut pb_doc)
|
||||
@ -96,7 +103,7 @@ impl ServerDocPersistence for DocPersistenceImpl {
|
||||
}
|
||||
|
||||
fn create_doc(&self, revision: Revision) -> FutureResultSend<Doc, CollaborateError> {
|
||||
let pg_pool = self.0.clone();
|
||||
let pg_pool = self.0.pg_pool();
|
||||
FutureResultSend::new(async move {
|
||||
let delta = RichTextDelta::from_bytes(&revision.delta_data)?;
|
||||
let doc_json = delta.to_json();
|
||||
@ -108,7 +115,7 @@ impl ServerDocPersistence for DocPersistenceImpl {
|
||||
cached_size: Default::default(),
|
||||
};
|
||||
|
||||
let _ = create_doc(pg_pool.get_ref(), params)
|
||||
let _ = create_doc(&pg_pool, params)
|
||||
.await
|
||||
.map_err(server_error_to_collaborate_error)?;
|
||||
let doc: Doc = revision.try_into()?;
|
@ -1,9 +1,6 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
pub(crate) use crud::*;
|
||||
pub use router::*;
|
||||
|
||||
pub mod crud;
|
||||
pub mod manager;
|
||||
pub mod router;
|
||||
mod ws_actor;
|
||||
pub(crate) mod controller;
|
||||
pub(crate) mod persistence;
|
||||
pub(crate) mod router;
|
||||
pub(crate) mod ws_actor;
|
||||
|
48
backend/src/services/document/persistence/kv.rs
Normal file
48
backend/src/services/document/persistence/kv.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use crate::{services::kv_store::KVStore, util::serde_ext::parse_from_bytes};
|
||||
use backend_service::errors::ServerError;
|
||||
use bytes::Bytes;
|
||||
use lib_ot::protobuf::{RepeatedRevision, Revision};
|
||||
use protobuf::Message;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct DocumentKVPersistence {
|
||||
inner: Arc<dyn KVStore>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for DocumentKVPersistence {
|
||||
type Target = Arc<dyn KVStore>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for DocumentKVPersistence {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
|
||||
}
|
||||
|
||||
impl DocumentKVPersistence {
|
||||
pub(crate) fn new(kv_store: Arc<dyn KVStore>) -> Self { DocumentKVPersistence { inner: kv_store } }
|
||||
|
||||
pub(crate) async fn set_revision(&self, revision: Revision) -> Result<(), ServerError> {
|
||||
let key = revision.rev_id.to_string();
|
||||
let bytes = revision.write_to_bytes()?;
|
||||
let _ = self.inner.set(&key, Bytes::from(bytes)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn batch_get_revisions(&self, rev_ids: Vec<i64>) -> Result<RepeatedRevision, ServerError> {
|
||||
let keys = rev_ids
|
||||
.into_iter()
|
||||
.map(|rev_id| rev_id.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let items = self.inner.batch_get(keys).await?;
|
||||
let revisions = items
|
||||
.into_iter()
|
||||
.filter_map(|kv| parse_from_bytes::<Revision>(&kv.value).ok())
|
||||
.collect::<Vec<Revision>>();
|
||||
|
||||
let mut repeated_revision = RepeatedRevision::new();
|
||||
repeated_revision.set_items(revisions.into());
|
||||
Ok(repeated_revision)
|
||||
}
|
||||
}
|
5
backend/src/services/document/persistence/mod.rs
Normal file
5
backend/src/services/document/persistence/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
mod kv;
|
||||
mod postgres;
|
||||
|
||||
pub use kv::*;
|
||||
pub use postgres::*;
|
@ -1,20 +1,29 @@
|
||||
use crate::{
|
||||
entities::doc::{DocTable, DOC_TABLE},
|
||||
services::kv_store::KVStore,
|
||||
util::sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
|
||||
};
|
||||
use anyhow::Context;
|
||||
use backend_service::errors::ServerError;
|
||||
use flowy_collaboration::protobuf::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams};
|
||||
use protobuf::Message;
|
||||
use sqlx::{postgres::PgArguments, PgPool, Postgres};
|
||||
use uuid::Uuid;
|
||||
|
||||
const DOC_TABLE: &str = "doc_table";
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(transaction), err)]
|
||||
pub(crate) async fn create_doc_with_transaction(
|
||||
transaction: &mut DBTransaction<'_>,
|
||||
params: CreateDocParams,
|
||||
// kv_store: Data<Arc<dyn KVStore>>,
|
||||
) -> Result<(), ServerError> {
|
||||
let uuid = Uuid::parse_str(¶ms.id)?;
|
||||
let (sql, args) = NewDocSqlBuilder::new(uuid).data(params.data).build()?;
|
||||
let (sql, args) = SqlBuilder::create(DOC_TABLE)
|
||||
.add_field_with_arg("id", uuid)
|
||||
.add_field_with_arg("rev_id", 0)
|
||||
.build()?;
|
||||
|
||||
// TODO kv
|
||||
let _ = sqlx::query_with(&sql, args)
|
||||
.execute(transaction)
|
||||
.await
|
||||
@ -51,18 +60,20 @@ pub(crate) async fn read_doc(pool: &PgPool, params: DocIdentifier) -> Result<Doc
|
||||
|
||||
let (sql, args) = builder.build()?;
|
||||
// TODO: benchmark the speed of different documents with different size
|
||||
let doc: Doc = sqlx::query_as_with::<Postgres, DocTable, PgArguments>(&sql, args)
|
||||
let _table = sqlx::query_as_with::<Postgres, DocTable, PgArguments>(&sql, args)
|
||||
.fetch_one(&mut transaction)
|
||||
.await
|
||||
.map_err(map_sqlx_error)?
|
||||
.into();
|
||||
.map_err(map_sqlx_error)?;
|
||||
|
||||
transaction
|
||||
.commit()
|
||||
.await
|
||||
.context("Failed to commit SQL transaction to read document.")?;
|
||||
// TODO: kv
|
||||
panic!("")
|
||||
|
||||
Ok(doc)
|
||||
// transaction
|
||||
// .commit()
|
||||
// .await
|
||||
// .context("Failed to commit SQL transaction to read document.")?;
|
||||
//
|
||||
// Ok(doc)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(pool, params), fields(delta), err)]
|
||||
@ -107,32 +118,17 @@ pub(crate) async fn delete_doc(transaction: &mut DBTransaction<'_>, doc_id: Uuid
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct NewDocSqlBuilder {
|
||||
table: DocTable,
|
||||
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||
struct DocTable {
|
||||
id: uuid::Uuid,
|
||||
rev_id: i64,
|
||||
}
|
||||
|
||||
impl NewDocSqlBuilder {
|
||||
pub fn new(id: Uuid) -> Self {
|
||||
let table = DocTable {
|
||||
id,
|
||||
data: "".to_owned(),
|
||||
rev_id: 0,
|
||||
};
|
||||
Self { table }
|
||||
}
|
||||
|
||||
pub fn data(mut self, data: String) -> Self {
|
||||
self.table.data = data;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<(String, PgArguments), ServerError> {
|
||||
let (sql, args) = SqlBuilder::create(DOC_TABLE)
|
||||
.add_field_with_arg("id", self.table.id)
|
||||
.add_field_with_arg("data", self.table.data)
|
||||
.add_field_with_arg("rev_id", self.table.rev_id)
|
||||
.build()?;
|
||||
|
||||
Ok((sql, args))
|
||||
}
|
||||
}
|
||||
// impl std::convert::From<DocTable> for Doc {
|
||||
// fn from(table: DocTable) -> Self {
|
||||
// let mut doc = Doc::new();
|
||||
// doc.set_id(table.id.to_string());
|
||||
// doc.set_rev_id(table.rev_id);
|
||||
// doc
|
||||
// }
|
||||
// }
|
@ -1,10 +1,11 @@
|
||||
use crate::services::document::{create_doc, read_doc, update_doc};
|
||||
use crate::{
|
||||
services::document::persistence::{create_doc, read_doc, update_doc},
|
||||
util::serde_ext::parse_from_payload,
|
||||
};
|
||||
use actix_web::{
|
||||
web::{Data, Payload},
|
||||
HttpResponse,
|
||||
};
|
||||
|
||||
use crate::util::serde_ext::parse_from_payload;
|
||||
use backend_service::{errors::ServerError, response::FlowyResponse};
|
||||
use flowy_collaboration::protobuf::{CreateDocParams, DocIdentifier, UpdateDocParams};
|
||||
use sqlx::PgPool;
|
||||
|
@ -1,16 +1,16 @@
|
||||
use crate::{
|
||||
services::{
|
||||
document::update_doc,
|
||||
document::persistence::update_doc,
|
||||
web_socket::{entities::Socket, WSClientData, WSMessageAdaptor, WSUser},
|
||||
},
|
||||
util::serde_ext::{md5, parse_from_bytes},
|
||||
};
|
||||
use actix_rt::task::spawn_blocking;
|
||||
use actix_web::web::Data;
|
||||
|
||||
use async_stream::stream;
|
||||
use backend_service::errors::{internal_error, Result, ServerError};
|
||||
use flowy_collaboration::{
|
||||
core::sync::{RevisionUser, ServerDocManager, SyncResponse},
|
||||
core::sync::{RevisionUser, ServerDocumentManager, SyncResponse},
|
||||
protobuf::{DocumentWSData, DocumentWSDataType, NewDocumentUser, UpdateDocParams},
|
||||
};
|
||||
use futures::stream::StreamExt;
|
||||
@ -22,18 +22,18 @@ use tokio::sync::{mpsc, oneshot};
|
||||
pub enum WSActorMessage {
|
||||
ClientData {
|
||||
client_data: WSClientData,
|
||||
pool: Data<PgPool>,
|
||||
pool: PgPool,
|
||||
ret: oneshot::Sender<Result<()>>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct DocumentWebSocketActor {
|
||||
receiver: Option<mpsc::Receiver<WSActorMessage>>,
|
||||
doc_manager: Arc<ServerDocManager>,
|
||||
doc_manager: Arc<ServerDocumentManager>,
|
||||
}
|
||||
|
||||
impl DocumentWebSocketActor {
|
||||
pub fn new(receiver: mpsc::Receiver<WSActorMessage>, manager: Arc<ServerDocManager>) -> Self {
|
||||
pub fn new(receiver: mpsc::Receiver<WSActorMessage>, manager: Arc<ServerDocumentManager>) -> Self {
|
||||
Self {
|
||||
receiver: Some(receiver),
|
||||
doc_manager: manager,
|
||||
@ -66,7 +66,7 @@ impl DocumentWebSocketActor {
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_client_data(&self, client_data: WSClientData, pg_pool: Data<PgPool>) -> Result<()> {
|
||||
async fn handle_client_data(&self, client_data: WSClientData, pg_pool: PgPool) -> Result<()> {
|
||||
let WSClientData { user, socket, data } = client_data;
|
||||
let document_data = spawn_blocking(move || {
|
||||
let document_data: DocumentWSData = parse_from_bytes(&data)?;
|
||||
@ -151,7 +151,7 @@ fn verify_md5(revision: &Revision) -> Result<()> {
|
||||
pub struct ServerDocUser {
|
||||
pub user: Arc<WSUser>,
|
||||
pub(crate) socket: Socket,
|
||||
pub pg_pool: Data<PgPool>,
|
||||
pub pg_pool: PgPool,
|
||||
}
|
||||
|
||||
impl RevisionUser for ServerDocUser {
|
||||
@ -182,7 +182,7 @@ impl RevisionUser for ServerDocUser {
|
||||
params.set_doc_id(doc_id);
|
||||
params.set_data(doc_json);
|
||||
params.set_rev_id(rev_id);
|
||||
match update_doc(pg_pool.get_ref(), params).await {
|
||||
match update_doc(&pg_pool, params).await {
|
||||
Ok(_) => {},
|
||||
Err(e) => log::error!("{}", e),
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
services::kv_store::{KVStore, KeyValue},
|
||||
util::sqlx_ext::{map_sqlx_error, SqlBuilder},
|
||||
};
|
||||
use actix_web::web::Data;
|
||||
|
||||
use anyhow::Context;
|
||||
use backend_service::errors::ServerError;
|
||||
use bytes::Bytes;
|
||||
@ -13,7 +13,7 @@ use sqlx::{postgres::PgArguments, Error, PgPool, Postgres, Row};
|
||||
const KV_TABLE: &str = "kv_table";
|
||||
|
||||
pub(crate) struct PostgresKV {
|
||||
pub(crate) pg_pool: Data<PgPool>,
|
||||
pub(crate) pg_pool: PgPool,
|
||||
}
|
||||
|
||||
impl KVStore for PostgresKV {
|
||||
|
@ -29,7 +29,9 @@ impl std::default::Default for WebSocketReceivers {
|
||||
impl WebSocketReceivers {
|
||||
pub fn new() -> Self { WebSocketReceivers::default() }
|
||||
|
||||
pub fn set(&mut self, source: WSModule, handler: Arc<dyn WebSocketReceiver>) { self.inner.insert(source, handler); }
|
||||
pub fn set(&mut self, source: WSModule, receiver: Arc<dyn WebSocketReceiver>) {
|
||||
self.inner.insert(source, receiver);
|
||||
}
|
||||
|
||||
pub fn get(&self, source: &WSModule) -> Option<Arc<dyn WebSocketReceiver>> { self.inner.get(source).cloned() }
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use std::str;
|
||||
#[actix_rt::test]
|
||||
async fn kv_set_test() {
|
||||
let server = spawn_server().await;
|
||||
let kv = server.app_ctx.kv_store.clone();
|
||||
let kv = server.app_ctx.persistence.kv_store();
|
||||
let s1 = "123".to_string();
|
||||
let key = "1";
|
||||
|
||||
@ -18,7 +18,7 @@ async fn kv_set_test() {
|
||||
#[actix_rt::test]
|
||||
async fn kv_delete_test() {
|
||||
let server = spawn_server().await;
|
||||
let kv = server.app_ctx.kv_store.clone();
|
||||
let kv = server.app_ctx.persistence.kv_store();
|
||||
let s1 = "123".to_string();
|
||||
let key = "1";
|
||||
|
||||
@ -30,7 +30,7 @@ async fn kv_delete_test() {
|
||||
#[actix_rt::test]
|
||||
async fn kv_batch_set_test() {
|
||||
let server = spawn_server().await;
|
||||
let kv = server.app_ctx.kv_store.clone();
|
||||
let kv = server.app_ctx.persistence.kv_store();
|
||||
let kvs = vec![
|
||||
KeyValue {
|
||||
key: "1".to_string(),
|
||||
|
@ -145,6 +145,47 @@ class Revision extends $pb.GeneratedMessage {
|
||||
void clearUserId() => clearField(7);
|
||||
}
|
||||
|
||||
class RepeatedRevision extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedRevision', createEmptyInstance: create)
|
||||
..pc<Revision>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: Revision.create)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
RepeatedRevision._() : super();
|
||||
factory RepeatedRevision({
|
||||
$core.Iterable<Revision>? items,
|
||||
}) {
|
||||
final _result = create();
|
||||
if (items != null) {
|
||||
_result.items.addAll(items);
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
factory RepeatedRevision.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory RepeatedRevision.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
RepeatedRevision clone() => RepeatedRevision()..mergeFromMessage(this);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
RepeatedRevision copyWith(void Function(RepeatedRevision) updates) => super.copyWith((message) => updates(message as RepeatedRevision)) as RepeatedRevision; // ignore: deprecated_member_use
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static RepeatedRevision create() => RepeatedRevision._();
|
||||
RepeatedRevision createEmptyInstance() => create();
|
||||
static $pb.PbList<RepeatedRevision> createRepeated() => $pb.PbList<RepeatedRevision>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static RepeatedRevision getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<RepeatedRevision>(create);
|
||||
static RepeatedRevision? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.List<Revision> get items => $_getList(0);
|
||||
}
|
||||
|
||||
class RevId extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RevId', createEmptyInstance: create)
|
||||
..aInt64(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value')
|
||||
|
@ -26,11 +26,11 @@ class RevType extends $pb.ProtobufEnum {
|
||||
|
||||
class RevState extends $pb.ProtobufEnum {
|
||||
static const RevState StateLocal = RevState._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'StateLocal');
|
||||
static const RevState Acked = RevState._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Acked');
|
||||
static const RevState Ack = RevState._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Ack');
|
||||
|
||||
static const $core.List<RevState> values = <RevState> [
|
||||
StateLocal,
|
||||
Acked,
|
||||
Ack,
|
||||
];
|
||||
|
||||
static final $core.Map<$core.int, RevState> _byValue = $pb.ProtobufEnum.initByValue(values);
|
||||
|
@ -24,12 +24,12 @@ const RevState$json = const {
|
||||
'1': 'RevState',
|
||||
'2': const [
|
||||
const {'1': 'StateLocal', '2': 0},
|
||||
const {'1': 'Acked', '2': 1},
|
||||
const {'1': 'Ack', '2': 1},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `RevState`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||
final $typed_data.Uint8List revStateDescriptor = $convert.base64Decode('CghSZXZTdGF0ZRIOCgpTdGF0ZUxvY2FsEAASCQoFQWNrZWQQAQ==');
|
||||
final $typed_data.Uint8List revStateDescriptor = $convert.base64Decode('CghSZXZTdGF0ZRIOCgpTdGF0ZUxvY2FsEAASBwoDQWNrEAE=');
|
||||
@$core.Deprecated('Use revisionDescriptor instead')
|
||||
const Revision$json = const {
|
||||
'1': 'Revision',
|
||||
@ -46,6 +46,16 @@ const Revision$json = const {
|
||||
|
||||
/// Descriptor for `Revision`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List revisionDescriptor = $convert.base64Decode('CghSZXZpc2lvbhIeCgtiYXNlX3Jldl9pZBgBIAEoA1IJYmFzZVJldklkEhUKBnJldl9pZBgCIAEoA1IFcmV2SWQSHQoKZGVsdGFfZGF0YRgDIAEoDFIJZGVsdGFEYXRhEhAKA21kNRgEIAEoCVIDbWQ1EhUKBmRvY19pZBgFIAEoCVIFZG9jSWQSGAoCdHkYBiABKA4yCC5SZXZUeXBlUgJ0eRIXCgd1c2VyX2lkGAcgASgJUgZ1c2VySWQ=');
|
||||
@$core.Deprecated('Use repeatedRevisionDescriptor instead')
|
||||
const RepeatedRevision$json = const {
|
||||
'1': 'RepeatedRevision',
|
||||
'2': const [
|
||||
const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.Revision', '10': 'items'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `RepeatedRevision`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List repeatedRevisionDescriptor = $convert.base64Decode('ChBSZXBlYXRlZFJldmlzaW9uEh8KBWl0ZW1zGAEgAygLMgkuUmV2aXNpb25SBWl0ZW1z');
|
||||
@$core.Deprecated('Use revIdDescriptor instead')
|
||||
const RevId$json = const {
|
||||
'1': 'RevId',
|
||||
|
@ -72,7 +72,7 @@ impl RevisionCache {
|
||||
let rev_id = revision.rev_id;
|
||||
let record = RevisionRecord {
|
||||
revision,
|
||||
state: RevState::Acked,
|
||||
state: RevState::Ack,
|
||||
};
|
||||
self.memory_cache.add_revision(&record).await;
|
||||
let _ = self.latest_rev_id.fetch_update(SeqCst, SeqCst, |_e| Some(rev_id));
|
||||
@ -170,7 +170,7 @@ pub struct RevisionRecord {
|
||||
}
|
||||
|
||||
impl RevisionRecord {
|
||||
pub fn ack(&mut self) { self.state = RevState::Acked; }
|
||||
pub fn ack(&mut self) { self.state = RevState::Ack; }
|
||||
}
|
||||
|
||||
struct RevisionSyncSeq {
|
||||
|
@ -145,7 +145,7 @@ impl RevisionLoader {
|
||||
Ok(_) => {},
|
||||
Err(e) => tracing::error!("{}", e),
|
||||
},
|
||||
RevState::Acked => {},
|
||||
RevState::Ack => {},
|
||||
}
|
||||
}
|
||||
revisions = records.into_iter().map(|record| record.revision).collect::<_>();
|
||||
|
@ -50,7 +50,7 @@ impl std::convert::From<RevTableState> for RevState {
|
||||
fn from(s: RevTableState) -> Self {
|
||||
match s {
|
||||
RevTableState::Local => RevState::StateLocal,
|
||||
RevTableState::Acked => RevState::Acked,
|
||||
RevTableState::Acked => RevState::Ack,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,7 +59,7 @@ impl std::convert::From<RevState> for RevTableState {
|
||||
fn from(s: RevState) -> Self {
|
||||
match s {
|
||||
RevState::StateLocal => RevTableState::Local,
|
||||
RevState::Acked => RevTableState::Acked,
|
||||
RevState::Ack => RevTableState::Acked,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::services::ws::{FlowyError, FlowyWebSocket, FlowyWsSender, WSConnectSt
|
||||
use bytes::Bytes;
|
||||
use dashmap::DashMap;
|
||||
use flowy_collaboration::{
|
||||
core::sync::{RevisionUser, ServerDocManager, ServerDocPersistence, SyncResponse},
|
||||
core::sync::{DocumentPersistence, RevisionUser, ServerDocumentManager, SyncResponse},
|
||||
entities::{
|
||||
doc::Doc,
|
||||
ws::{DocumentWSData, DocumentWSDataBuilder, DocumentWSDataType, NewDocumentUser},
|
||||
@ -96,13 +96,13 @@ lazy_static! {
|
||||
}
|
||||
|
||||
struct MockDocServer {
|
||||
pub manager: Arc<ServerDocManager>,
|
||||
pub manager: Arc<ServerDocumentManager>,
|
||||
}
|
||||
|
||||
impl std::default::Default for MockDocServer {
|
||||
fn default() -> Self {
|
||||
let persistence = Arc::new(MockDocServerPersistence::default());
|
||||
let manager = Arc::new(ServerDocManager::new(persistence));
|
||||
let manager = Arc::new(ServerDocumentManager::new(persistence));
|
||||
MockDocServer { manager }
|
||||
}
|
||||
}
|
||||
@ -160,7 +160,7 @@ impl std::default::Default for MockDocServerPersistence {
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerDocPersistence for MockDocServerPersistence {
|
||||
impl DocumentPersistence for MockDocServerPersistence {
|
||||
fn update_doc(&self, _doc_id: &str, _rev_id: i64, _delta: RichTextDelta) -> FutureResultSend<(), CollaborateError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -17,40 +17,19 @@ use tokio::{
|
||||
task::spawn_blocking,
|
||||
};
|
||||
|
||||
pub trait ServerDocPersistence: Send + Sync {
|
||||
pub trait DocumentPersistence: Send + Sync {
|
||||
fn update_doc(&self, doc_id: &str, rev_id: i64, delta: RichTextDelta) -> FutureResultSend<(), CollaborateError>;
|
||||
fn read_doc(&self, doc_id: &str) -> FutureResultSend<Doc, CollaborateError>;
|
||||
fn create_doc(&self, revision: Revision) -> FutureResultSend<Doc, CollaborateError>;
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
// ┌─────────────────┐
|
||||
// │ServerDocManager │
|
||||
// └─────────────────┘
|
||||
// │ 1
|
||||
// ▼ n
|
||||
// ┌───────────────┐
|
||||
// │ OpenDocHandle │
|
||||
// └───────────────┘
|
||||
// │
|
||||
// ▼
|
||||
// ┌──────────────────┐
|
||||
// │ DocCommandQueue │
|
||||
// └──────────────────┘
|
||||
// │ ┌──────────────────────┐ ┌────────────┐
|
||||
// ▼ ┌────▶│ RevisionSynchronizer │────▶│ Document │
|
||||
// ┌────────────────┐ │ └──────────────────────┘ └────────────┘
|
||||
// │ServerDocEditor │─────┤
|
||||
// └────────────────┘ │ ┌────────┐ ┌────────────┐
|
||||
// └────▶│ Users │◆──────│RevisionUser│
|
||||
// └────────┘ └────────────┘
|
||||
pub struct ServerDocManager {
|
||||
pub struct ServerDocumentManager {
|
||||
open_doc_map: DashMap<String, Arc<OpenDocHandle>>,
|
||||
persistence: Arc<dyn ServerDocPersistence>,
|
||||
persistence: Arc<dyn DocumentPersistence>,
|
||||
}
|
||||
|
||||
impl ServerDocManager {
|
||||
pub fn new(persistence: Arc<dyn ServerDocPersistence>) -> Self {
|
||||
impl ServerDocumentManager {
|
||||
pub fn new(persistence: Arc<dyn DocumentPersistence>) -> Self {
|
||||
Self {
|
||||
open_doc_map: DashMap::new(),
|
||||
persistence,
|
||||
|
@ -75,6 +75,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
|
||||
| "WSError"
|
||||
| "WSMessage"
|
||||
| "Revision"
|
||||
| "RepeatedRevision"
|
||||
| "RevId"
|
||||
| "RevisionRange"
|
||||
=> TypeCategory::Protobuf,
|
||||
|
@ -409,6 +409,172 @@ impl ::protobuf::reflect::ProtobufValue for Revision {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default)]
|
||||
pub struct RepeatedRevision {
|
||||
// message fields
|
||||
pub items: ::protobuf::RepeatedField<Revision>,
|
||||
// special fields
|
||||
pub unknown_fields: ::protobuf::UnknownFields,
|
||||
pub cached_size: ::protobuf::CachedSize,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a RepeatedRevision {
|
||||
fn default() -> &'a RepeatedRevision {
|
||||
<RepeatedRevision as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl RepeatedRevision {
|
||||
pub fn new() -> RepeatedRevision {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
// repeated .Revision items = 1;
|
||||
|
||||
|
||||
pub fn get_items(&self) -> &[Revision] {
|
||||
&self.items
|
||||
}
|
||||
pub fn clear_items(&mut self) {
|
||||
self.items.clear();
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_items(&mut self, v: ::protobuf::RepeatedField<Revision>) {
|
||||
self.items = v;
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
pub fn mut_items(&mut self) -> &mut ::protobuf::RepeatedField<Revision> {
|
||||
&mut self.items
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_items(&mut self) -> ::protobuf::RepeatedField<Revision> {
|
||||
::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for RepeatedRevision {
|
||||
fn is_initialized(&self) -> bool {
|
||||
for v in &self.items {
|
||||
if !v.is_initialized() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
||||
while !is.eof()? {
|
||||
let (field_number, wire_type) = is.read_tag_unpack()?;
|
||||
match field_number {
|
||||
1 => {
|
||||
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?;
|
||||
},
|
||||
_ => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u32 {
|
||||
let mut my_size = 0;
|
||||
for value in &self.items {
|
||||
let len = value.compute_size();
|
||||
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
|
||||
};
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
||||
self.cached_size.set(my_size);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
||||
for v in &self.items {
|
||||
os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?;
|
||||
os.write_raw_varint32(v.get_cached_size())?;
|
||||
v.write_to_with_cached_sizes(os)?;
|
||||
};
|
||||
os.write_unknown_fields(self.get_unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn get_cached_size(&self) -> u32 {
|
||||
self.cached_size.get()
|
||||
}
|
||||
|
||||
fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
|
||||
&self.unknown_fields
|
||||
}
|
||||
|
||||
fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
|
||||
&mut self.unknown_fields
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn (::std::any::Any) {
|
||||
self as &dyn (::std::any::Any)
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
|
||||
self as &mut dyn (::std::any::Any)
|
||||
}
|
||||
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
|
||||
self
|
||||
}
|
||||
|
||||
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||
Self::descriptor_static()
|
||||
}
|
||||
|
||||
fn new() -> RepeatedRevision {
|
||||
RepeatedRevision::new()
|
||||
}
|
||||
|
||||
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
||||
descriptor.get(|| {
|
||||
let mut fields = ::std::vec::Vec::new();
|
||||
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<Revision>>(
|
||||
"items",
|
||||
|m: &RepeatedRevision| { &m.items },
|
||||
|m: &mut RepeatedRevision| { &mut m.items },
|
||||
));
|
||||
::protobuf::reflect::MessageDescriptor::new_pb_name::<RepeatedRevision>(
|
||||
"RepeatedRevision",
|
||||
fields,
|
||||
file_descriptor_proto()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static RepeatedRevision {
|
||||
static instance: ::protobuf::rt::LazyV2<RepeatedRevision> = ::protobuf::rt::LazyV2::INIT;
|
||||
instance.get(RepeatedRevision::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Clear for RepeatedRevision {
|
||||
fn clear(&mut self) {
|
||||
self.items.clear();
|
||||
self.unknown_fields.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Debug for RepeatedRevision {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for RepeatedRevision {
|
||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||
::protobuf::reflect::ReflectValueRef::Message(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default)]
|
||||
pub struct RevId {
|
||||
// message fields
|
||||
@ -843,7 +1009,7 @@ impl ::protobuf::reflect::ProtobufValue for RevType {
|
||||
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
|
||||
pub enum RevState {
|
||||
StateLocal = 0,
|
||||
Acked = 1,
|
||||
Ack = 1,
|
||||
}
|
||||
|
||||
impl ::protobuf::ProtobufEnum for RevState {
|
||||
@ -854,7 +1020,7 @@ impl ::protobuf::ProtobufEnum for RevState {
|
||||
fn from_i32(value: i32) -> ::std::option::Option<RevState> {
|
||||
match value {
|
||||
0 => ::std::option::Option::Some(RevState::StateLocal),
|
||||
1 => ::std::option::Option::Some(RevState::Acked),
|
||||
1 => ::std::option::Option::Some(RevState::Ack),
|
||||
_ => ::std::option::Option::None
|
||||
}
|
||||
}
|
||||
@ -862,7 +1028,7 @@ impl ::protobuf::ProtobufEnum for RevState {
|
||||
fn values() -> &'static [Self] {
|
||||
static values: &'static [RevState] = &[
|
||||
RevState::StateLocal,
|
||||
RevState::Acked,
|
||||
RevState::Ack,
|
||||
];
|
||||
values
|
||||
}
|
||||
@ -896,57 +1062,63 @@ static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\x05revId\x12\x1d\n\ndelta_data\x18\x03\x20\x01(\x0cR\tdeltaData\x12\x10\
|
||||
\n\x03md5\x18\x04\x20\x01(\tR\x03md5\x12\x15\n\x06doc_id\x18\x05\x20\x01\
|
||||
(\tR\x05docId\x12\x18\n\x02ty\x18\x06\x20\x01(\x0e2\x08.RevTypeR\x02ty\
|
||||
\x12\x17\n\x07user_id\x18\x07\x20\x01(\tR\x06userId\"\x1d\n\x05RevId\x12\
|
||||
\x14\n\x05value\x18\x01\x20\x01(\x03R\x05value\"N\n\rRevisionRange\x12\
|
||||
\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\x14\n\x05start\x18\x02\
|
||||
\x20\x01(\x03R\x05start\x12\x10\n\x03end\x18\x03\x20\x01(\x03R\x03end*\
|
||||
\x20\n\x07RevType\x12\t\n\x05Local\x10\0\x12\n\n\x06Remote\x10\x01*%\n\
|
||||
\x08RevState\x12\x0e\n\nStateLocal\x10\0\x12\t\n\x05Acked\x10\x01J\x8b\
|
||||
\x07\n\x06\x12\x04\0\0\x1a\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
|
||||
\x04\0\x12\x04\x02\0\n\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x10\n\x0b\
|
||||
\n\x04\x04\0\x02\0\x12\x03\x03\x04\x1a\n\x0c\n\x05\x04\0\x02\0\x05\x12\
|
||||
\x03\x03\x04\t\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\n\x15\n\x0c\n\x05\
|
||||
\x04\0\x02\0\x03\x12\x03\x03\x18\x19\n\x0b\n\x04\x04\0\x02\x01\x12\x03\
|
||||
\x04\x04\x15\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\t\n\x0c\n\x05\
|
||||
\x04\0\x02\x01\x01\x12\x03\x04\n\x10\n\x0c\n\x05\x04\0\x02\x01\x03\x12\
|
||||
\x03\x04\x13\x14\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x19\n\x0c\n\
|
||||
\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\t\n\x0c\n\x05\x04\0\x02\x02\x01\
|
||||
\x12\x03\x05\n\x14\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x17\x18\n\
|
||||
\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x04\x13\n\x0c\n\x05\x04\0\x02\x03\
|
||||
\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06\x0b\x0e\
|
||||
\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06\x11\x12\n\x0b\n\x04\x04\0\x02\
|
||||
\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\x04\0\x02\x04\x05\x12\x03\x07\x04\n\
|
||||
\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\x0b\x11\n\x0c\n\x05\x04\0\x02\
|
||||
\x04\x03\x12\x03\x07\x14\x15\n\x0b\n\x04\x04\0\x02\x05\x12\x03\x08\x04\
|
||||
\x13\n\x0c\n\x05\x04\0\x02\x05\x06\x12\x03\x08\x04\x0b\n\x0c\n\x05\x04\0\
|
||||
\x02\x05\x01\x12\x03\x08\x0c\x0e\n\x0c\n\x05\x04\0\x02\x05\x03\x12\x03\
|
||||
\x08\x11\x12\n\x0b\n\x04\x04\0\x02\x06\x12\x03\t\x04\x17\n\x0c\n\x05\x04\
|
||||
\0\x02\x06\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\0\x02\x06\x01\x12\x03\t\
|
||||
\x0b\x12\n\x0c\n\x05\x04\0\x02\x06\x03\x12\x03\t\x15\x16\n\n\n\x02\x04\
|
||||
\x01\x12\x04\x0b\0\r\x01\n\n\n\x03\x04\x01\x01\x12\x03\x0b\x08\r\n\x0b\n\
|
||||
\x04\x04\x01\x02\0\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x01\x02\0\x05\x12\
|
||||
\x03\x0c\x04\t\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x0c\n\x0f\n\x0c\n\
|
||||
\x05\x04\x01\x02\0\x03\x12\x03\x0c\x12\x13\n\n\n\x02\x04\x02\x12\x04\x0e\
|
||||
\0\x12\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\x15\n\x0b\n\x04\x04\x02\
|
||||
\x02\0\x12\x03\x0f\x04\x16\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0f\x04\
|
||||
\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0f\x0b\x11\n\x0c\n\x05\x04\x02\
|
||||
\x02\0\x03\x12\x03\x0f\x14\x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x10\
|
||||
\x04\x14\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x10\x04\t\n\x0c\n\x05\
|
||||
\x04\x02\x02\x01\x01\x12\x03\x10\n\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\
|
||||
\x12\x03\x10\x12\x13\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x11\x04\x12\n\
|
||||
\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\x11\x04\t\n\x0c\n\x05\x04\x02\x02\
|
||||
\x02\x01\x12\x03\x11\n\r\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x11\x10\
|
||||
\x11\n\n\n\x02\x05\0\x12\x04\x13\0\x16\x01\n\n\n\x03\x05\0\x01\x12\x03\
|
||||
\x13\x05\x0c\n\x0b\n\x04\x05\0\x02\0\x12\x03\x14\x04\x0e\n\x0c\n\x05\x05\
|
||||
\0\x02\0\x01\x12\x03\x14\x04\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x14\
|
||||
\x0c\r\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x15\x04\x0f\n\x0c\n\x05\x05\0\
|
||||
\x02\x01\x01\x12\x03\x15\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x15\
|
||||
\r\x0e\n\n\n\x02\x05\x01\x12\x04\x17\0\x1a\x01\n\n\n\x03\x05\x01\x01\x12\
|
||||
\x03\x17\x05\r\n\x0b\n\x04\x05\x01\x02\0\x12\x03\x18\x04\x13\n\x0c\n\x05\
|
||||
\x05\x01\x02\0\x01\x12\x03\x18\x04\x0e\n\x0c\n\x05\x05\x01\x02\0\x02\x12\
|
||||
\x03\x18\x11\x12\n\x0b\n\x04\x05\x01\x02\x01\x12\x03\x19\x04\x0e\n\x0c\n\
|
||||
\x05\x05\x01\x02\x01\x01\x12\x03\x19\x04\t\n\x0c\n\x05\x05\x01\x02\x01\
|
||||
\x02\x12\x03\x19\x0c\rb\x06proto3\
|
||||
\x12\x17\n\x07user_id\x18\x07\x20\x01(\tR\x06userId\"3\n\x10RepeatedRevi\
|
||||
sion\x12\x1f\n\x05items\x18\x01\x20\x03(\x0b2\t.RevisionR\x05items\"\x1d\
|
||||
\n\x05RevId\x12\x14\n\x05value\x18\x01\x20\x01(\x03R\x05value\"N\n\rRevi\
|
||||
sionRange\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\x14\n\x05\
|
||||
start\x18\x02\x20\x01(\x03R\x05start\x12\x10\n\x03end\x18\x03\x20\x01(\
|
||||
\x03R\x03end*\x20\n\x07RevType\x12\t\n\x05Local\x10\0\x12\n\n\x06Remote\
|
||||
\x10\x01*#\n\x08RevState\x12\x0e\n\nStateLocal\x10\0\x12\x07\n\x03Ack\
|
||||
\x10\x01J\xe8\x07\n\x06\x12\x04\0\0\x1d\x01\n\x08\n\x01\x0c\x12\x03\0\0\
|
||||
\x12\n\n\n\x02\x04\0\x12\x04\x02\0\n\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\
|
||||
\x08\x10\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x1a\n\x0c\n\x05\x04\0\
|
||||
\x02\0\x05\x12\x03\x03\x04\t\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\n\
|
||||
\x15\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x18\x19\n\x0b\n\x04\x04\0\
|
||||
\x02\x01\x12\x03\x04\x04\x15\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\
|
||||
\x04\t\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\n\x10\n\x0c\n\x05\x04\0\
|
||||
\x02\x01\x03\x12\x03\x04\x13\x14\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\
|
||||
\x04\x19\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\t\n\x0c\n\x05\x04\
|
||||
\0\x02\x02\x01\x12\x03\x05\n\x14\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\
|
||||
\x05\x17\x18\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x04\x13\n\x0c\n\x05\
|
||||
\x04\0\x02\x03\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\0\x02\x03\x01\x12\
|
||||
\x03\x06\x0b\x0e\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06\x11\x12\n\x0b\
|
||||
\n\x04\x04\0\x02\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\x04\0\x02\x04\x05\
|
||||
\x12\x03\x07\x04\n\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\x0b\x11\n\
|
||||
\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\x07\x14\x15\n\x0b\n\x04\x04\0\x02\
|
||||
\x05\x12\x03\x08\x04\x13\n\x0c\n\x05\x04\0\x02\x05\x06\x12\x03\x08\x04\
|
||||
\x0b\n\x0c\n\x05\x04\0\x02\x05\x01\x12\x03\x08\x0c\x0e\n\x0c\n\x05\x04\0\
|
||||
\x02\x05\x03\x12\x03\x08\x11\x12\n\x0b\n\x04\x04\0\x02\x06\x12\x03\t\x04\
|
||||
\x17\n\x0c\n\x05\x04\0\x02\x06\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\0\x02\
|
||||
\x06\x01\x12\x03\t\x0b\x12\n\x0c\n\x05\x04\0\x02\x06\x03\x12\x03\t\x15\
|
||||
\x16\n\n\n\x02\x04\x01\x12\x04\x0b\0\r\x01\n\n\n\x03\x04\x01\x01\x12\x03\
|
||||
\x0b\x08\x18\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x0c\x04\x20\n\x0c\n\x05\
|
||||
\x04\x01\x02\0\x04\x12\x03\x0c\x04\x0c\n\x0c\n\x05\x04\x01\x02\0\x06\x12\
|
||||
\x03\x0c\r\x15\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x0c\x16\x1b\n\x0c\n\
|
||||
\x05\x04\x01\x02\0\x03\x12\x03\x0c\x1e\x1f\n\n\n\x02\x04\x02\x12\x04\x0e\
|
||||
\0\x10\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\r\n\x0b\n\x04\x04\x02\
|
||||
\x02\0\x12\x03\x0f\x04\x14\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0f\x04\
|
||||
\t\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0f\n\x0f\n\x0c\n\x05\x04\x02\
|
||||
\x02\0\x03\x12\x03\x0f\x12\x13\n\n\n\x02\x04\x03\x12\x04\x11\0\x15\x01\n\
|
||||
\n\n\x03\x04\x03\x01\x12\x03\x11\x08\x15\n\x0b\n\x04\x04\x03\x02\0\x12\
|
||||
\x03\x12\x04\x16\n\x0c\n\x05\x04\x03\x02\0\x05\x12\x03\x12\x04\n\n\x0c\n\
|
||||
\x05\x04\x03\x02\0\x01\x12\x03\x12\x0b\x11\n\x0c\n\x05\x04\x03\x02\0\x03\
|
||||
\x12\x03\x12\x14\x15\n\x0b\n\x04\x04\x03\x02\x01\x12\x03\x13\x04\x14\n\
|
||||
\x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x13\x04\t\n\x0c\n\x05\x04\x03\x02\
|
||||
\x01\x01\x12\x03\x13\n\x0f\n\x0c\n\x05\x04\x03\x02\x01\x03\x12\x03\x13\
|
||||
\x12\x13\n\x0b\n\x04\x04\x03\x02\x02\x12\x03\x14\x04\x12\n\x0c\n\x05\x04\
|
||||
\x03\x02\x02\x05\x12\x03\x14\x04\t\n\x0c\n\x05\x04\x03\x02\x02\x01\x12\
|
||||
\x03\x14\n\r\n\x0c\n\x05\x04\x03\x02\x02\x03\x12\x03\x14\x10\x11\n\n\n\
|
||||
\x02\x05\0\x12\x04\x16\0\x19\x01\n\n\n\x03\x05\0\x01\x12\x03\x16\x05\x0c\
|
||||
\n\x0b\n\x04\x05\0\x02\0\x12\x03\x17\x04\x0e\n\x0c\n\x05\x05\0\x02\0\x01\
|
||||
\x12\x03\x17\x04\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x17\x0c\r\n\x0b\n\
|
||||
\x04\x05\0\x02\x01\x12\x03\x18\x04\x0f\n\x0c\n\x05\x05\0\x02\x01\x01\x12\
|
||||
\x03\x18\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x18\r\x0e\n\n\n\x02\
|
||||
\x05\x01\x12\x04\x1a\0\x1d\x01\n\n\n\x03\x05\x01\x01\x12\x03\x1a\x05\r\n\
|
||||
\x0b\n\x04\x05\x01\x02\0\x12\x03\x1b\x04\x13\n\x0c\n\x05\x05\x01\x02\0\
|
||||
\x01\x12\x03\x1b\x04\x0e\n\x0c\n\x05\x05\x01\x02\0\x02\x12\x03\x1b\x11\
|
||||
\x12\n\x0b\n\x04\x05\x01\x02\x01\x12\x03\x1c\x04\x0c\n\x0c\n\x05\x05\x01\
|
||||
\x02\x01\x01\x12\x03\x1c\x04\x07\n\x0c\n\x05\x05\x01\x02\x01\x02\x12\x03\
|
||||
\x1c\n\x0bb\x06proto3\
|
||||
";
|
||||
|
||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||
|
@ -9,6 +9,9 @@ message Revision {
|
||||
RevType ty = 6;
|
||||
string user_id = 7;
|
||||
}
|
||||
message RepeatedRevision {
|
||||
repeated Revision items = 1;
|
||||
}
|
||||
message RevId {
|
||||
int64 value = 1;
|
||||
}
|
||||
@ -23,5 +26,5 @@ enum RevType {
|
||||
}
|
||||
enum RevState {
|
||||
StateLocal = 0;
|
||||
Acked = 1;
|
||||
Ack = 1;
|
||||
}
|
||||
|
@ -92,6 +92,26 @@ impl Revision {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Default, ProtoBuf, Clone)]
|
||||
pub struct RepeatedRevision {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<Revision>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for RepeatedRevision {
|
||||
type Target = Vec<Revision>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.items }
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for RepeatedRevision {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.items }
|
||||
}
|
||||
|
||||
impl RepeatedRevision {
|
||||
pub fn into_inner(self) -> Vec<Revision> { self.items }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, ProtoBuf, Default)]
|
||||
pub struct RevId {
|
||||
#[pb(index = 1)]
|
||||
@ -167,5 +187,5 @@ pub fn md5<T: AsRef<[u8]>>(data: T) -> String {
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum RevState {
|
||||
StateLocal = 0,
|
||||
Acked = 1,
|
||||
Ack = 1,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user