mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: integrate grid into flowy-sdk
This commit is contained in:
parent
9125db7ef0
commit
d0b457c007
@ -12,10 +12,12 @@ import 'package:protobuf/protobuf.dart' as $pb;
|
||||
class WSChannel extends $pb.ProtobufEnum {
|
||||
static const WSChannel Document = WSChannel._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Document');
|
||||
static const WSChannel Folder = WSChannel._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Folder');
|
||||
static const WSChannel Grid = WSChannel._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Grid');
|
||||
|
||||
static const $core.List<WSChannel> values = <WSChannel> [
|
||||
Document,
|
||||
Folder,
|
||||
Grid,
|
||||
];
|
||||
|
||||
static final $core.Map<$core.int, WSChannel> _byValue = $pb.ProtobufEnum.initByValue(values);
|
||||
|
@ -14,11 +14,12 @@ const WSChannel$json = const {
|
||||
'2': const [
|
||||
const {'1': 'Document', '2': 0},
|
||||
const {'1': 'Folder', '2': 1},
|
||||
const {'1': 'Grid', '2': 2},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `WSChannel`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||
final $typed_data.Uint8List wSChannelDescriptor = $convert.base64Decode('CglXU0NoYW5uZWwSDAoIRG9jdW1lbnQQABIKCgZGb2xkZXIQAQ==');
|
||||
final $typed_data.Uint8List wSChannelDescriptor = $convert.base64Decode('CglXU0NoYW5uZWwSDAoIRG9jdW1lbnQQABIKCgZGb2xkZXIQARIICgRHcmlkEAI=');
|
||||
@$core.Deprecated('Use webSocketRawMessageDescriptor instead')
|
||||
const WebSocketRawMessage$json = const {
|
||||
'1': 'WebSocketRawMessage',
|
||||
|
1
frontend/rust-lib/Cargo.lock
generated
1
frontend/rust-lib/Cargo.lock
generated
@ -1052,6 +1052,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"dart-notify",
|
||||
"dashmap",
|
||||
"diesel",
|
||||
"flowy-collaboration",
|
||||
"flowy-database",
|
||||
|
@ -32,11 +32,11 @@ impl BlockManager {
|
||||
block_user: Arc<dyn BlockUser>,
|
||||
rev_web_socket: Arc<dyn RevisionWebSocket>,
|
||||
) -> Self {
|
||||
let block_handlers = Arc::new(BlockEditors::new());
|
||||
let block_editors = Arc::new(BlockEditors::new());
|
||||
Self {
|
||||
cloud_service,
|
||||
rev_web_socket,
|
||||
block_editors: block_handlers,
|
||||
block_editors,
|
||||
block_user,
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ chrono = "0.4.19"
|
||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||
bytes = { version = "1.0" }
|
||||
diesel = {version = "1.4.8", features = ["sqlite"]}
|
||||
#diesel_derives = {version = "1.4.1", features = ["sqlite"]}
|
||||
dashmap = "4.0"
|
||||
|
||||
|
||||
parking_lot = "0.11"
|
||||
|
@ -1 +0,0 @@
|
||||
pub struct GridManager {}
|
@ -1,4 +1,4 @@
|
||||
use crate::controller::GridManager;
|
||||
use crate::manager::GridManager;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_grid_data_model::entities::{
|
||||
CreateGridPayload, Grid, GridId, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::controller::GridManager;
|
||||
use crate::event_handler::*;
|
||||
use crate::manager::GridManager;
|
||||
use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
|
||||
use lib_dispatch::prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod controller;
|
||||
mod event_handler;
|
||||
mod event_map;
|
||||
pub mod event_map;
|
||||
pub mod manager;
|
||||
|
||||
mod protobuf;
|
||||
mod services;
|
||||
|
107
frontend/rust-lib/flowy-grid/src/manager.rs
Normal file
107
frontend/rust-lib/flowy-grid/src/manager.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use crate::services::grid_editor::ClientGridEditor;
|
||||
use dashmap::DashMap;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
|
||||
use lib_sqlite::ConnectionPool;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait GridUser: Send + Sync {
|
||||
fn user_id(&self) -> Result<String, FlowyError>;
|
||||
fn token(&self) -> Result<String, FlowyError>;
|
||||
fn db_pool(&self) -> Result<Arc<ConnectionPool>, FlowyError>;
|
||||
}
|
||||
|
||||
pub struct GridManager {
|
||||
grid_editors: Arc<GridEditors>,
|
||||
grid_user: Arc<dyn GridUser>,
|
||||
rev_web_socket: Arc<dyn RevisionWebSocket>,
|
||||
}
|
||||
|
||||
impl GridManager {
|
||||
pub fn new(grid_user: Arc<dyn GridUser>, rev_web_socket: Arc<dyn RevisionWebSocket>) -> Self {
|
||||
let grid_editors = Arc::new(GridEditors::new());
|
||||
Self {
|
||||
grid_editors,
|
||||
grid_user,
|
||||
rev_web_socket,
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self, grid_id), fields(grid_id), err)]
|
||||
pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> Result<Arc<ClientGridEditor>, FlowyError> {
|
||||
let grid_id = grid_id.as_ref();
|
||||
tracing::Span::current().record("grid_id", &grid_id);
|
||||
self.get_grid_editor(grid_id).await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self, grid_id), fields(grid_id), err)]
|
||||
pub fn close_grid<T: AsRef<str>>(&self, grid_id: T) -> Result<(), FlowyError> {
|
||||
let grid_id = grid_id.as_ref();
|
||||
tracing::Span::current().record("grid_id", &grid_id);
|
||||
self.grid_editors.remove(grid_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self, grid_id), fields(doc_id), err)]
|
||||
pub fn delete_grid<T: AsRef<str>>(&self, grid_id: T) -> Result<(), FlowyError> {
|
||||
let grid_id = grid_id.as_ref();
|
||||
tracing::Span::current().record("grid_id", &grid_id);
|
||||
self.grid_editors.remove(grid_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<ClientGridEditor>> {
|
||||
match self.grid_editors.get(grid_id) {
|
||||
None => {
|
||||
let db_pool = self.grid_user.db_pool()?;
|
||||
self.make_grid_editor(grid_id, db_pool).await
|
||||
}
|
||||
Some(editor) => Ok(editor),
|
||||
}
|
||||
}
|
||||
|
||||
async fn make_grid_editor(
|
||||
&self,
|
||||
grid_id: &str,
|
||||
pool: Arc<ConnectionPool>,
|
||||
) -> Result<Arc<ClientGridEditor>, FlowyError> {
|
||||
let token = self.grid_user.token()?;
|
||||
let user_id = self.grid_user.user_id()?;
|
||||
let grid_editor = ClientGridEditor::new(&user_id, grid_id, &token, pool, self.rev_web_socket.clone()).await?;
|
||||
self.grid_editors.insert(grid_id, &grid_editor);
|
||||
Ok(grid_editor)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GridEditors {
|
||||
inner: DashMap<String, Arc<ClientGridEditor>>,
|
||||
}
|
||||
|
||||
impl GridEditors {
|
||||
fn new() -> Self {
|
||||
Self { inner: DashMap::new() }
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&self, grid_id: &str, grid_editor: &Arc<ClientGridEditor>) {
|
||||
if self.inner.contains_key(grid_id) {
|
||||
tracing::warn!("Grid:{} already exists in cache", grid_id);
|
||||
}
|
||||
self.inner.insert(grid_id.to_string(), grid_editor.clone());
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, grid_id: &str) -> bool {
|
||||
self.inner.get(grid_id).is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, grid_id: &str) -> Option<Arc<ClientGridEditor>> {
|
||||
if !self.contains(grid_id) {
|
||||
return None;
|
||||
}
|
||||
let opened_grid = self.inner.get(grid_id).unwrap();
|
||||
Some(opened_grid.clone())
|
||||
}
|
||||
|
||||
pub(crate) fn remove(&self, grid_id: &str) {
|
||||
self.inner.remove(grid_id);
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ use std::sync::Arc;
|
||||
|
||||
pub struct ClientGridEditor {
|
||||
user_id: String,
|
||||
grid_id: GridId,
|
||||
grid_id: String,
|
||||
grid: Arc<RwLock<GridPad>>,
|
||||
rev_manager: Arc<RevisionManager>,
|
||||
kv: Arc<GridKVPersistence>,
|
||||
@ -25,13 +25,13 @@ pub struct ClientGridEditor {
|
||||
impl ClientGridEditor {
|
||||
pub async fn new(
|
||||
user_id: &str,
|
||||
grid_id: &GridId,
|
||||
grid_id: &str,
|
||||
token: &str,
|
||||
pool: Arc<ConnectionPool>,
|
||||
_web_socket: Arc<dyn RevisionWebSocket>,
|
||||
) -> FlowyResult<Self> {
|
||||
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, grid_id.as_ref(), pool.clone()));
|
||||
let mut rev_manager = RevisionManager::new(user_id, grid_id.as_ref(), rev_persistence);
|
||||
) -> FlowyResult<Arc<Self>> {
|
||||
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, grid_id, pool.clone()));
|
||||
let mut rev_manager = RevisionManager::new(user_id, grid_id, rev_persistence);
|
||||
let cloud = Arc::new(GridRevisionCloudService {
|
||||
token: token.to_string(),
|
||||
});
|
||||
@ -43,13 +43,13 @@ impl ClientGridEditor {
|
||||
|
||||
let user_id = user_id.to_owned();
|
||||
let grid_id = grid_id.to_owned();
|
||||
Ok(Self {
|
||||
Ok(Arc::new(Self {
|
||||
user_id,
|
||||
grid_id,
|
||||
grid,
|
||||
rev_manager,
|
||||
kv,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn create_row(&self, row: RawRow) -> FlowyResult<()> {
|
||||
|
@ -122,6 +122,9 @@ impl LocalWebSocketRunner {
|
||||
let _ = self.handle_folder_client_data(client_data, "".to_owned()).await?;
|
||||
Ok(())
|
||||
}
|
||||
WSChannel::Grid => {
|
||||
todo!("Implement grid web socket channel")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,13 +25,13 @@ impl BlockDepsResolver {
|
||||
server_config: &ClientServerConfiguration,
|
||||
) -> Arc<BlockManager> {
|
||||
let user = Arc::new(BlockUserImpl(user_session));
|
||||
let ws_sender = Arc::new(BlockWebSocket(ws_conn.clone()));
|
||||
let rev_web_socket = Arc::new(BlockWebSocket(ws_conn.clone()));
|
||||
let cloud_service: Arc<dyn BlockCloudService> = match local_server {
|
||||
None => Arc::new(BlockHttpCloudService::new(server_config.clone())),
|
||||
Some(local_server) => local_server,
|
||||
};
|
||||
|
||||
let manager = Arc::new(BlockManager::new(cloud_service, user, ws_sender));
|
||||
let manager = Arc::new(BlockManager::new(cloud_service, user, rev_web_socket));
|
||||
let receiver = Arc::new(DocumentWSMessageReceiverImpl(manager.clone()));
|
||||
ws_conn.add_ws_message_receiver(receiver).unwrap();
|
||||
|
||||
|
66
frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs
Normal file
66
frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use crate::FlowyError;
|
||||
use bytes::Bytes;
|
||||
use flowy_collaboration::entities::ws_data::ClientRevisionWSData;
|
||||
use flowy_database::ConnectionPool;
|
||||
use flowy_grid::manager::{GridManager, GridUser};
|
||||
use flowy_net::ws::connection::FlowyWebSocketConnect;
|
||||
use flowy_sync::{RevisionWebSocket, WSStateReceiver};
|
||||
use flowy_user::services::UserSession;
|
||||
use futures_core::future::BoxFuture;
|
||||
use lib_infra::future::BoxResultFuture;
|
||||
use lib_ws::{WSChannel, WebSocketRawMessage};
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct GridDepsResolver();
|
||||
|
||||
impl GridDepsResolver {
|
||||
pub fn resolve(ws_conn: Arc<FlowyWebSocketConnect>, user_session: Arc<UserSession>) -> Arc<GridManager> {
|
||||
let user = Arc::new(GridUserImpl(user_session));
|
||||
let rev_web_socket = Arc::new(GridWebSocket(ws_conn.clone()));
|
||||
let manager = Arc::new(GridManager::new(user, rev_web_socket));
|
||||
manager
|
||||
}
|
||||
}
|
||||
|
||||
struct GridUserImpl(Arc<UserSession>);
|
||||
impl GridUser for GridUserImpl {
|
||||
fn user_id(&self) -> Result<String, FlowyError> {
|
||||
self.0.user_id()
|
||||
}
|
||||
|
||||
fn token(&self) -> Result<String, FlowyError> {
|
||||
self.0.token()
|
||||
}
|
||||
|
||||
fn db_pool(&self) -> Result<Arc<ConnectionPool>, FlowyError> {
|
||||
self.0.db_pool()
|
||||
}
|
||||
}
|
||||
|
||||
struct GridWebSocket(Arc<FlowyWebSocketConnect>);
|
||||
impl RevisionWebSocket for GridWebSocket {
|
||||
fn send(&self, data: ClientRevisionWSData) -> BoxResultFuture<(), FlowyError> {
|
||||
let bytes: Bytes = data.try_into().unwrap();
|
||||
let msg = WebSocketRawMessage {
|
||||
channel: WSChannel::Grid,
|
||||
data: bytes.to_vec(),
|
||||
};
|
||||
|
||||
let ws_conn = self.0.clone();
|
||||
Box::pin(async move {
|
||||
match ws_conn.web_socket().await? {
|
||||
None => {}
|
||||
Some(sender) => {
|
||||
sender.send(msg).map_err(|e| FlowyError::internal().context(e))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn subscribe_state_changed(&self) -> BoxFuture<WSStateReceiver> {
|
||||
let ws_conn = self.0.clone();
|
||||
Box::pin(async move { ws_conn.subscribe_websocket_state().await })
|
||||
}
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
mod block_deps;
|
||||
mod folder_deps;
|
||||
mod grid_deps;
|
||||
mod user_deps;
|
||||
mod util;
|
||||
|
||||
pub use block_deps::*;
|
||||
pub use folder_deps::*;
|
||||
pub use grid_deps::*;
|
||||
pub use user_deps::*;
|
||||
|
@ -5,6 +5,7 @@ pub use flowy_net::get_client_server_configuration;
|
||||
use crate::deps_resolve::*;
|
||||
use flowy_block::BlockManager;
|
||||
use flowy_folder::{controller::FolderManager, errors::FlowyError};
|
||||
use flowy_grid::manager::GridManager;
|
||||
use flowy_net::ClientServerConfiguration;
|
||||
use flowy_net::{
|
||||
entities::NetworkType,
|
||||
@ -88,6 +89,7 @@ pub struct FlowySDK {
|
||||
pub user_session: Arc<UserSession>,
|
||||
pub document_manager: Arc<BlockManager>,
|
||||
pub folder_manager: Arc<FolderManager>,
|
||||
pub grid_manager: Arc<GridManager>,
|
||||
pub dispatcher: Arc<EventDispatcher>,
|
||||
pub ws_conn: Arc<FlowyWebSocketConnect>,
|
||||
pub local_server: Option<Arc<LocalServer>>,
|
||||
@ -100,7 +102,7 @@ impl FlowySDK {
|
||||
tracing::debug!("🔥 {:?}", config);
|
||||
let runtime = tokio_default_runtime().unwrap();
|
||||
let (local_server, ws_conn) = mk_local_server(&config.server_config);
|
||||
let (user_session, document_manager, folder_manager, local_server) = runtime.block_on(async {
|
||||
let (user_session, document_manager, folder_manager, local_server, grid_manager) = runtime.block_on(async {
|
||||
let user_session = mk_user_session(&config, &local_server, &config.server_config);
|
||||
let document_manager = BlockDepsResolver::resolve(
|
||||
local_server.clone(),
|
||||
@ -118,15 +120,23 @@ impl FlowySDK {
|
||||
)
|
||||
.await;
|
||||
|
||||
let grid_manager = GridDepsResolver::resolve(ws_conn.clone(), user_session.clone());
|
||||
|
||||
if let Some(local_server) = local_server.as_ref() {
|
||||
local_server.run();
|
||||
}
|
||||
ws_conn.init().await;
|
||||
(user_session, document_manager, folder_manager, local_server)
|
||||
(
|
||||
user_session,
|
||||
document_manager,
|
||||
folder_manager,
|
||||
local_server,
|
||||
grid_manager,
|
||||
)
|
||||
});
|
||||
|
||||
let dispatcher = Arc::new(EventDispatcher::construct(runtime, || {
|
||||
mk_modules(&ws_conn, &folder_manager, &user_session)
|
||||
mk_modules(&ws_conn, &folder_manager, &grid_manager, &user_session)
|
||||
}));
|
||||
|
||||
_start_listening(&dispatcher, &ws_conn, &user_session, &folder_manager);
|
||||
@ -136,6 +146,7 @@ impl FlowySDK {
|
||||
user_session,
|
||||
document_manager,
|
||||
folder_manager,
|
||||
grid_manager,
|
||||
dispatcher,
|
||||
ws_conn,
|
||||
local_server,
|
||||
|
@ -1,4 +1,5 @@
|
||||
use flowy_folder::controller::FolderManager;
|
||||
use flowy_grid::manager::GridManager;
|
||||
use flowy_net::ws::connection::FlowyWebSocketConnect;
|
||||
use flowy_user::services::UserSession;
|
||||
use lib_dispatch::prelude::Module;
|
||||
@ -7,22 +8,28 @@ use std::sync::Arc;
|
||||
pub fn mk_modules(
|
||||
ws_conn: &Arc<FlowyWebSocketConnect>,
|
||||
folder_manager: &Arc<FolderManager>,
|
||||
grid_manager: &Arc<GridManager>,
|
||||
user_session: &Arc<UserSession>,
|
||||
) -> Vec<Module> {
|
||||
let user_module = mk_user_module(user_session.clone());
|
||||
let folder_module = mk_folder_module(folder_manager.clone());
|
||||
let network_module = mk_network_module(ws_conn.clone());
|
||||
vec![user_module, folder_module, network_module]
|
||||
let grid_module = mk_grid_module(grid_manager.clone());
|
||||
vec![user_module, folder_module, network_module, grid_module]
|
||||
}
|
||||
|
||||
fn mk_user_module(user_session: Arc<UserSession>) -> Module {
|
||||
flowy_user::event_map::create(user_session)
|
||||
}
|
||||
|
||||
fn mk_folder_module(core: Arc<FolderManager>) -> Module {
|
||||
flowy_folder::event_map::create(core)
|
||||
fn mk_folder_module(folder_manager: Arc<FolderManager>) -> Module {
|
||||
flowy_folder::event_map::create(folder_manager)
|
||||
}
|
||||
|
||||
fn mk_network_module(ws_conn: Arc<FlowyWebSocketConnect>) -> Module {
|
||||
flowy_net::event_map::create(ws_conn)
|
||||
}
|
||||
|
||||
fn mk_grid_module(grid_manager: Arc<GridManager>) -> Module {
|
||||
flowy_grid::event_map::create(grid_manager)
|
||||
}
|
||||
|
@ -12,10 +12,12 @@ pub struct WebSocketRawMessage {
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
// The lib-ws crate should not contain business logic.So WSChannel should be removed into another place.
|
||||
#[derive(ProtoBuf_Enum, Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum WSChannel {
|
||||
Document = 0,
|
||||
Folder = 1,
|
||||
Grid = 2,
|
||||
}
|
||||
|
||||
impl std::default::Default for WSChannel {
|
||||
@ -29,6 +31,7 @@ impl ToString for WSChannel {
|
||||
match self {
|
||||
WSChannel::Document => "0".to_string(),
|
||||
WSChannel::Folder => "1".to_string(),
|
||||
WSChannel::Grid => "2".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -217,6 +217,7 @@ impl ::protobuf::reflect::ProtobufValue for WebSocketRawMessage {
|
||||
pub enum WSChannel {
|
||||
Document = 0,
|
||||
Folder = 1,
|
||||
Grid = 2,
|
||||
}
|
||||
|
||||
impl ::protobuf::ProtobufEnum for WSChannel {
|
||||
@ -228,6 +229,7 @@ impl ::protobuf::ProtobufEnum for WSChannel {
|
||||
match value {
|
||||
0 => ::std::option::Option::Some(WSChannel::Document),
|
||||
1 => ::std::option::Option::Some(WSChannel::Folder),
|
||||
2 => ::std::option::Option::Some(WSChannel::Grid),
|
||||
_ => ::std::option::Option::None
|
||||
}
|
||||
}
|
||||
@ -236,6 +238,7 @@ impl ::protobuf::ProtobufEnum for WSChannel {
|
||||
static values: &'static [WSChannel] = &[
|
||||
WSChannel::Document,
|
||||
WSChannel::Folder,
|
||||
WSChannel::Grid,
|
||||
];
|
||||
values
|
||||
}
|
||||
@ -266,8 +269,8 @@ impl ::protobuf::reflect::ProtobufValue for WSChannel {
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\tmsg.proto\"O\n\x13WebSocketRawMessage\x12$\n\x07channel\x18\x01\x20\
|
||||
\x01(\x0e2\n.WSChannelR\x07channel\x12\x12\n\x04data\x18\x02\x20\x01(\
|
||||
\x0cR\x04data*%\n\tWSChannel\x12\x0c\n\x08Document\x10\0\x12\n\n\x06Fold\
|
||||
er\x10\x01b\x06proto3\
|
||||
\x0cR\x04data*/\n\tWSChannel\x12\x0c\n\x08Document\x10\0\x12\n\n\x06Fold\
|
||||
er\x10\x01\x12\x08\n\x04Grid\x10\x02b\x06proto3\
|
||||
";
|
||||
|
||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||
|
@ -7,4 +7,5 @@ message WebSocketRawMessage {
|
||||
enum WSChannel {
|
||||
Document = 0;
|
||||
Folder = 1;
|
||||
Grid = 2;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user