mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
rename some struct
This commit is contained in:
@ -4,7 +4,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use actix::Addr;
|
use actix::Addr;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use lib_ws::WsModule;
|
use lib_ws::WSModule;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ impl AppContext {
|
|||||||
|
|
||||||
let mut ws_bizs = WsBizHandlers::new();
|
let mut ws_bizs = WsBizHandlers::new();
|
||||||
let document_core = Arc::new(DocumentCore::new(pg_pool.clone()));
|
let document_core = Arc::new(DocumentCore::new(pg_pool.clone()));
|
||||||
ws_bizs.register(WsModule::Doc, document_core.clone());
|
ws_bizs.register(WSModule::Doc, document_core.clone());
|
||||||
|
|
||||||
AppContext {
|
AppContext {
|
||||||
ws_server,
|
ws_server,
|
||||||
|
@ -11,7 +11,7 @@ use async_stream::stream;
|
|||||||
use backend_service::errors::{internal_error, Result, ServerError};
|
use backend_service::errors::{internal_error, Result, ServerError};
|
||||||
use flowy_collaboration::{
|
use flowy_collaboration::{
|
||||||
core::sync::ServerDocManager,
|
core::sync::ServerDocManager,
|
||||||
protobuf::{WsDocumentData, WsDocumentDataType},
|
protobuf::{DocumentWSData, DocumentWSDataType},
|
||||||
};
|
};
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use lib_ot::protobuf::Revision;
|
use lib_ot::protobuf::Revision;
|
||||||
@ -69,7 +69,7 @@ impl DocWsActor {
|
|||||||
async fn handle_client_data(&self, client_data: WsClientData, pool: Data<PgPool>) -> Result<()> {
|
async fn handle_client_data(&self, client_data: WsClientData, pool: Data<PgPool>) -> Result<()> {
|
||||||
let WsClientData { user, socket, data } = client_data;
|
let WsClientData { user, socket, data } = client_data;
|
||||||
let document_data = spawn_blocking(move || {
|
let document_data = spawn_blocking(move || {
|
||||||
let document_data: WsDocumentData = parse_from_bytes(&data)?;
|
let document_data: DocumentWSData = parse_from_bytes(&data)?;
|
||||||
Result::Ok(document_data)
|
Result::Ok(document_data)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -78,10 +78,10 @@ impl DocWsActor {
|
|||||||
let data = document_data.data;
|
let data = document_data.data;
|
||||||
|
|
||||||
match document_data.ty {
|
match document_data.ty {
|
||||||
WsDocumentDataType::Acked => Ok(()),
|
DocumentWSDataType::Acked => Ok(()),
|
||||||
WsDocumentDataType::PushRev => self.apply_pushed_rev(user, socket, data, pool).await,
|
DocumentWSDataType::PushRev => self.apply_pushed_rev(user, socket, data, pool).await,
|
||||||
WsDocumentDataType::PullRev => Ok(()),
|
DocumentWSDataType::PullRev => Ok(()),
|
||||||
WsDocumentDataType::UserConnect => Ok(()),
|
DocumentWSDataType::UserConnect => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::web_socket::WsClientData;
|
use crate::web_socket::WsClientData;
|
||||||
use lib_ws::WsModule;
|
use lib_ws::WSModule;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
pub trait WsBizHandler: Send + Sync {
|
pub trait WsBizHandler: Send + Sync {
|
||||||
@ -8,7 +8,7 @@ pub trait WsBizHandler: Send + Sync {
|
|||||||
|
|
||||||
pub type BizHandler = Arc<dyn WsBizHandler>;
|
pub type BizHandler = Arc<dyn WsBizHandler>;
|
||||||
pub struct WsBizHandlers {
|
pub struct WsBizHandlers {
|
||||||
inner: HashMap<WsModule, BizHandler>,
|
inner: HashMap<WSModule, BizHandler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for WsBizHandlers {
|
impl std::default::Default for WsBizHandlers {
|
||||||
@ -18,7 +18,7 @@ impl std::default::Default for WsBizHandlers {
|
|||||||
impl WsBizHandlers {
|
impl WsBizHandlers {
|
||||||
pub fn new() -> Self { WsBizHandlers::default() }
|
pub fn new() -> Self { WsBizHandlers::default() }
|
||||||
|
|
||||||
pub fn register(&mut self, source: WsModule, handler: BizHandler) { self.inner.insert(source, handler); }
|
pub fn register(&mut self, source: WSModule, handler: BizHandler) { self.inner.insert(source, handler); }
|
||||||
|
|
||||||
pub fn get(&self, source: &WsModule) -> Option<BizHandler> { self.inner.get(source).cloned() }
|
pub fn get(&self, source: &WSModule) -> Option<BizHandler> { self.inner.get(source).cloned() }
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use actix::Message;
|
use actix::Message;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use flowy_collaboration::entities::ws::WsDocumentData;
|
use flowy_collaboration::entities::ws::DocumentWSData;
|
||||||
use lib_ws::{WsMessage, WsModule};
|
use lib_ws::{WSMessage, WSModule};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
#[derive(Debug, Message, Clone)]
|
#[derive(Debug, Message, Clone)]
|
||||||
@ -14,11 +14,11 @@ impl std::ops::Deref for WsMessageAdaptor {
|
|||||||
fn deref(&self) -> &Self::Target { &self.0 }
|
fn deref(&self) -> &Self::Target { &self.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<WsDocumentData> for WsMessageAdaptor {
|
impl std::convert::From<DocumentWSData> for WsMessageAdaptor {
|
||||||
fn from(data: WsDocumentData) -> Self {
|
fn from(data: DocumentWSData) -> Self {
|
||||||
let bytes: Bytes = data.try_into().unwrap();
|
let bytes: Bytes = data.try_into().unwrap();
|
||||||
let msg = WsMessage {
|
let msg = WSMessage {
|
||||||
module: WsModule::Doc,
|
module: WSModule::Doc,
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use actix::*;
|
|||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use actix_web_actors::{ws, ws::Message::Text};
|
use actix_web_actors::{ws, ws::Message::Text};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use lib_ws::WsMessage;
|
use lib_ws::WSMessage;
|
||||||
use std::{convert::TryFrom, sync::Arc, time::Instant};
|
use std::{convert::TryFrom, sync::Arc, time::Instant};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -64,7 +64,7 @@ impl WsClient {
|
|||||||
|
|
||||||
fn handle_binary_message(&self, bytes: Bytes, socket: Socket) {
|
fn handle_binary_message(&self, bytes: Bytes, socket: Socket) {
|
||||||
// TODO: ok to unwrap?
|
// TODO: ok to unwrap?
|
||||||
let message: WsMessage = WsMessage::try_from(bytes).unwrap();
|
let message: WSMessage = WSMessage::try_from(bytes).unwrap();
|
||||||
match self.biz_handlers.get(&message.module) {
|
match self.biz_handlers.get(&message.module) {
|
||||||
None => {
|
None => {
|
||||||
log::error!("Can't find the handler for {:?}", message.module);
|
log::error!("Can't find the handler for {:?}", message.module);
|
||||||
|
@ -14,19 +14,31 @@ import 'ws.pbenum.dart';
|
|||||||
|
|
||||||
export 'ws.pbenum.dart';
|
export 'ws.pbenum.dart';
|
||||||
|
|
||||||
class WsDocumentData extends $pb.GeneratedMessage {
|
enum DocumentWSData_OneOfId {
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'WsDocumentData', createEmptyInstance: create)
|
id,
|
||||||
|
notSet
|
||||||
|
}
|
||||||
|
|
||||||
|
class DocumentWSData extends $pb.GeneratedMessage {
|
||||||
|
static const $core.Map<$core.int, DocumentWSData_OneOfId> _DocumentWSData_OneOfIdByTag = {
|
||||||
|
4 : DocumentWSData_OneOfId.id,
|
||||||
|
0 : DocumentWSData_OneOfId.notSet
|
||||||
|
};
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocumentWSData', createEmptyInstance: create)
|
||||||
|
..oo(0, [4])
|
||||||
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
|
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
|
||||||
..e<WsDocumentDataType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: WsDocumentDataType.Acked, valueOf: WsDocumentDataType.valueOf, enumValues: WsDocumentDataType.values)
|
..e<DocumentWSDataType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: DocumentWSDataType.Acked, valueOf: DocumentWSDataType.valueOf, enumValues: DocumentWSDataType.values)
|
||||||
..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
|
..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
|
||||||
|
..aInt64(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
|
||||||
WsDocumentData._() : super();
|
DocumentWSData._() : super();
|
||||||
factory WsDocumentData({
|
factory DocumentWSData({
|
||||||
$core.String? docId,
|
$core.String? docId,
|
||||||
WsDocumentDataType? ty,
|
DocumentWSDataType? ty,
|
||||||
$core.List<$core.int>? data,
|
$core.List<$core.int>? data,
|
||||||
|
$fixnum.Int64? id,
|
||||||
}) {
|
}) {
|
||||||
final _result = create();
|
final _result = create();
|
||||||
if (docId != null) {
|
if (docId != null) {
|
||||||
@ -38,28 +50,34 @@ class WsDocumentData extends $pb.GeneratedMessage {
|
|||||||
if (data != null) {
|
if (data != null) {
|
||||||
_result.data = data;
|
_result.data = data;
|
||||||
}
|
}
|
||||||
|
if (id != null) {
|
||||||
|
_result.id = id;
|
||||||
|
}
|
||||||
return _result;
|
return _result;
|
||||||
}
|
}
|
||||||
factory WsDocumentData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
factory DocumentWSData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||||
factory WsDocumentData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
factory DocumentWSData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||||
@$core.Deprecated(
|
@$core.Deprecated(
|
||||||
'Using this can add significant overhead to your binary. '
|
'Using this can add significant overhead to your binary. '
|
||||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||||
'Will be removed in next major version')
|
'Will be removed in next major version')
|
||||||
WsDocumentData clone() => WsDocumentData()..mergeFromMessage(this);
|
DocumentWSData clone() => DocumentWSData()..mergeFromMessage(this);
|
||||||
@$core.Deprecated(
|
@$core.Deprecated(
|
||||||
'Using this can add significant overhead to your binary. '
|
'Using this can add significant overhead to your binary. '
|
||||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||||
'Will be removed in next major version')
|
'Will be removed in next major version')
|
||||||
WsDocumentData copyWith(void Function(WsDocumentData) updates) => super.copyWith((message) => updates(message as WsDocumentData)) as WsDocumentData; // ignore: deprecated_member_use
|
DocumentWSData copyWith(void Function(DocumentWSData) updates) => super.copyWith((message) => updates(message as DocumentWSData)) as DocumentWSData; // ignore: deprecated_member_use
|
||||||
$pb.BuilderInfo get info_ => _i;
|
$pb.BuilderInfo get info_ => _i;
|
||||||
@$core.pragma('dart2js:noInline')
|
@$core.pragma('dart2js:noInline')
|
||||||
static WsDocumentData create() => WsDocumentData._();
|
static DocumentWSData create() => DocumentWSData._();
|
||||||
WsDocumentData createEmptyInstance() => create();
|
DocumentWSData createEmptyInstance() => create();
|
||||||
static $pb.PbList<WsDocumentData> createRepeated() => $pb.PbList<WsDocumentData>();
|
static $pb.PbList<DocumentWSData> createRepeated() => $pb.PbList<DocumentWSData>();
|
||||||
@$core.pragma('dart2js:noInline')
|
@$core.pragma('dart2js:noInline')
|
||||||
static WsDocumentData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<WsDocumentData>(create);
|
static DocumentWSData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DocumentWSData>(create);
|
||||||
static WsDocumentData? _defaultInstance;
|
static DocumentWSData? _defaultInstance;
|
||||||
|
|
||||||
|
DocumentWSData_OneOfId whichOneOfId() => _DocumentWSData_OneOfIdByTag[$_whichOneof(0)]!;
|
||||||
|
void clearOneOfId() => clearField($_whichOneof(0));
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
$core.String get docId => $_getSZ(0);
|
$core.String get docId => $_getSZ(0);
|
||||||
@ -71,9 +89,9 @@ class WsDocumentData extends $pb.GeneratedMessage {
|
|||||||
void clearDocId() => clearField(1);
|
void clearDocId() => clearField(1);
|
||||||
|
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
WsDocumentDataType get ty => $_getN(1);
|
DocumentWSDataType get ty => $_getN(1);
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
set ty(WsDocumentDataType v) { setField(2, v); }
|
set ty(DocumentWSDataType v) { setField(2, v); }
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
$core.bool hasTy() => $_has(1);
|
$core.bool hasTy() => $_has(1);
|
||||||
@$pb.TagNumber(2)
|
@$pb.TagNumber(2)
|
||||||
@ -87,6 +105,15 @@ class WsDocumentData extends $pb.GeneratedMessage {
|
|||||||
$core.bool hasData() => $_has(2);
|
$core.bool hasData() => $_has(2);
|
||||||
@$pb.TagNumber(3)
|
@$pb.TagNumber(3)
|
||||||
void clearData() => clearField(3);
|
void clearData() => clearField(3);
|
||||||
|
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$fixnum.Int64 get id => $_getI64(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
set id($fixnum.Int64 v) { $_setInt64(3, v); }
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$core.bool hasId() => $_has(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
void clearId() => clearField(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
class DocumentConnected extends $pb.GeneratedMessage {
|
class DocumentConnected extends $pb.GeneratedMessage {
|
||||||
|
@ -9,22 +9,22 @@
|
|||||||
import 'dart:core' as $core;
|
import 'dart:core' as $core;
|
||||||
import 'package:protobuf/protobuf.dart' as $pb;
|
import 'package:protobuf/protobuf.dart' as $pb;
|
||||||
|
|
||||||
class WsDocumentDataType extends $pb.ProtobufEnum {
|
class DocumentWSDataType extends $pb.ProtobufEnum {
|
||||||
static const WsDocumentDataType Acked = WsDocumentDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Acked');
|
static const DocumentWSDataType Acked = DocumentWSDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Acked');
|
||||||
static const WsDocumentDataType PushRev = WsDocumentDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PushRev');
|
static const DocumentWSDataType PushRev = DocumentWSDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PushRev');
|
||||||
static const WsDocumentDataType PullRev = WsDocumentDataType._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PullRev');
|
static const DocumentWSDataType PullRev = DocumentWSDataType._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PullRev');
|
||||||
static const WsDocumentDataType UserConnect = WsDocumentDataType._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserConnect');
|
static const DocumentWSDataType UserConnect = DocumentWSDataType._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserConnect');
|
||||||
|
|
||||||
static const $core.List<WsDocumentDataType> values = <WsDocumentDataType> [
|
static const $core.List<DocumentWSDataType> values = <DocumentWSDataType> [
|
||||||
Acked,
|
Acked,
|
||||||
PushRev,
|
PushRev,
|
||||||
PullRev,
|
PullRev,
|
||||||
UserConnect,
|
UserConnect,
|
||||||
];
|
];
|
||||||
|
|
||||||
static final $core.Map<$core.int, WsDocumentDataType> _byValue = $pb.ProtobufEnum.initByValue(values);
|
static final $core.Map<$core.int, DocumentWSDataType> _byValue = $pb.ProtobufEnum.initByValue(values);
|
||||||
static WsDocumentDataType? valueOf($core.int value) => _byValue[value];
|
static DocumentWSDataType? valueOf($core.int value) => _byValue[value];
|
||||||
|
|
||||||
const WsDocumentDataType._($core.int v, $core.String n) : super(v, n);
|
const DocumentWSDataType._($core.int v, $core.String n) : super(v, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
import 'dart:core' as $core;
|
import 'dart:core' as $core;
|
||||||
import 'dart:convert' as $convert;
|
import 'dart:convert' as $convert;
|
||||||
import 'dart:typed_data' as $typed_data;
|
import 'dart:typed_data' as $typed_data;
|
||||||
@$core.Deprecated('Use wsDocumentDataTypeDescriptor instead')
|
@$core.Deprecated('Use documentWSDataTypeDescriptor instead')
|
||||||
const WsDocumentDataType$json = const {
|
const DocumentWSDataType$json = const {
|
||||||
'1': 'WsDocumentDataType',
|
'1': 'DocumentWSDataType',
|
||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'Acked', '2': 0},
|
const {'1': 'Acked', '2': 0},
|
||||||
const {'1': 'PushRev', '2': 1},
|
const {'1': 'PushRev', '2': 1},
|
||||||
@ -19,20 +19,24 @@ const WsDocumentDataType$json = const {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `WsDocumentDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
/// Descriptor for `DocumentWSDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||||
final $typed_data.Uint8List wsDocumentDataTypeDescriptor = $convert.base64Decode('ChJXc0RvY3VtZW50RGF0YVR5cGUSCQoFQWNrZWQQABILCgdQdXNoUmV2EAESCwoHUHVsbFJldhACEg8KC1VzZXJDb25uZWN0EAM=');
|
final $typed_data.Uint8List documentWSDataTypeDescriptor = $convert.base64Decode('ChJEb2N1bWVudFdTRGF0YVR5cGUSCQoFQWNrZWQQABILCgdQdXNoUmV2EAESCwoHUHVsbFJldhACEg8KC1VzZXJDb25uZWN0EAM=');
|
||||||
@$core.Deprecated('Use wsDocumentDataDescriptor instead')
|
@$core.Deprecated('Use documentWSDataDescriptor instead')
|
||||||
const WsDocumentData$json = const {
|
const DocumentWSData$json = const {
|
||||||
'1': 'WsDocumentData',
|
'1': 'DocumentWSData',
|
||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
|
const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
|
||||||
const {'1': 'ty', '3': 2, '4': 1, '5': 14, '6': '.WsDocumentDataType', '10': 'ty'},
|
const {'1': 'ty', '3': 2, '4': 1, '5': 14, '6': '.DocumentWSDataType', '10': 'ty'},
|
||||||
const {'1': 'data', '3': 3, '4': 1, '5': 12, '10': 'data'},
|
const {'1': 'data', '3': 3, '4': 1, '5': 12, '10': 'data'},
|
||||||
|
const {'1': 'id', '3': 4, '4': 1, '5': 3, '9': 0, '10': 'id'},
|
||||||
|
],
|
||||||
|
'8': const [
|
||||||
|
const {'1': 'one_of_id'},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `WsDocumentData`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `DocumentWSData`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List wsDocumentDataDescriptor = $convert.base64Decode('Cg5Xc0RvY3VtZW50RGF0YRIVCgZkb2NfaWQYASABKAlSBWRvY0lkEiMKAnR5GAIgASgOMhMuV3NEb2N1bWVudERhdGFUeXBlUgJ0eRISCgRkYXRhGAMgASgMUgRkYXRh');
|
final $typed_data.Uint8List documentWSDataDescriptor = $convert.base64Decode('Cg5Eb2N1bWVudFdTRGF0YRIVCgZkb2NfaWQYASABKAlSBWRvY0lkEiMKAnR5GAIgASgOMhMuRG9jdW1lbnRXU0RhdGFUeXBlUgJ0eRISCgRkYXRhGAMgASgMUgRkYXRhEhAKAmlkGAQgASgDSABSAmlkQgsKCW9uZV9vZl9pZA==');
|
||||||
@$core.Deprecated('Use documentConnectedDescriptor instead')
|
@$core.Deprecated('Use documentConnectedDescriptor instead')
|
||||||
const DocumentConnected$json = const {
|
const DocumentConnected$json = const {
|
||||||
'1': 'DocumentConnected',
|
'1': 'DocumentConnected',
|
||||||
|
@ -13,15 +13,15 @@ import 'errors.pbenum.dart';
|
|||||||
|
|
||||||
export 'errors.pbenum.dart';
|
export 'errors.pbenum.dart';
|
||||||
|
|
||||||
class WsError extends $pb.GeneratedMessage {
|
class WSError extends $pb.GeneratedMessage {
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'WsError', createEmptyInstance: create)
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'WSError', createEmptyInstance: create)
|
||||||
..e<ErrorCode>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'code', $pb.PbFieldType.OE, defaultOrMaker: ErrorCode.InternalError, valueOf: ErrorCode.valueOf, enumValues: ErrorCode.values)
|
..e<ErrorCode>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'code', $pb.PbFieldType.OE, defaultOrMaker: ErrorCode.InternalError, valueOf: ErrorCode.valueOf, enumValues: ErrorCode.values)
|
||||||
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'msg')
|
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'msg')
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
|
||||||
WsError._() : super();
|
WSError._() : super();
|
||||||
factory WsError({
|
factory WSError({
|
||||||
ErrorCode? code,
|
ErrorCode? code,
|
||||||
$core.String? msg,
|
$core.String? msg,
|
||||||
}) {
|
}) {
|
||||||
@ -34,26 +34,26 @@ class WsError extends $pb.GeneratedMessage {
|
|||||||
}
|
}
|
||||||
return _result;
|
return _result;
|
||||||
}
|
}
|
||||||
factory WsError.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
factory WSError.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||||
factory WsError.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
factory WSError.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||||
@$core.Deprecated(
|
@$core.Deprecated(
|
||||||
'Using this can add significant overhead to your binary. '
|
'Using this can add significant overhead to your binary. '
|
||||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||||
'Will be removed in next major version')
|
'Will be removed in next major version')
|
||||||
WsError clone() => WsError()..mergeFromMessage(this);
|
WSError clone() => WSError()..mergeFromMessage(this);
|
||||||
@$core.Deprecated(
|
@$core.Deprecated(
|
||||||
'Using this can add significant overhead to your binary. '
|
'Using this can add significant overhead to your binary. '
|
||||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||||
'Will be removed in next major version')
|
'Will be removed in next major version')
|
||||||
WsError copyWith(void Function(WsError) updates) => super.copyWith((message) => updates(message as WsError)) as WsError; // ignore: deprecated_member_use
|
WSError copyWith(void Function(WSError) updates) => super.copyWith((message) => updates(message as WSError)) as WSError; // ignore: deprecated_member_use
|
||||||
$pb.BuilderInfo get info_ => _i;
|
$pb.BuilderInfo get info_ => _i;
|
||||||
@$core.pragma('dart2js:noInline')
|
@$core.pragma('dart2js:noInline')
|
||||||
static WsError create() => WsError._();
|
static WSError create() => WSError._();
|
||||||
WsError createEmptyInstance() => create();
|
WSError createEmptyInstance() => create();
|
||||||
static $pb.PbList<WsError> createRepeated() => $pb.PbList<WsError>();
|
static $pb.PbList<WSError> createRepeated() => $pb.PbList<WSError>();
|
||||||
@$core.pragma('dart2js:noInline')
|
@$core.pragma('dart2js:noInline')
|
||||||
static WsError getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<WsError>(create);
|
static WSError getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<WSError>(create);
|
||||||
static WsError? _defaultInstance;
|
static WSError? _defaultInstance;
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
ErrorCode get code => $_getN(0);
|
ErrorCode get code => $_getN(0);
|
||||||
|
@ -20,14 +20,14 @@ const ErrorCode$json = const {
|
|||||||
|
|
||||||
/// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
/// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||||
final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSEQoNSW50ZXJuYWxFcnJvchAAEhYKElVuc3VwcG9ydGVkTWVzc2FnZRABEhAKDFVuYXV0aG9yaXplZBAC');
|
final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSEQoNSW50ZXJuYWxFcnJvchAAEhYKElVuc3VwcG9ydGVkTWVzc2FnZRABEhAKDFVuYXV0aG9yaXplZBAC');
|
||||||
@$core.Deprecated('Use wsErrorDescriptor instead')
|
@$core.Deprecated('Use wSErrorDescriptor instead')
|
||||||
const WsError$json = const {
|
const WSError$json = const {
|
||||||
'1': 'WsError',
|
'1': 'WSError',
|
||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'code', '3': 1, '4': 1, '5': 14, '6': '.ErrorCode', '10': 'code'},
|
const {'1': 'code', '3': 1, '4': 1, '5': 14, '6': '.ErrorCode', '10': 'code'},
|
||||||
const {'1': 'msg', '3': 2, '4': 1, '5': 9, '10': 'msg'},
|
const {'1': 'msg', '3': 2, '4': 1, '5': 9, '10': 'msg'},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `WsError`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `WSError`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List wsErrorDescriptor = $convert.base64Decode('CgdXc0Vycm9yEh4KBGNvZGUYASABKA4yCi5FcnJvckNvZGVSBGNvZGUSEAoDbXNnGAIgASgJUgNtc2c=');
|
final $typed_data.Uint8List wSErrorDescriptor = $convert.base64Decode('CgdXU0Vycm9yEh4KBGNvZGUYASABKA4yCi5FcnJvckNvZGVSBGNvZGUSEAoDbXNnGAIgASgJUgNtc2c=');
|
||||||
|
@ -13,16 +13,16 @@ import 'msg.pbenum.dart';
|
|||||||
|
|
||||||
export 'msg.pbenum.dart';
|
export 'msg.pbenum.dart';
|
||||||
|
|
||||||
class WsMessage extends $pb.GeneratedMessage {
|
class WSMessage extends $pb.GeneratedMessage {
|
||||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'WsMessage', createEmptyInstance: create)
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'WSMessage', createEmptyInstance: create)
|
||||||
..e<WsModule>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'module', $pb.PbFieldType.OE, defaultOrMaker: WsModule.Doc, valueOf: WsModule.valueOf, enumValues: WsModule.values)
|
..e<WSModule>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'module', $pb.PbFieldType.OE, defaultOrMaker: WSModule.Doc, valueOf: WSModule.valueOf, enumValues: WSModule.values)
|
||||||
..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
|
..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
|
||||||
..hasRequiredFields = false
|
..hasRequiredFields = false
|
||||||
;
|
;
|
||||||
|
|
||||||
WsMessage._() : super();
|
WSMessage._() : super();
|
||||||
factory WsMessage({
|
factory WSMessage({
|
||||||
WsModule? module,
|
WSModule? module,
|
||||||
$core.List<$core.int>? data,
|
$core.List<$core.int>? data,
|
||||||
}) {
|
}) {
|
||||||
final _result = create();
|
final _result = create();
|
||||||
@ -34,31 +34,31 @@ class WsMessage extends $pb.GeneratedMessage {
|
|||||||
}
|
}
|
||||||
return _result;
|
return _result;
|
||||||
}
|
}
|
||||||
factory WsMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
factory WSMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||||
factory WsMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
factory WSMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||||
@$core.Deprecated(
|
@$core.Deprecated(
|
||||||
'Using this can add significant overhead to your binary. '
|
'Using this can add significant overhead to your binary. '
|
||||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||||
'Will be removed in next major version')
|
'Will be removed in next major version')
|
||||||
WsMessage clone() => WsMessage()..mergeFromMessage(this);
|
WSMessage clone() => WSMessage()..mergeFromMessage(this);
|
||||||
@$core.Deprecated(
|
@$core.Deprecated(
|
||||||
'Using this can add significant overhead to your binary. '
|
'Using this can add significant overhead to your binary. '
|
||||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||||
'Will be removed in next major version')
|
'Will be removed in next major version')
|
||||||
WsMessage copyWith(void Function(WsMessage) updates) => super.copyWith((message) => updates(message as WsMessage)) as WsMessage; // ignore: deprecated_member_use
|
WSMessage copyWith(void Function(WSMessage) updates) => super.copyWith((message) => updates(message as WSMessage)) as WSMessage; // ignore: deprecated_member_use
|
||||||
$pb.BuilderInfo get info_ => _i;
|
$pb.BuilderInfo get info_ => _i;
|
||||||
@$core.pragma('dart2js:noInline')
|
@$core.pragma('dart2js:noInline')
|
||||||
static WsMessage create() => WsMessage._();
|
static WSMessage create() => WSMessage._();
|
||||||
WsMessage createEmptyInstance() => create();
|
WSMessage createEmptyInstance() => create();
|
||||||
static $pb.PbList<WsMessage> createRepeated() => $pb.PbList<WsMessage>();
|
static $pb.PbList<WSMessage> createRepeated() => $pb.PbList<WSMessage>();
|
||||||
@$core.pragma('dart2js:noInline')
|
@$core.pragma('dart2js:noInline')
|
||||||
static WsMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<WsMessage>(create);
|
static WSMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<WSMessage>(create);
|
||||||
static WsMessage? _defaultInstance;
|
static WSMessage? _defaultInstance;
|
||||||
|
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
WsModule get module => $_getN(0);
|
WSModule get module => $_getN(0);
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
set module(WsModule v) { setField(1, v); }
|
set module(WSModule v) { setField(1, v); }
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
$core.bool hasModule() => $_has(0);
|
$core.bool hasModule() => $_has(0);
|
||||||
@$pb.TagNumber(1)
|
@$pb.TagNumber(1)
|
||||||
|
@ -9,16 +9,16 @@
|
|||||||
import 'dart:core' as $core;
|
import 'dart:core' as $core;
|
||||||
import 'package:protobuf/protobuf.dart' as $pb;
|
import 'package:protobuf/protobuf.dart' as $pb;
|
||||||
|
|
||||||
class WsModule extends $pb.ProtobufEnum {
|
class WSModule extends $pb.ProtobufEnum {
|
||||||
static const WsModule Doc = WsModule._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Doc');
|
static const WSModule Doc = WSModule._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Doc');
|
||||||
|
|
||||||
static const $core.List<WsModule> values = <WsModule> [
|
static const $core.List<WSModule> values = <WSModule> [
|
||||||
Doc,
|
Doc,
|
||||||
];
|
];
|
||||||
|
|
||||||
static final $core.Map<$core.int, WsModule> _byValue = $pb.ProtobufEnum.initByValue(values);
|
static final $core.Map<$core.int, WSModule> _byValue = $pb.ProtobufEnum.initByValue(values);
|
||||||
static WsModule? valueOf($core.int value) => _byValue[value];
|
static WSModule? valueOf($core.int value) => _byValue[value];
|
||||||
|
|
||||||
const WsModule._($core.int v, $core.String n) : super(v, n);
|
const WSModule._($core.int v, $core.String n) : super(v, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,24 +8,24 @@
|
|||||||
import 'dart:core' as $core;
|
import 'dart:core' as $core;
|
||||||
import 'dart:convert' as $convert;
|
import 'dart:convert' as $convert;
|
||||||
import 'dart:typed_data' as $typed_data;
|
import 'dart:typed_data' as $typed_data;
|
||||||
@$core.Deprecated('Use wsModuleDescriptor instead')
|
@$core.Deprecated('Use wSModuleDescriptor instead')
|
||||||
const WsModule$json = const {
|
const WSModule$json = const {
|
||||||
'1': 'WsModule',
|
'1': 'WSModule',
|
||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'Doc', '2': 0},
|
const {'1': 'Doc', '2': 0},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `WsModule`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
/// Descriptor for `WSModule`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||||
final $typed_data.Uint8List wsModuleDescriptor = $convert.base64Decode('CghXc01vZHVsZRIHCgNEb2MQAA==');
|
final $typed_data.Uint8List wSModuleDescriptor = $convert.base64Decode('CghXU01vZHVsZRIHCgNEb2MQAA==');
|
||||||
@$core.Deprecated('Use wsMessageDescriptor instead')
|
@$core.Deprecated('Use wSMessageDescriptor instead')
|
||||||
const WsMessage$json = const {
|
const WSMessage$json = const {
|
||||||
'1': 'WsMessage',
|
'1': 'WSMessage',
|
||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'module', '3': 1, '4': 1, '5': 14, '6': '.WsModule', '10': 'module'},
|
const {'1': 'module', '3': 1, '4': 1, '5': 14, '6': '.WSModule', '10': 'module'},
|
||||||
const {'1': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'},
|
const {'1': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `WsMessage`. Decode as a `google.protobuf.DescriptorProto`.
|
/// Descriptor for `WSMessage`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
final $typed_data.Uint8List wsMessageDescriptor = $convert.base64Decode('CglXc01lc3NhZ2USIQoGbW9kdWxlGAEgASgOMgkuV3NNb2R1bGVSBm1vZHVsZRISCgRkYXRhGAIgASgMUgRkYXRh');
|
final $typed_data.Uint8List wSMessageDescriptor = $convert.base64Decode('CglXU01lc3NhZ2USIQoGbW9kdWxlGAEgASgOMgkuV1NNb2R1bGVSBm1vZHVsZRISCgRkYXRhGAIgASgMUgRkYXRh');
|
||||||
|
@ -0,0 +1,207 @@
|
|||||||
|
use async_stream::stream;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use flowy_collaboration::{
|
||||||
|
core::document::{history::UndoResult, Document},
|
||||||
|
errors::CollaborateError,
|
||||||
|
};
|
||||||
|
use flowy_error::FlowyError;
|
||||||
|
use futures::stream::StreamExt;
|
||||||
|
use lib_ot::{
|
||||||
|
core::{Interval, OperationTransformable},
|
||||||
|
revision::{RevId, Revision},
|
||||||
|
rich_text::{RichTextAttribute, RichTextDelta},
|
||||||
|
};
|
||||||
|
use std::{convert::TryFrom, sync::Arc};
|
||||||
|
use tokio::sync::{mpsc, oneshot, RwLock};
|
||||||
|
|
||||||
|
pub(crate) struct EditCommandQueue {
|
||||||
|
doc_id: String,
|
||||||
|
document: Arc<RwLock<Document>>,
|
||||||
|
receiver: Option<mpsc::UnboundedReceiver<EditCommand>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EditCommandQueue {
|
||||||
|
pub(crate) fn new(doc_id: &str, delta: RichTextDelta, receiver: mpsc::UnboundedReceiver<EditCommand>) -> Self {
|
||||||
|
let document = Arc::new(RwLock::new(Document::from_delta(delta)));
|
||||||
|
Self {
|
||||||
|
doc_id: doc_id.to_owned(),
|
||||||
|
document,
|
||||||
|
receiver: Some(receiver),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn run(mut self) {
|
||||||
|
let mut receiver = self.receiver.take().expect("Should only call once");
|
||||||
|
let stream = stream! {
|
||||||
|
loop {
|
||||||
|
match receiver.recv().await {
|
||||||
|
Some(msg) => yield msg,
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
stream
|
||||||
|
.for_each(|msg| async {
|
||||||
|
match self.handle_message(msg).await {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => tracing::debug!("[EditCommandQueue]: {}", e),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_message(&self, msg: EditCommand) -> Result<(), FlowyError> {
|
||||||
|
match msg {
|
||||||
|
EditCommand::ComposeDelta { delta, ret } => {
|
||||||
|
let result = self.composed_delta(delta).await;
|
||||||
|
let _ = ret.send(result);
|
||||||
|
},
|
||||||
|
EditCommand::ProcessRemoteRevision { bytes, ret } => {
|
||||||
|
let f = || async {
|
||||||
|
let revision = Revision::try_from(bytes)?;
|
||||||
|
let delta = RichTextDelta::from_bytes(&revision.delta_data)?;
|
||||||
|
let server_rev_id: RevId = revision.rev_id.into();
|
||||||
|
let read_guard = self.document.read().await;
|
||||||
|
let (server_prime, client_prime) = read_guard.delta().transform(&delta)?;
|
||||||
|
drop(read_guard);
|
||||||
|
|
||||||
|
let transform_delta = TransformDeltas {
|
||||||
|
client_prime,
|
||||||
|
server_prime,
|
||||||
|
server_rev_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok::<TransformDeltas, CollaborateError>(transform_delta)
|
||||||
|
};
|
||||||
|
let _ = ret.send(f().await);
|
||||||
|
},
|
||||||
|
EditCommand::Insert { index, data, ret } => {
|
||||||
|
let mut write_guard = self.document.write().await;
|
||||||
|
let delta = write_guard.insert(index, data)?;
|
||||||
|
let md5 = write_guard.md5();
|
||||||
|
let _ = ret.send(Ok((delta, md5)));
|
||||||
|
},
|
||||||
|
EditCommand::Delete { interval, ret } => {
|
||||||
|
let mut write_guard = self.document.write().await;
|
||||||
|
let delta = write_guard.delete(interval)?;
|
||||||
|
let md5 = write_guard.md5();
|
||||||
|
let _ = ret.send(Ok((delta, md5)));
|
||||||
|
},
|
||||||
|
EditCommand::Format {
|
||||||
|
interval,
|
||||||
|
attribute,
|
||||||
|
ret,
|
||||||
|
} => {
|
||||||
|
let mut write_guard = self.document.write().await;
|
||||||
|
let delta = write_guard.format(interval, attribute)?;
|
||||||
|
let md5 = write_guard.md5();
|
||||||
|
let _ = ret.send(Ok((delta, md5)));
|
||||||
|
},
|
||||||
|
EditCommand::Replace { interval, data, ret } => {
|
||||||
|
let mut write_guard = self.document.write().await;
|
||||||
|
let delta = write_guard.replace(interval, data)?;
|
||||||
|
let md5 = write_guard.md5();
|
||||||
|
let _ = ret.send(Ok((delta, md5)));
|
||||||
|
},
|
||||||
|
EditCommand::CanUndo { ret } => {
|
||||||
|
let _ = ret.send(self.document.read().await.can_undo());
|
||||||
|
},
|
||||||
|
EditCommand::CanRedo { ret } => {
|
||||||
|
let _ = ret.send(self.document.read().await.can_redo());
|
||||||
|
},
|
||||||
|
EditCommand::Undo { ret } => {
|
||||||
|
let result = self.document.write().await.undo();
|
||||||
|
let _ = ret.send(result);
|
||||||
|
},
|
||||||
|
EditCommand::Redo { ret } => {
|
||||||
|
let result = self.document.write().await.redo();
|
||||||
|
let _ = ret.send(result);
|
||||||
|
},
|
||||||
|
EditCommand::ReadDoc { ret } => {
|
||||||
|
let data = self.document.read().await.to_json();
|
||||||
|
let _ = ret.send(Ok(data));
|
||||||
|
},
|
||||||
|
EditCommand::ReadDocDelta { ret } => {
|
||||||
|
let delta = self.document.read().await.delta().clone();
|
||||||
|
let _ = ret.send(Ok(delta));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip(self, delta), fields(compose_result), err)]
|
||||||
|
async fn composed_delta(&self, delta: RichTextDelta) -> Result<String, CollaborateError> {
|
||||||
|
// tracing::debug!("{:?} thread handle_message", thread::current(),);
|
||||||
|
let mut document = self.document.write().await;
|
||||||
|
tracing::Span::current().record(
|
||||||
|
"composed_delta",
|
||||||
|
&format!("doc_id:{} - {}", &self.doc_id, delta.to_json()).as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = document.compose_delta(delta)?;
|
||||||
|
let md5 = document.md5();
|
||||||
|
drop(document);
|
||||||
|
|
||||||
|
Ok(md5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type Ret<T> = oneshot::Sender<Result<T, CollaborateError>>;
|
||||||
|
pub(crate) type NewDelta = (RichTextDelta, String);
|
||||||
|
pub(crate) type DocumentMD5 = String;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) enum EditCommand {
|
||||||
|
ComposeDelta {
|
||||||
|
delta: RichTextDelta,
|
||||||
|
ret: Ret<DocumentMD5>,
|
||||||
|
},
|
||||||
|
ProcessRemoteRevision {
|
||||||
|
bytes: Bytes,
|
||||||
|
ret: Ret<TransformDeltas>,
|
||||||
|
},
|
||||||
|
Insert {
|
||||||
|
index: usize,
|
||||||
|
data: String,
|
||||||
|
ret: Ret<NewDelta>,
|
||||||
|
},
|
||||||
|
Delete {
|
||||||
|
interval: Interval,
|
||||||
|
ret: Ret<NewDelta>,
|
||||||
|
},
|
||||||
|
Format {
|
||||||
|
interval: Interval,
|
||||||
|
attribute: RichTextAttribute,
|
||||||
|
ret: Ret<NewDelta>,
|
||||||
|
},
|
||||||
|
|
||||||
|
Replace {
|
||||||
|
interval: Interval,
|
||||||
|
data: String,
|
||||||
|
ret: Ret<NewDelta>,
|
||||||
|
},
|
||||||
|
CanUndo {
|
||||||
|
ret: oneshot::Sender<bool>,
|
||||||
|
},
|
||||||
|
CanRedo {
|
||||||
|
ret: oneshot::Sender<bool>,
|
||||||
|
},
|
||||||
|
Undo {
|
||||||
|
ret: Ret<UndoResult>,
|
||||||
|
},
|
||||||
|
Redo {
|
||||||
|
ret: Ret<UndoResult>,
|
||||||
|
},
|
||||||
|
ReadDoc {
|
||||||
|
ret: Ret<String>,
|
||||||
|
},
|
||||||
|
ReadDocDelta {
|
||||||
|
ret: Ret<RichTextDelta>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TransformDeltas {
|
||||||
|
pub client_prime: RichTextDelta,
|
||||||
|
pub server_prime: RichTextDelta,
|
||||||
|
pub server_rev_id: RevId,
|
||||||
|
}
|
@ -0,0 +1,297 @@
|
|||||||
|
use crate::services::doc::{DocumentWebSocket, DocumentWsHandler, SYNC_INTERVAL_IN_MILLIS};
|
||||||
|
use async_stream::stream;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use flowy_collaboration::{
|
||||||
|
entities::ws::{DocumentWSData, DocumentWSDataType},
|
||||||
|
Revision,
|
||||||
|
};
|
||||||
|
use flowy_error::{internal_error, FlowyError, FlowyResult};
|
||||||
|
use futures::stream::StreamExt;
|
||||||
|
use lib_infra::future::FutureResult;
|
||||||
|
use lib_ot::revision::{RevId, RevisionRange};
|
||||||
|
use lib_ws::WSConnectState;
|
||||||
|
use std::{convert::TryFrom, sync::Arc};
|
||||||
|
use tokio::{
|
||||||
|
sync::{
|
||||||
|
broadcast,
|
||||||
|
mpsc,
|
||||||
|
mpsc::{UnboundedReceiver, UnboundedSender},
|
||||||
|
},
|
||||||
|
task::spawn_blocking,
|
||||||
|
time::{interval, Duration},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) struct WebSocketManager {
|
||||||
|
doc_id: String,
|
||||||
|
data_provider: Arc<dyn DocumentSinkDataProvider>,
|
||||||
|
stream_consumer: Arc<dyn DocumentWebSocketSteamConsumer>,
|
||||||
|
ws: Arc<dyn DocumentWebSocket>,
|
||||||
|
ws_msg_tx: UnboundedSender<DocumentWSData>,
|
||||||
|
ws_msg_rx: Option<UnboundedReceiver<DocumentWSData>>,
|
||||||
|
stop_sync_tx: SinkStopTx,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebSocketManager {
|
||||||
|
pub(crate) fn new(
|
||||||
|
doc_id: &str,
|
||||||
|
ws: Arc<dyn DocumentWebSocket>,
|
||||||
|
data_provider: Arc<dyn DocumentSinkDataProvider>,
|
||||||
|
stream_consumer: Arc<dyn DocumentWebSocketSteamConsumer>,
|
||||||
|
) -> Self {
|
||||||
|
let (ws_msg_tx, ws_msg_rx) = mpsc::unbounded_channel();
|
||||||
|
let (stop_sync_tx, _) = tokio::sync::broadcast::channel(2);
|
||||||
|
let doc_id = doc_id.to_string();
|
||||||
|
let mut manager = WebSocketManager {
|
||||||
|
doc_id,
|
||||||
|
data_provider,
|
||||||
|
stream_consumer,
|
||||||
|
ws,
|
||||||
|
ws_msg_tx,
|
||||||
|
ws_msg_rx: Some(ws_msg_rx),
|
||||||
|
stop_sync_tx,
|
||||||
|
};
|
||||||
|
manager.start_sync();
|
||||||
|
manager
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_sync(&mut self) {
|
||||||
|
let ws_msg_rx = self.ws_msg_rx.take().expect("Only take once");
|
||||||
|
let sink = DocumentWebSocketSink::new(
|
||||||
|
&self.doc_id,
|
||||||
|
self.data_provider.clone(),
|
||||||
|
self.ws.clone(),
|
||||||
|
self.stop_sync_tx.subscribe(),
|
||||||
|
);
|
||||||
|
let stream = DocumentWebSocketStream::new(
|
||||||
|
&self.doc_id,
|
||||||
|
self.stream_consumer.clone(),
|
||||||
|
ws_msg_rx,
|
||||||
|
self.ws.clone(),
|
||||||
|
self.stop_sync_tx.subscribe(),
|
||||||
|
);
|
||||||
|
tokio::spawn(sink.run());
|
||||||
|
tokio::spawn(stream.run());
|
||||||
|
self.notify_user_conn();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn stop(&self) {
|
||||||
|
if self.stop_sync_tx.send(()).is_ok() {
|
||||||
|
tracing::debug!("{} stop sync", self.doc_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip(self))]
|
||||||
|
fn notify_user_conn(&self) {
|
||||||
|
// let rev_id: RevId = self.rev_manager.rev_id().into();
|
||||||
|
// if let Ok(user_id) = self.user.user_id() {
|
||||||
|
// let action = OpenDocAction::new(&user_id, &self.doc_id, &rev_id,
|
||||||
|
// &self.ws_sender); let strategy =
|
||||||
|
// ExponentialBackoff::from_millis(50).take(3); let retry =
|
||||||
|
// Retry::spawn(strategy, action); tokio::spawn(async move {
|
||||||
|
// match retry.await {
|
||||||
|
// Ok(_) => log::debug!("Notify open doc success"),
|
||||||
|
// Err(e) => log::error!("Notify open doc failed: {}", e),
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocumentWsHandler for WebSocketManager {
|
||||||
|
fn receive(&self, doc_data: DocumentWSData) {
|
||||||
|
match self.ws_msg_tx.send(doc_data) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => tracing::error!("❌Propagate ws message failed. {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect_state_changed(&self, state: &WSConnectState) {
|
||||||
|
match state {
|
||||||
|
WSConnectState::Init => {},
|
||||||
|
WSConnectState::Connecting => {},
|
||||||
|
WSConnectState::Connected => self.notify_user_conn(),
|
||||||
|
WSConnectState::Disconnected => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DocumentWebSocketSteamConsumer: Send + Sync {
|
||||||
|
fn receive_push_revision(&self, bytes: Bytes) -> FutureResult<(), FlowyError>;
|
||||||
|
fn make_revision_from_range(&self, range: RevisionRange) -> FutureResult<Revision, FlowyError>;
|
||||||
|
fn ack_revision(&self, rev_id: i64) -> FutureResult<(), FlowyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct DocumentWebSocketStream {
|
||||||
|
doc_id: String,
|
||||||
|
consumer: Arc<dyn DocumentWebSocketSteamConsumer>,
|
||||||
|
ws_msg_rx: Option<mpsc::UnboundedReceiver<DocumentWSData>>,
|
||||||
|
ws_sender: Arc<dyn DocumentWebSocket>,
|
||||||
|
stop_rx: Option<SinkStopRx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocumentWebSocketStream {
|
||||||
|
pub(crate) fn new(
|
||||||
|
doc_id: &str,
|
||||||
|
consumer: Arc<dyn DocumentWebSocketSteamConsumer>,
|
||||||
|
ws_msg_rx: mpsc::UnboundedReceiver<DocumentWSData>,
|
||||||
|
ws_sender: Arc<dyn DocumentWebSocket>,
|
||||||
|
stop_rx: SinkStopRx,
|
||||||
|
) -> Self {
|
||||||
|
DocumentWebSocketStream {
|
||||||
|
doc_id: doc_id.to_owned(),
|
||||||
|
consumer,
|
||||||
|
ws_msg_rx: Some(ws_msg_rx),
|
||||||
|
ws_sender,
|
||||||
|
stop_rx: Some(stop_rx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run(mut self) {
|
||||||
|
let mut receiver = self.ws_msg_rx.take().expect("Only take once");
|
||||||
|
let mut stop_rx = self.stop_rx.take().expect("Only take once");
|
||||||
|
let doc_id = self.doc_id.clone();
|
||||||
|
let stream = stream! {
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
result = receiver.recv() => {
|
||||||
|
match result {
|
||||||
|
Some(msg) => {
|
||||||
|
yield msg
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
tracing::debug!("[DocumentStream:{}] loop exit", doc_id);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ = stop_rx.recv() => {
|
||||||
|
tracing::debug!("[DocumentStream:{}] loop exit", doc_id);
|
||||||
|
break
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
stream
|
||||||
|
.for_each(|msg| async {
|
||||||
|
match self.handle_message(msg).await {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => log::error!("[DocumentStream:{}] error: {}", self.doc_id, e),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_message(&self, msg: DocumentWSData) -> FlowyResult<()> {
|
||||||
|
let DocumentWSData {
|
||||||
|
doc_id: _,
|
||||||
|
ty,
|
||||||
|
data,
|
||||||
|
id: _,
|
||||||
|
} = msg;
|
||||||
|
let bytes = spawn_blocking(move || Bytes::from(data))
|
||||||
|
.await
|
||||||
|
.map_err(internal_error)?;
|
||||||
|
|
||||||
|
tracing::debug!("[DocumentStream]: receives new message: {:?}", ty);
|
||||||
|
match ty {
|
||||||
|
DocumentWSDataType::PushRev => {
|
||||||
|
let _ = self.consumer.receive_push_revision(bytes).await?;
|
||||||
|
},
|
||||||
|
DocumentWSDataType::PullRev => {
|
||||||
|
let range = RevisionRange::try_from(bytes)?;
|
||||||
|
let revision = self.consumer.make_revision_from_range(range).await?;
|
||||||
|
let _ = self.ws_sender.send(revision.into());
|
||||||
|
},
|
||||||
|
DocumentWSDataType::Acked => {
|
||||||
|
let rev_id = RevId::try_from(bytes)?;
|
||||||
|
let _ = self.consumer.ack_revision(rev_id.into()).await;
|
||||||
|
},
|
||||||
|
DocumentWSDataType::UserConnect => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type Tick = ();
|
||||||
|
pub(crate) type SinkStopRx = broadcast::Receiver<()>;
|
||||||
|
pub(crate) type SinkStopTx = broadcast::Sender<()>;
|
||||||
|
|
||||||
|
pub trait DocumentSinkDataProvider: Send + Sync {
|
||||||
|
fn next(&self) -> FutureResult<Option<DocumentWSData>, FlowyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct DocumentWebSocketSink {
|
||||||
|
provider: Arc<dyn DocumentSinkDataProvider>,
|
||||||
|
ws_sender: Arc<dyn DocumentWebSocket>,
|
||||||
|
stop_rx: Option<SinkStopRx>,
|
||||||
|
doc_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocumentWebSocketSink {
|
||||||
|
pub(crate) fn new(
|
||||||
|
doc_id: &str,
|
||||||
|
provider: Arc<dyn DocumentSinkDataProvider>,
|
||||||
|
ws_sender: Arc<dyn DocumentWebSocket>,
|
||||||
|
stop_rx: SinkStopRx,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
provider,
|
||||||
|
ws_sender,
|
||||||
|
stop_rx: Some(stop_rx),
|
||||||
|
doc_id: doc_id.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run(mut self) {
|
||||||
|
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||||
|
let mut stop_rx = self.stop_rx.take().expect("Only take once");
|
||||||
|
let doc_id = self.doc_id.clone();
|
||||||
|
tokio::spawn(tick(tx));
|
||||||
|
let stream = stream! {
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
result = rx.recv() => {
|
||||||
|
match result {
|
||||||
|
Some(msg) => yield msg,
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ = stop_rx.recv() => {
|
||||||
|
tracing::debug!("[DocumentSink:{}] loop exit", doc_id);
|
||||||
|
break
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
stream
|
||||||
|
.for_each(|_| async {
|
||||||
|
match self.send_next_revision().await {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => log::error!("[DocumentSink]: send msg failed, {:?}", e),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_next_revision(&self) -> FlowyResult<()> {
|
||||||
|
match self.provider.next().await? {
|
||||||
|
None => {
|
||||||
|
tracing::debug!("Finish synchronizing revisions");
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
Some(data) => {
|
||||||
|
self.ws_sender.send(data).map_err(internal_error)
|
||||||
|
// let _ = tokio::time::timeout(Duration::from_millis(2000),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn tick(sender: mpsc::UnboundedSender<Tick>) {
|
||||||
|
let mut interval = interval(Duration::from_millis(SYNC_INTERVAL_IN_MILLIS));
|
||||||
|
while sender.send(()).is_ok() {
|
||||||
|
interval.tick().await;
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ use crate::{errors::FlowyError, module::DocumentUser, services::doc::*};
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use flowy_collaboration::{
|
use flowy_collaboration::{
|
||||||
core::document::history::UndoResult,
|
core::document::history::UndoResult,
|
||||||
entities::{doc::DocDelta, ws::WsDocumentData},
|
entities::{doc::DocDelta, ws::DocumentWSData},
|
||||||
errors::CollaborateResult,
|
errors::CollaborateResult,
|
||||||
};
|
};
|
||||||
use flowy_database::ConnectionPool;
|
use flowy_database::ConnectionPool;
|
||||||
@ -13,16 +13,16 @@ use lib_ot::{
|
|||||||
revision::{RevId, RevType, Revision, RevisionRange},
|
revision::{RevId, RevType, Revision, RevisionRange},
|
||||||
rich_text::{RichTextAttribute, RichTextDelta},
|
rich_text::{RichTextAttribute, RichTextDelta},
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use parking_lot::RwLock;
|
||||||
|
use std::{collections::VecDeque, sync::Arc};
|
||||||
use tokio::sync::{mpsc, mpsc::UnboundedSender, oneshot};
|
use tokio::sync::{mpsc, mpsc::UnboundedSender, oneshot};
|
||||||
|
type SinkVec = Arc<RwLock<VecDeque<DocumentWSData>>>;
|
||||||
pub type DocId = String;
|
|
||||||
|
|
||||||
pub struct ClientDocEditor {
|
pub struct ClientDocEditor {
|
||||||
pub doc_id: DocId,
|
pub doc_id: String,
|
||||||
rev_manager: Arc<RevisionManager>,
|
rev_manager: Arc<RevisionManager>,
|
||||||
ws_manager: Arc<WebSocketManager>,
|
ws_manager: Arc<WebSocketManager>,
|
||||||
edit_cmd_tx: UnboundedSender<EditCommand>,
|
edit_cmd_tx: UnboundedSender<EditCommand>,
|
||||||
|
sink_vec: SinkVec,
|
||||||
user: Arc<dyn DocumentUser>,
|
user: Arc<dyn DocumentUser>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,15 +38,17 @@ impl ClientDocEditor {
|
|||||||
let edit_cmd_tx = spawn_edit_queue(doc_id, delta, pool.clone());
|
let edit_cmd_tx = spawn_edit_queue(doc_id, delta, pool.clone());
|
||||||
let doc_id = doc_id.to_string();
|
let doc_id = doc_id.to_string();
|
||||||
let rev_manager = Arc::new(rev_manager);
|
let rev_manager = Arc::new(rev_manager);
|
||||||
|
let sink_vec = Arc::new(RwLock::new(VecDeque::new()));
|
||||||
let data_provider = Arc::new(DocumentSinkDataProviderAdapter {
|
let data_provider = Arc::new(DocumentSinkDataProviderAdapter {
|
||||||
rev_manager: rev_manager.clone(),
|
rev_manager: rev_manager.clone(),
|
||||||
|
sink_vec: sink_vec.clone(),
|
||||||
});
|
});
|
||||||
let stream_consumer = Arc::new(DocumentWebSocketSteamConsumerAdapter {
|
let stream_consumer = Arc::new(DocumentWebSocketSteamConsumerAdapter {
|
||||||
doc_id: doc_id.clone(),
|
doc_id: doc_id.clone(),
|
||||||
edit_cmd_tx: edit_cmd_tx.clone(),
|
edit_cmd_tx: edit_cmd_tx.clone(),
|
||||||
rev_manager: rev_manager.clone(),
|
rev_manager: rev_manager.clone(),
|
||||||
user: user.clone(),
|
user: user.clone(),
|
||||||
|
sink_vec: sink_vec.clone(),
|
||||||
});
|
});
|
||||||
let ws_manager = Arc::new(WebSocketManager::new(&doc_id, ws, data_provider, stream_consumer));
|
let ws_manager = Arc::new(WebSocketManager::new(&doc_id, ws, data_provider, stream_consumer));
|
||||||
let editor = Arc::new(Self {
|
let editor = Arc::new(Self {
|
||||||
@ -54,6 +56,7 @@ impl ClientDocEditor {
|
|||||||
rev_manager,
|
rev_manager,
|
||||||
ws_manager,
|
ws_manager,
|
||||||
edit_cmd_tx,
|
edit_cmd_tx,
|
||||||
|
sink_vec,
|
||||||
user,
|
user,
|
||||||
});
|
});
|
||||||
Ok(editor)
|
Ok(editor)
|
||||||
@ -199,6 +202,7 @@ struct DocumentWebSocketSteamConsumerAdapter {
|
|||||||
edit_cmd_tx: UnboundedSender<EditCommand>,
|
edit_cmd_tx: UnboundedSender<EditCommand>,
|
||||||
rev_manager: Arc<RevisionManager>,
|
rev_manager: Arc<RevisionManager>,
|
||||||
user: Arc<dyn DocumentUser>,
|
user: Arc<dyn DocumentUser>,
|
||||||
|
sink_vec: SinkVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentWebSocketSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
|
impl DocumentWebSocketSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
|
||||||
@ -233,12 +237,16 @@ impl DocumentWebSocketSteamConsumer for DocumentWebSocketSteamConsumerAdapter {
|
|||||||
|
|
||||||
struct DocumentSinkDataProviderAdapter {
|
struct DocumentSinkDataProviderAdapter {
|
||||||
rev_manager: Arc<RevisionManager>,
|
rev_manager: Arc<RevisionManager>,
|
||||||
|
sink_vec: SinkVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentSinkDataProvider for DocumentSinkDataProviderAdapter {
|
impl DocumentSinkDataProvider for DocumentSinkDataProviderAdapter {
|
||||||
fn next(&self) -> FutureResult<Option<WsDocumentData>, FlowyError> {
|
fn next(&self) -> FutureResult<Option<DocumentWSData>, FlowyError> {
|
||||||
let rev_manager = self.rev_manager.clone();
|
let rev_manager = self.rev_manager.clone();
|
||||||
|
let sink_vec = self.sink_vec.clone();
|
||||||
|
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
|
if sink_vec.read().is_empty() {
|
||||||
match rev_manager.next_sync_revision().await? {
|
match rev_manager.next_sync_revision().await? {
|
||||||
Some(rev) => {
|
Some(rev) => {
|
||||||
tracing::debug!("[DocumentSinkDataProvider]: revision: {}:{:?}", rev.doc_id, rev.rev_id);
|
tracing::debug!("[DocumentSinkDataProvider]: revision: {}:{:?}", rev.doc_id, rev.rev_id);
|
||||||
@ -246,6 +254,12 @@ impl DocumentSinkDataProvider for DocumentSinkDataProviderAdapter {
|
|||||||
},
|
},
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
match sink_vec.read().front() {
|
||||||
|
None => Ok(None),
|
||||||
|
Some(data) => Ok(Some(data.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
use crate::errors::FlowyError;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use flowy_collaboration::entities::ws::DocumentWSData;
|
||||||
|
use lib_ws::WSConnectState;
|
||||||
|
use std::{convert::TryInto, sync::Arc};
|
||||||
|
|
||||||
|
pub(crate) trait DocumentWsHandler: Send + Sync {
|
||||||
|
fn receive(&self, data: DocumentWSData);
|
||||||
|
fn connect_state_changed(&self, state: &WSConnectState);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type WsStateReceiver = tokio::sync::broadcast::Receiver<WSConnectState>;
|
||||||
|
pub trait DocumentWebSocket: Send + Sync {
|
||||||
|
fn send(&self, data: DocumentWSData) -> Result<(), FlowyError>;
|
||||||
|
fn subscribe_state_changed(&self) -> WsStateReceiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DocumentWsHandlers {
|
||||||
|
ws: Arc<dyn DocumentWebSocket>,
|
||||||
|
// key: the document id
|
||||||
|
handlers: Arc<DashMap<String, Arc<dyn DocumentWsHandler>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocumentWsHandlers {
|
||||||
|
pub fn new(ws: Arc<dyn DocumentWebSocket>) -> Self {
|
||||||
|
let handlers: Arc<DashMap<String, Arc<dyn DocumentWsHandler>>> = Arc::new(DashMap::new());
|
||||||
|
Self { ws, handlers }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn init(&self) { listen_ws_state_changed(self.ws.clone(), self.handlers.clone()); }
|
||||||
|
|
||||||
|
pub(crate) fn register_handler(&self, id: &str, handler: Arc<dyn DocumentWsHandler>) {
|
||||||
|
if self.handlers.contains_key(id) {
|
||||||
|
log::error!("Duplicate handler registered for {:?}", id);
|
||||||
|
}
|
||||||
|
self.handlers.insert(id.to_string(), handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn remove_handler(&self, id: &str) { self.handlers.remove(id); }
|
||||||
|
|
||||||
|
pub fn did_receive_data(&self, data: Bytes) {
|
||||||
|
let data: DocumentWSData = data.try_into().unwrap();
|
||||||
|
match self.handlers.get(&data.doc_id) {
|
||||||
|
None => {
|
||||||
|
log::error!("Can't find any source handler for {:?}", data.doc_id);
|
||||||
|
},
|
||||||
|
Some(handler) => {
|
||||||
|
handler.receive(data);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ws(&self) -> Arc<dyn DocumentWebSocket> { self.ws.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip(ws, handlers))]
|
||||||
|
fn listen_ws_state_changed(ws: Arc<dyn DocumentWebSocket>, handlers: Arc<DashMap<String, Arc<dyn DocumentWsHandler>>>) {
|
||||||
|
let mut notify = ws.subscribe_state_changed();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
while let Ok(state) = notify.recv().await {
|
||||||
|
handlers.iter().for_each(|handle| {
|
||||||
|
handle.value().connect_state_changed(&state);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
use crate::services::ws::{FlowyError, FlowyWebSocket, FlowyWsSender, WsConnectState, WsMessage, WsMessageReceiver};
|
use crate::services::ws::{FlowyError, FlowyWebSocket, FlowyWsSender, WSConnectState, WSMessage, WSMessageReceiver};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use flowy_collaboration::{
|
use flowy_collaboration::{
|
||||||
core::sync::{RevisionUser, ServerDocManager, ServerDocPersistence, SyncResponse},
|
core::sync::{RevisionUser, ServerDocManager, ServerDocPersistence, SyncResponse},
|
||||||
entities::{
|
entities::{
|
||||||
doc::Doc,
|
doc::Doc,
|
||||||
ws::{WsDocumentData, WsDocumentDataType},
|
ws::{DocumentWSData, DocumentWSDataType},
|
||||||
},
|
},
|
||||||
errors::CollaborateError,
|
errors::CollaborateError,
|
||||||
Revision,
|
Revision,
|
||||||
@ -13,7 +13,7 @@ use flowy_collaboration::{
|
|||||||
};
|
};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use lib_infra::future::{FutureResult, FutureResultSend};
|
use lib_infra::future::{FutureResult, FutureResultSend};
|
||||||
use lib_ws::WsModule;
|
use lib_ws::WSModule;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::{
|
use std::{
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
@ -22,9 +22,9 @@ use std::{
|
|||||||
use tokio::sync::{broadcast, broadcast::Receiver, mpsc};
|
use tokio::sync::{broadcast, broadcast::Receiver, mpsc};
|
||||||
|
|
||||||
pub struct MockWebSocket {
|
pub struct MockWebSocket {
|
||||||
handlers: DashMap<WsModule, Arc<dyn WsMessageReceiver>>,
|
handlers: DashMap<WSModule, Arc<dyn WSMessageReceiver>>,
|
||||||
state_sender: broadcast::Sender<WsConnectState>,
|
state_sender: broadcast::Sender<WSConnectState>,
|
||||||
ws_sender: broadcast::Sender<WsMessage>,
|
ws_sender: broadcast::Sender<WSMessage>,
|
||||||
is_stop: RwLock<bool>,
|
is_stop: RwLock<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ impl FlowyWebSocket for Arc<MockWebSocket> {
|
|||||||
if *cloned_ws.is_stop.read() {
|
if *cloned_ws.is_stop.read() {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else {
|
} else {
|
||||||
let ws_data = WsDocumentData::try_from(Bytes::from(message.data.clone())).unwrap();
|
let ws_data = DocumentWSData::try_from(Bytes::from(message.data.clone())).unwrap();
|
||||||
let mut rx = DOC_SERVER.handle_ws_data(ws_data).await;
|
let mut rx = DOC_SERVER.handle_ws_data(ws_data).await;
|
||||||
let new_ws_message = rx.recv().await.unwrap();
|
let new_ws_message = rx.recv().await.unwrap();
|
||||||
match cloned_ws.handlers.get(&new_ws_message.module) {
|
match cloned_ws.handlers.get(&new_ws_message.module) {
|
||||||
@ -75,11 +75,11 @@ impl FlowyWebSocket for Arc<MockWebSocket> {
|
|||||||
FutureResult::new(async { Ok(()) })
|
FutureResult::new(async { Ok(()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscribe_connect_state(&self) -> Receiver<WsConnectState> { self.state_sender.subscribe() }
|
fn subscribe_connect_state(&self) -> Receiver<WSConnectState> { self.state_sender.subscribe() }
|
||||||
|
|
||||||
fn reconnect(&self, _count: usize) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) }
|
fn reconnect(&self, _count: usize) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) }
|
||||||
|
|
||||||
fn add_message_receiver(&self, handler: Arc<dyn WsMessageReceiver>) -> Result<(), FlowyError> {
|
fn add_message_receiver(&self, handler: Arc<dyn WSMessageReceiver>) -> Result<(), FlowyError> {
|
||||||
let source = handler.source();
|
let source = handler.source();
|
||||||
if self.handlers.contains_key(&source) {
|
if self.handlers.contains_key(&source) {
|
||||||
tracing::error!("WsSource's {:?} is already registered", source);
|
tracing::error!("WsSource's {:?} is already registered", source);
|
||||||
@ -108,13 +108,13 @@ impl std::default::Default for MockDocServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MockDocServer {
|
impl MockDocServer {
|
||||||
async fn handle_ws_data(&self, ws_data: WsDocumentData) -> mpsc::Receiver<WsMessage> {
|
async fn handle_ws_data(&self, ws_data: DocumentWSData) -> mpsc::Receiver<WSMessage> {
|
||||||
let bytes = Bytes::from(ws_data.data);
|
let bytes = Bytes::from(ws_data.data);
|
||||||
match ws_data.ty {
|
match ws_data.ty {
|
||||||
WsDocumentDataType::Acked => {
|
DocumentWSDataType::Acked => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
},
|
},
|
||||||
WsDocumentDataType::PushRev => {
|
DocumentWSDataType::PushRev => {
|
||||||
let revision = Revision::try_from(bytes).unwrap();
|
let revision = Revision::try_from(bytes).unwrap();
|
||||||
let handler = match self.manager.get(&revision.doc_id).await {
|
let handler = match self.manager.get(&revision.doc_id).await {
|
||||||
None => self.manager.create_doc(revision.clone()).await.unwrap(),
|
None => self.manager.create_doc(revision.clone()).await.unwrap(),
|
||||||
@ -129,10 +129,10 @@ impl MockDocServer {
|
|||||||
handler.apply_revision(Arc::new(user), revision).await.unwrap();
|
handler.apply_revision(Arc::new(user), revision).await.unwrap();
|
||||||
rx
|
rx
|
||||||
},
|
},
|
||||||
WsDocumentDataType::PullRev => {
|
DocumentWSDataType::PullRev => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
},
|
},
|
||||||
WsDocumentDataType::UserConnect => {
|
DocumentWSDataType::UserConnect => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -184,7 +184,7 @@ impl ServerDocPersistence for MockDocServerPersistence {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct MockDocUser {
|
struct MockDocUser {
|
||||||
user_id: String,
|
user_id: String,
|
||||||
tx: mpsc::Sender<WsMessage>,
|
tx: mpsc::Sender<WSMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RevisionUser for MockDocUser {
|
impl RevisionUser for MockDocUser {
|
||||||
@ -196,24 +196,24 @@ impl RevisionUser for MockDocUser {
|
|||||||
match resp {
|
match resp {
|
||||||
SyncResponse::Pull(data) => {
|
SyncResponse::Pull(data) => {
|
||||||
let bytes: Bytes = data.try_into().unwrap();
|
let bytes: Bytes = data.try_into().unwrap();
|
||||||
let msg = WsMessage {
|
let msg = WSMessage {
|
||||||
module: WsModule::Doc,
|
module: WSModule::Doc,
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
};
|
};
|
||||||
sender.send(msg).await.unwrap();
|
sender.send(msg).await.unwrap();
|
||||||
},
|
},
|
||||||
SyncResponse::Push(data) => {
|
SyncResponse::Push(data) => {
|
||||||
let bytes: Bytes = data.try_into().unwrap();
|
let bytes: Bytes = data.try_into().unwrap();
|
||||||
let msg = WsMessage {
|
let msg = WSMessage {
|
||||||
module: WsModule::Doc,
|
module: WSModule::Doc,
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
};
|
};
|
||||||
sender.send(msg).await.unwrap();
|
sender.send(msg).await.unwrap();
|
||||||
},
|
},
|
||||||
SyncResponse::Ack(data) => {
|
SyncResponse::Ack(data) => {
|
||||||
let bytes: Bytes = data.try_into().unwrap();
|
let bytes: Bytes = data.try_into().unwrap();
|
||||||
let msg = WsMessage {
|
let msg = WSMessage {
|
||||||
module: WsModule::Doc,
|
module: WSModule::Doc,
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
};
|
};
|
||||||
sender.send(msg).await.unwrap();
|
sender.send(msg).await.unwrap();
|
||||||
|
@ -3,17 +3,17 @@ use std::sync::Arc;
|
|||||||
use tokio::sync::broadcast;
|
use tokio::sync::broadcast;
|
||||||
|
|
||||||
pub use flowy_error::FlowyError;
|
pub use flowy_error::FlowyError;
|
||||||
pub use lib_ws::{WsConnectState, WsMessage, WsMessageReceiver};
|
pub use lib_ws::{WSConnectState, WSMessage, WSMessageReceiver};
|
||||||
|
|
||||||
pub trait FlowyWebSocket: Send + Sync {
|
pub trait FlowyWebSocket: Send + Sync {
|
||||||
fn start_connect(&self, addr: String) -> FutureResult<(), FlowyError>;
|
fn start_connect(&self, addr: String) -> FutureResult<(), FlowyError>;
|
||||||
fn stop_connect(&self) -> FutureResult<(), FlowyError>;
|
fn stop_connect(&self) -> FutureResult<(), FlowyError>;
|
||||||
fn subscribe_connect_state(&self) -> broadcast::Receiver<WsConnectState>;
|
fn subscribe_connect_state(&self) -> broadcast::Receiver<WSConnectState>;
|
||||||
fn reconnect(&self, count: usize) -> FutureResult<(), FlowyError>;
|
fn reconnect(&self, count: usize) -> FutureResult<(), FlowyError>;
|
||||||
fn add_message_receiver(&self, handler: Arc<dyn WsMessageReceiver>) -> Result<(), FlowyError>;
|
fn add_message_receiver(&self, handler: Arc<dyn WSMessageReceiver>) -> Result<(), FlowyError>;
|
||||||
fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, FlowyError>;
|
fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, FlowyError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FlowyWsSender: Send + Sync {
|
pub trait FlowyWsSender: Send + Sync {
|
||||||
fn send(&self, msg: WsMessage) -> Result<(), FlowyError>;
|
fn send(&self, msg: WSMessage) -> Result<(), FlowyError>;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use flowy_error::{internal_error, FlowyError};
|
use flowy_error::{internal_error, FlowyError};
|
||||||
use lib_infra::future::FutureResult;
|
use lib_infra::future::FutureResult;
|
||||||
use lib_ws::{WsConnectState, WsController, WsMessage, WsMessageReceiver, WsSender};
|
use lib_ws::{WSConnectState, WSController, WSMessage, WSMessageReceiver, WSSender};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{broadcast, broadcast::Receiver};
|
use tokio::sync::{broadcast, broadcast::Receiver};
|
||||||
@ -19,7 +19,7 @@ pub struct WsManager {
|
|||||||
impl WsManager {
|
impl WsManager {
|
||||||
pub fn new(addr: String) -> Self {
|
pub fn new(addr: String) -> Self {
|
||||||
let ws: Arc<dyn FlowyWebSocket> = if cfg!(feature = "http_server") {
|
let ws: Arc<dyn FlowyWebSocket> = if cfg!(feature = "http_server") {
|
||||||
Arc::new(Arc::new(WsController::new()))
|
Arc::new(Arc::new(WSController::new()))
|
||||||
} else {
|
} else {
|
||||||
local_web_socket()
|
local_web_socket()
|
||||||
};
|
};
|
||||||
@ -65,13 +65,13 @@ impl WsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe_websocket_state(&self) -> broadcast::Receiver<WsConnectState> {
|
pub fn subscribe_websocket_state(&self) -> broadcast::Receiver<WSConnectState> {
|
||||||
self.inner.subscribe_connect_state()
|
self.inner.subscribe_connect_state()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe_network_ty(&self) -> broadcast::Receiver<NetworkType> { self.status_notifier.subscribe() }
|
pub fn subscribe_network_ty(&self) -> broadcast::Receiver<NetworkType> { self.status_notifier.subscribe() }
|
||||||
|
|
||||||
pub fn add_receiver(&self, handler: Arc<dyn WsMessageReceiver>) -> Result<(), FlowyError> {
|
pub fn add_receiver(&self, handler: Arc<dyn WSMessageReceiver>) -> Result<(), FlowyError> {
|
||||||
let _ = self.inner.add_message_receiver(handler)?;
|
let _ = self.inner.add_message_receiver(handler)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -88,10 +88,10 @@ fn listen_on_websocket(ws: Arc<dyn FlowyWebSocket>) {
|
|||||||
Ok(state) => {
|
Ok(state) => {
|
||||||
tracing::info!("Websocket state changed: {}", state);
|
tracing::info!("Websocket state changed: {}", state);
|
||||||
match state {
|
match state {
|
||||||
WsConnectState::Init => {},
|
WSConnectState::Init => {},
|
||||||
WsConnectState::Connected => {},
|
WSConnectState::Connected => {},
|
||||||
WsConnectState::Connecting => {},
|
WSConnectState::Connecting => {},
|
||||||
WsConnectState::Disconnected => retry_connect(ws.clone(), 100).await,
|
WSConnectState::Disconnected => retry_connect(ws.clone(), 100).await,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -112,7 +112,7 @@ async fn retry_connect(ws: Arc<dyn FlowyWebSocket>, count: usize) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowyWebSocket for Arc<WsController> {
|
impl FlowyWebSocket for Arc<WSController> {
|
||||||
fn start_connect(&self, addr: String) -> FutureResult<(), FlowyError> {
|
fn start_connect(&self, addr: String) -> FutureResult<(), FlowyError> {
|
||||||
let cloned_ws = self.clone();
|
let cloned_ws = self.clone();
|
||||||
FutureResult::new(async move {
|
FutureResult::new(async move {
|
||||||
@ -129,7 +129,7 @@ impl FlowyWebSocket for Arc<WsController> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscribe_connect_state(&self) -> Receiver<WsConnectState> { self.subscribe_state() }
|
fn subscribe_connect_state(&self) -> Receiver<WSConnectState> { self.subscribe_state() }
|
||||||
|
|
||||||
fn reconnect(&self, count: usize) -> FutureResult<(), FlowyError> {
|
fn reconnect(&self, count: usize) -> FutureResult<(), FlowyError> {
|
||||||
let cloned_ws = self.clone();
|
let cloned_ws = self.clone();
|
||||||
@ -139,7 +139,7 @@ impl FlowyWebSocket for Arc<WsController> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_message_receiver(&self, handler: Arc<dyn WsMessageReceiver>) -> Result<(), FlowyError> {
|
fn add_message_receiver(&self, handler: Arc<dyn WSMessageReceiver>) -> Result<(), FlowyError> {
|
||||||
let _ = self.add_receiver(handler).map_err(internal_error)?;
|
let _ = self.add_receiver(handler).map_err(internal_error)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -150,8 +150,8 @@ impl FlowyWebSocket for Arc<WsController> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowyWsSender for WsSender {
|
impl FlowyWsSender for WSSender {
|
||||||
fn send(&self, msg: WsMessage) -> Result<(), FlowyError> {
|
fn send(&self, msg: WSMessage) -> Result<(), FlowyError> {
|
||||||
let _ = self.send_msg(msg).map_err(internal_error)?;
|
let _ = self.send_msg(msg).map_err(internal_error)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use crate::services::ws::{FlowyError, FlowyWebSocket, FlowyWsSender, WsConnectState, WsMessage, WsMessageReceiver};
|
use crate::services::ws::{FlowyError, FlowyWebSocket, FlowyWsSender, WSConnectState, WSMessage, WSMessageReceiver};
|
||||||
use lib_infra::future::FutureResult;
|
use lib_infra::future::FutureResult;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{broadcast, broadcast::Receiver};
|
use tokio::sync::{broadcast, broadcast::Receiver};
|
||||||
|
|
||||||
pub(crate) struct LocalWebSocket {
|
pub(crate) struct LocalWebSocket {
|
||||||
state_sender: broadcast::Sender<WsConnectState>,
|
state_sender: broadcast::Sender<WSConnectState>,
|
||||||
ws_sender: broadcast::Sender<WsMessage>,
|
ws_sender: broadcast::Sender<WSMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for LocalWebSocket {
|
impl std::default::Default for LocalWebSocket {
|
||||||
@ -24,17 +24,17 @@ impl FlowyWebSocket for Arc<LocalWebSocket> {
|
|||||||
|
|
||||||
fn stop_connect(&self) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) }
|
fn stop_connect(&self) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) }
|
||||||
|
|
||||||
fn subscribe_connect_state(&self) -> Receiver<WsConnectState> { self.state_sender.subscribe() }
|
fn subscribe_connect_state(&self) -> Receiver<WSConnectState> { self.state_sender.subscribe() }
|
||||||
|
|
||||||
fn reconnect(&self, _count: usize) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) }
|
fn reconnect(&self, _count: usize) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) }
|
||||||
|
|
||||||
fn add_message_receiver(&self, _handler: Arc<dyn WsMessageReceiver>) -> Result<(), FlowyError> { Ok(()) }
|
fn add_message_receiver(&self, _handler: Arc<dyn WSMessageReceiver>) -> Result<(), FlowyError> { Ok(()) }
|
||||||
|
|
||||||
fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, FlowyError> { Ok(Arc::new(self.ws_sender.clone())) }
|
fn ws_sender(&self) -> Result<Arc<dyn FlowyWsSender>, FlowyError> { Ok(Arc::new(self.ws_sender.clone())) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowyWsSender for broadcast::Sender<WsMessage> {
|
impl FlowyWsSender for broadcast::Sender<WSMessage> {
|
||||||
fn send(&self, msg: WsMessage) -> Result<(), FlowyError> {
|
fn send(&self, msg: WSMessage) -> Result<(), FlowyError> {
|
||||||
let _ = self.send(msg);
|
let _ = self.send(msg);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use flowy_collaboration::entities::ws::WsDocumentData;
|
use flowy_collaboration::entities::ws::DocumentWSData;
|
||||||
use flowy_database::ConnectionPool;
|
use flowy_database::ConnectionPool;
|
||||||
use flowy_document::{
|
use flowy_document::{
|
||||||
errors::{internal_error, FlowyError},
|
errors::{internal_error, FlowyError},
|
||||||
@ -8,7 +8,7 @@ use flowy_document::{
|
|||||||
};
|
};
|
||||||
use flowy_net::services::ws::WsManager;
|
use flowy_net::services::ws::WsManager;
|
||||||
use flowy_user::services::user::UserSession;
|
use flowy_user::services::user::UserSession;
|
||||||
use lib_ws::{WsMessage, WsMessageReceiver, WsModule};
|
use lib_ws::{WSMessage, WSMessageReceiver, WSModule};
|
||||||
use std::{convert::TryInto, path::Path, sync::Arc};
|
use std::{convert::TryInto, path::Path, sync::Arc};
|
||||||
|
|
||||||
pub struct DocumentDepsResolver();
|
pub struct DocumentDepsResolver();
|
||||||
@ -61,10 +61,10 @@ struct WsSenderImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentWebSocket for WsSenderImpl {
|
impl DocumentWebSocket for WsSenderImpl {
|
||||||
fn send(&self, data: WsDocumentData) -> Result<(), FlowyError> {
|
fn send(&self, data: DocumentWSData) -> Result<(), FlowyError> {
|
||||||
let bytes: Bytes = data.try_into().unwrap();
|
let bytes: Bytes = data.try_into().unwrap();
|
||||||
let msg = WsMessage {
|
let msg = WSMessage {
|
||||||
module: WsModule::Doc,
|
module: WSModule::Doc,
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
};
|
};
|
||||||
let sender = self.ws_manager.ws_sender().map_err(internal_error)?;
|
let sender = self.ws_manager.ws_sender().map_err(internal_error)?;
|
||||||
@ -78,7 +78,7 @@ impl DocumentWebSocket for WsSenderImpl {
|
|||||||
|
|
||||||
struct WsMessageReceiverAdaptor(Arc<DocumentWsHandlers>);
|
struct WsMessageReceiverAdaptor(Arc<DocumentWsHandlers>);
|
||||||
|
|
||||||
impl WsMessageReceiver for WsMessageReceiverAdaptor {
|
impl WSMessageReceiver for WsMessageReceiverAdaptor {
|
||||||
fn source(&self) -> WsModule { WsModule::Doc }
|
fn source(&self) -> WSModule { WSModule::Doc }
|
||||||
fn receive_message(&self, msg: WsMessage) { self.0.did_receive_data(Bytes::from(msg.data)); }
|
fn receive_message(&self, msg: WSMessage) { self.0.did_receive_data(Bytes::from(msg.data)); }
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ fn parse_files_protobuf(proto_crate_path: &str, proto_output_dir: &str) -> Vec<P
|
|||||||
|
|
||||||
// https://docs.rs/syn/1.0.54/syn/struct.File.html
|
// https://docs.rs/syn/1.0.54/syn/struct.File.html
|
||||||
let ast =
|
let ast =
|
||||||
syn::parse_file(read_file(&path).unwrap().as_ref()).expect("Unable to parse file");
|
syn::parse_file(read_file(&path).unwrap().as_ref()).expect(&format!("Unable to parse file at {}", path));
|
||||||
let structs = get_ast_structs(&ast);
|
let structs = get_ast_structs(&ast);
|
||||||
let proto_file_path = format!("{}/{}.proto", &proto_output_dir, &file_name);
|
let proto_file_path = format!("{}/{}.proto", &proto_output_dir, &file_name);
|
||||||
let mut proto_file_content = parse_or_init_proto_file(proto_file_path.as_ref());
|
let mut proto_file_content = parse_or_init_proto_file(proto_file_path.as_ref());
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
core::document::Document,
|
core::document::Document,
|
||||||
entities::ws::{WsDocumentData, WsDocumentDataType},
|
entities::ws::{DocumentWSData, DocumentWSDataType, WsDocumentDataBuilder},
|
||||||
};
|
};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use lib_ot::{
|
use lib_ot::{
|
||||||
@ -29,9 +29,9 @@ pub trait RevisionUser: Send + Sync + Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum SyncResponse {
|
pub enum SyncResponse {
|
||||||
Pull(WsDocumentData),
|
Pull(DocumentWSData),
|
||||||
Push(WsDocumentData),
|
Push(DocumentWSData),
|
||||||
Ack(WsDocumentData),
|
Ack(DocumentWSData),
|
||||||
NewRevision {
|
NewRevision {
|
||||||
rev_id: i64,
|
rev_id: i64,
|
||||||
doc_json: String,
|
doc_json: String,
|
||||||
@ -63,7 +63,10 @@ impl RevisionSynchronizer {
|
|||||||
if server_base_rev_id == revision.base_rev_id || server_rev_id == revision.rev_id {
|
if server_base_rev_id == revision.base_rev_id || server_rev_id == revision.rev_id {
|
||||||
// The rev is in the right order, just compose it.
|
// The rev is in the right order, just compose it.
|
||||||
let _ = self.compose_revision(&revision)?;
|
let _ = self.compose_revision(&revision)?;
|
||||||
user.recv(SyncResponse::Ack(mk_acked_message(&revision)));
|
user.recv(SyncResponse::Ack(WsDocumentDataBuilder::build_acked_message(
|
||||||
|
&revision.doc_id,
|
||||||
|
revision.rev_id,
|
||||||
|
)));
|
||||||
let rev_id = revision.rev_id;
|
let rev_id = revision.rev_id;
|
||||||
let doc_id = self.doc_id.clone();
|
let doc_id = self.doc_id.clone();
|
||||||
let doc_json = self.doc_json();
|
let doc_json = self.doc_json();
|
||||||
@ -74,21 +77,27 @@ impl RevisionSynchronizer {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// The server document is outdated, pull the missing revision from the client.
|
// The server document is outdated, pull the missing revision from the client.
|
||||||
let msg = mk_pull_message(&self.doc_id, server_rev_id, revision.rev_id);
|
let range = RevisionRange {
|
||||||
|
doc_id: self.doc_id.clone(),
|
||||||
|
start: server_rev_id,
|
||||||
|
end: revision.rev_id,
|
||||||
|
};
|
||||||
|
let msg = WsDocumentDataBuilder::build_push_pull_message(&self.doc_id, range);
|
||||||
user.recv(SyncResponse::Pull(msg));
|
user.recv(SyncResponse::Pull(msg));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
log::warn!("Applied revision rev_id is the same as cur_rev_id");
|
log::warn!("Applied revision rev_id is the same as cur_rev_id");
|
||||||
user.recv(SyncResponse::Ack(mk_acked_message(&revision)));
|
let data = WsDocumentDataBuilder::build_acked_message(&revision.doc_id, revision.rev_id);
|
||||||
|
user.recv(SyncResponse::Ack(data));
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
// The client document is outdated. Transform the client revision delta and then
|
// The client document is outdated. Transform the client revision delta and then
|
||||||
// send the prime delta to the client. Client should compose the this prime
|
// send the prime delta to the client. Client should compose the this prime
|
||||||
// delta.
|
// delta.
|
||||||
let cli_revision = self.transform_revision(&revision)?;
|
let cli_revision = self.transform_revision(&revision)?;
|
||||||
let data = mk_push_message(&self.doc_id, cli_revision);
|
let data = WsDocumentDataBuilder::build_push_rev_message(&self.doc_id, cli_revision);
|
||||||
user.recv(SyncResponse::Push(data));
|
user.recv(SyncResponse::Push(data));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -143,44 +152,6 @@ impl RevisionSynchronizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_push_message(doc_id: &str, revision: Revision) -> WsDocumentData {
|
|
||||||
let bytes: Bytes = revision.try_into().unwrap();
|
|
||||||
WsDocumentData {
|
|
||||||
doc_id: doc_id.to_string(),
|
|
||||||
ty: WsDocumentDataType::PushRev,
|
|
||||||
data: bytes.to_vec(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mk_pull_message(doc_id: &str, from_rev_id: i64, to_rev_id: i64) -> WsDocumentData {
|
|
||||||
let range = RevisionRange {
|
|
||||||
doc_id: doc_id.to_string(),
|
|
||||||
start: from_rev_id,
|
|
||||||
end: to_rev_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
let bytes: Bytes = range.try_into().unwrap();
|
|
||||||
WsDocumentData {
|
|
||||||
doc_id: doc_id.to_string(),
|
|
||||||
ty: WsDocumentDataType::PullRev,
|
|
||||||
data: bytes.to_vec(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mk_acked_message(revision: &Revision) -> WsDocumentData {
|
|
||||||
// let mut wtr = vec![];
|
|
||||||
// let _ = wtr.write_i64::<BigEndian>(revision.rev_id);
|
|
||||||
let mut rev_id = RevId::new();
|
|
||||||
rev_id.set_value(revision.rev_id);
|
|
||||||
let data = rev_id.write_to_bytes().unwrap();
|
|
||||||
|
|
||||||
WsDocumentData {
|
|
||||||
doc_id: revision.doc_id.clone(),
|
|
||||||
ty: WsDocumentDataType::Acked,
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(rev_id: i64) -> i64 { rev_id + 1 }
|
fn next(rev_id: i64) -> i64 { rev_id + 1 }
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use lib_ot::revision::{RevId, Revision, RevisionRange};
|
|||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
#[derive(Debug, Clone, ProtoBuf_Enum, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, ProtoBuf_Enum, Eq, PartialEq, Hash)]
|
||||||
pub enum WsDocumentDataType {
|
pub enum DocumentWSDataType {
|
||||||
// The frontend receives the Acked means the backend has accepted the revision
|
// The frontend receives the Acked means the backend has accepted the revision
|
||||||
Acked = 0,
|
Acked = 0,
|
||||||
// The frontend receives the PushRev event means the backend is pushing the new revision to frontend
|
// The frontend receives the PushRev event means the backend is pushing the new revision to frontend
|
||||||
@ -15,7 +15,7 @@ pub enum WsDocumentDataType {
|
|||||||
UserConnect = 3,
|
UserConnect = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsDocumentDataType {
|
impl DocumentWSDataType {
|
||||||
pub fn data<T>(&self, bytes: Bytes) -> Result<T, CollaborateError>
|
pub fn data<T>(&self, bytes: Bytes) -> Result<T, CollaborateError>
|
||||||
where
|
where
|
||||||
T: TryFrom<Bytes, Error = CollaborateError>,
|
T: TryFrom<Bytes, Error = CollaborateError>,
|
||||||
@ -24,64 +24,75 @@ impl WsDocumentDataType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for WsDocumentDataType {
|
impl std::default::Default for DocumentWSDataType {
|
||||||
fn default() -> Self { WsDocumentDataType::Acked }
|
fn default() -> Self { DocumentWSDataType::Acked }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ProtoBuf, Default, Debug, Clone)]
|
#[derive(ProtoBuf, Default, Debug, Clone)]
|
||||||
pub struct WsDocumentData {
|
pub struct DocumentWSData {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
pub doc_id: String,
|
pub doc_id: String,
|
||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
pub ty: WsDocumentDataType,
|
pub ty: DocumentWSDataType,
|
||||||
|
|
||||||
#[pb(index = 3)]
|
#[pb(index = 3)]
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
|
|
||||||
|
#[pb(index = 4, one_of)]
|
||||||
|
pub id: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<Revision> for WsDocumentData {
|
impl std::convert::From<Revision> for DocumentWSData {
|
||||||
fn from(revision: Revision) -> Self {
|
fn from(revision: Revision) -> Self {
|
||||||
let doc_id = revision.doc_id.clone();
|
let doc_id = revision.doc_id.clone();
|
||||||
|
let rev_id = revision.rev_id;
|
||||||
let bytes: Bytes = revision.try_into().unwrap();
|
let bytes: Bytes = revision.try_into().unwrap();
|
||||||
Self {
|
Self {
|
||||||
doc_id,
|
doc_id,
|
||||||
ty: WsDocumentDataType::PushRev,
|
ty: DocumentWSDataType::PushRev,
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
|
id: Some(rev_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WsDocumentDataBuilder();
|
pub struct WsDocumentDataBuilder();
|
||||||
impl WsDocumentDataBuilder {
|
impl WsDocumentDataBuilder {
|
||||||
// WsDocumentDataType::PushRev -> Revision
|
// DocumentWSDataType::PushRev -> Revision
|
||||||
pub fn build_push_rev_message(doc_id: &str, revision: Revision) -> WsDocumentData {
|
pub fn build_push_rev_message(doc_id: &str, revision: Revision) -> DocumentWSData {
|
||||||
|
let rev_id = revision.rev_id;
|
||||||
let bytes: Bytes = revision.try_into().unwrap();
|
let bytes: Bytes = revision.try_into().unwrap();
|
||||||
WsDocumentData {
|
DocumentWSData {
|
||||||
doc_id: doc_id.to_string(),
|
doc_id: doc_id.to_string(),
|
||||||
ty: WsDocumentDataType::PushRev,
|
ty: DocumentWSDataType::PushRev,
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
|
id: Some(rev_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WsDocumentDataType::PullRev -> RevisionRange
|
// DocumentWSDataType::PullRev -> RevisionRange
|
||||||
pub fn build_push_pull_message(doc_id: &str, range: RevisionRange) -> WsDocumentData {
|
pub fn build_push_pull_message(doc_id: &str, range: RevisionRange) -> DocumentWSData {
|
||||||
let bytes: Bytes = range.try_into().unwrap();
|
let bytes: Bytes = range.try_into().unwrap();
|
||||||
WsDocumentData {
|
DocumentWSData {
|
||||||
doc_id: doc_id.to_string(),
|
doc_id: doc_id.to_string(),
|
||||||
ty: WsDocumentDataType::PullRev,
|
ty: DocumentWSDataType::PullRev,
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
|
id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WsDocumentDataType::Acked -> RevId
|
// DocumentWSDataType::Acked -> RevId
|
||||||
pub fn build_acked_message(doc_id: &str, rev_id: i64) -> WsDocumentData {
|
pub fn build_acked_message(doc_id: &str, rev_id: i64) -> DocumentWSData {
|
||||||
|
let cloned_rev_id = rev_id.clone();
|
||||||
let rev_id: RevId = rev_id.into();
|
let rev_id: RevId = rev_id.into();
|
||||||
let bytes: Bytes = rev_id.try_into().unwrap();
|
let bytes: Bytes = rev_id.try_into().unwrap();
|
||||||
WsDocumentData {
|
|
||||||
|
DocumentWSData {
|
||||||
doc_id: doc_id.to_string(),
|
doc_id: doc_id.to_string(),
|
||||||
ty: WsDocumentDataType::Acked,
|
ty: DocumentWSDataType::Acked,
|
||||||
data: bytes.to_vec(),
|
data: bytes.to_vec(),
|
||||||
|
id: Some(cloned_rev_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,24 +24,31 @@
|
|||||||
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
|
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
|
||||||
|
|
||||||
#[derive(PartialEq,Clone,Default)]
|
#[derive(PartialEq,Clone,Default)]
|
||||||
pub struct WsDocumentData {
|
pub struct DocumentWSData {
|
||||||
// message fields
|
// message fields
|
||||||
pub doc_id: ::std::string::String,
|
pub doc_id: ::std::string::String,
|
||||||
pub ty: WsDocumentDataType,
|
pub ty: DocumentWSDataType,
|
||||||
pub data: ::std::vec::Vec<u8>,
|
pub data: ::std::vec::Vec<u8>,
|
||||||
|
// message oneof groups
|
||||||
|
pub one_of_id: ::std::option::Option<DocumentWSData_oneof_one_of_id>,
|
||||||
// special fields
|
// special fields
|
||||||
pub unknown_fields: ::protobuf::UnknownFields,
|
pub unknown_fields: ::protobuf::UnknownFields,
|
||||||
pub cached_size: ::protobuf::CachedSize,
|
pub cached_size: ::protobuf::CachedSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ::std::default::Default for &'a WsDocumentData {
|
impl<'a> ::std::default::Default for &'a DocumentWSData {
|
||||||
fn default() -> &'a WsDocumentData {
|
fn default() -> &'a DocumentWSData {
|
||||||
<WsDocumentData as ::protobuf::Message>::default_instance()
|
<DocumentWSData as ::protobuf::Message>::default_instance()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsDocumentData {
|
#[derive(Clone,PartialEq,Debug)]
|
||||||
pub fn new() -> WsDocumentData {
|
pub enum DocumentWSData_oneof_one_of_id {
|
||||||
|
id(i64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DocumentWSData {
|
||||||
|
pub fn new() -> DocumentWSData {
|
||||||
::std::default::Default::default()
|
::std::default::Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,18 +78,18 @@ impl WsDocumentData {
|
|||||||
::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
|
::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
// .WsDocumentDataType ty = 2;
|
// .DocumentWSDataType ty = 2;
|
||||||
|
|
||||||
|
|
||||||
pub fn get_ty(&self) -> WsDocumentDataType {
|
pub fn get_ty(&self) -> DocumentWSDataType {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
pub fn clear_ty(&mut self) {
|
pub fn clear_ty(&mut self) {
|
||||||
self.ty = WsDocumentDataType::Acked;
|
self.ty = DocumentWSDataType::Acked;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Param is passed by value, moved
|
// Param is passed by value, moved
|
||||||
pub fn set_ty(&mut self, v: WsDocumentDataType) {
|
pub fn set_ty(&mut self, v: DocumentWSDataType) {
|
||||||
self.ty = v;
|
self.ty = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,9 +118,34 @@ impl WsDocumentData {
|
|||||||
pub fn take_data(&mut self) -> ::std::vec::Vec<u8> {
|
pub fn take_data(&mut self) -> ::std::vec::Vec<u8> {
|
||||||
::std::mem::replace(&mut self.data, ::std::vec::Vec::new())
|
::std::mem::replace(&mut self.data, ::std::vec::Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// int64 id = 4;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn get_id(&self) -> i64 {
|
||||||
|
match self.one_of_id {
|
||||||
|
::std::option::Option::Some(DocumentWSData_oneof_one_of_id::id(v)) => v,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn clear_id(&mut self) {
|
||||||
|
self.one_of_id = ::std::option::Option::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_id(&self) -> bool {
|
||||||
|
match self.one_of_id {
|
||||||
|
::std::option::Option::Some(DocumentWSData_oneof_one_of_id::id(..)) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param is passed by value, moved
|
||||||
|
pub fn set_id(&mut self, v: i64) {
|
||||||
|
self.one_of_id = ::std::option::Option::Some(DocumentWSData_oneof_one_of_id::id(v))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::Message for WsDocumentData {
|
impl ::protobuf::Message for DocumentWSData {
|
||||||
fn is_initialized(&self) -> bool {
|
fn is_initialized(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -131,6 +163,12 @@ impl ::protobuf::Message for WsDocumentData {
|
|||||||
3 => {
|
3 => {
|
||||||
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?;
|
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?;
|
||||||
},
|
},
|
||||||
|
4 => {
|
||||||
|
if wire_type != ::protobuf::wire_format::WireTypeVarint {
|
||||||
|
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
|
||||||
|
}
|
||||||
|
self.one_of_id = ::std::option::Option::Some(DocumentWSData_oneof_one_of_id::id(is.read_int64()?));
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
||||||
},
|
},
|
||||||
@ -146,12 +184,19 @@ impl ::protobuf::Message for WsDocumentData {
|
|||||||
if !self.doc_id.is_empty() {
|
if !self.doc_id.is_empty() {
|
||||||
my_size += ::protobuf::rt::string_size(1, &self.doc_id);
|
my_size += ::protobuf::rt::string_size(1, &self.doc_id);
|
||||||
}
|
}
|
||||||
if self.ty != WsDocumentDataType::Acked {
|
if self.ty != DocumentWSDataType::Acked {
|
||||||
my_size += ::protobuf::rt::enum_size(2, self.ty);
|
my_size += ::protobuf::rt::enum_size(2, self.ty);
|
||||||
}
|
}
|
||||||
if !self.data.is_empty() {
|
if !self.data.is_empty() {
|
||||||
my_size += ::protobuf::rt::bytes_size(3, &self.data);
|
my_size += ::protobuf::rt::bytes_size(3, &self.data);
|
||||||
}
|
}
|
||||||
|
if let ::std::option::Option::Some(ref v) = self.one_of_id {
|
||||||
|
match v {
|
||||||
|
&DocumentWSData_oneof_one_of_id::id(v) => {
|
||||||
|
my_size += ::protobuf::rt::value_size(4, v, ::protobuf::wire_format::WireTypeVarint);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
||||||
self.cached_size.set(my_size);
|
self.cached_size.set(my_size);
|
||||||
my_size
|
my_size
|
||||||
@ -161,12 +206,19 @@ impl ::protobuf::Message for WsDocumentData {
|
|||||||
if !self.doc_id.is_empty() {
|
if !self.doc_id.is_empty() {
|
||||||
os.write_string(1, &self.doc_id)?;
|
os.write_string(1, &self.doc_id)?;
|
||||||
}
|
}
|
||||||
if self.ty != WsDocumentDataType::Acked {
|
if self.ty != DocumentWSDataType::Acked {
|
||||||
os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.ty))?;
|
os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.ty))?;
|
||||||
}
|
}
|
||||||
if !self.data.is_empty() {
|
if !self.data.is_empty() {
|
||||||
os.write_bytes(3, &self.data)?;
|
os.write_bytes(3, &self.data)?;
|
||||||
}
|
}
|
||||||
|
if let ::std::option::Option::Some(ref v) = self.one_of_id {
|
||||||
|
match v {
|
||||||
|
&DocumentWSData_oneof_one_of_id::id(v) => {
|
||||||
|
os.write_int64(4, v)?;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
os.write_unknown_fields(self.get_unknown_fields())?;
|
os.write_unknown_fields(self.get_unknown_fields())?;
|
||||||
::std::result::Result::Ok(())
|
::std::result::Result::Ok(())
|
||||||
}
|
}
|
||||||
@ -197,8 +249,8 @@ impl ::protobuf::Message for WsDocumentData {
|
|||||||
Self::descriptor_static()
|
Self::descriptor_static()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> WsDocumentData {
|
fn new() -> DocumentWSData {
|
||||||
WsDocumentData::new()
|
DocumentWSData::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||||
@ -207,49 +259,55 @@ impl ::protobuf::Message for WsDocumentData {
|
|||||||
let mut fields = ::std::vec::Vec::new();
|
let mut fields = ::std::vec::Vec::new();
|
||||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
|
||||||
"doc_id",
|
"doc_id",
|
||||||
|m: &WsDocumentData| { &m.doc_id },
|
|m: &DocumentWSData| { &m.doc_id },
|
||||||
|m: &mut WsDocumentData| { &mut m.doc_id },
|
|m: &mut DocumentWSData| { &mut m.doc_id },
|
||||||
));
|
));
|
||||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<WsDocumentDataType>>(
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<DocumentWSDataType>>(
|
||||||
"ty",
|
"ty",
|
||||||
|m: &WsDocumentData| { &m.ty },
|
|m: &DocumentWSData| { &m.ty },
|
||||||
|m: &mut WsDocumentData| { &mut m.ty },
|
|m: &mut DocumentWSData| { &mut m.ty },
|
||||||
));
|
));
|
||||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
|
||||||
"data",
|
"data",
|
||||||
|m: &WsDocumentData| { &m.data },
|
|m: &DocumentWSData| { &m.data },
|
||||||
|m: &mut WsDocumentData| { &mut m.data },
|
|m: &mut DocumentWSData| { &mut m.data },
|
||||||
));
|
));
|
||||||
::protobuf::reflect::MessageDescriptor::new_pb_name::<WsDocumentData>(
|
fields.push(::protobuf::reflect::accessor::make_singular_i64_accessor::<_>(
|
||||||
"WsDocumentData",
|
"id",
|
||||||
|
DocumentWSData::has_id,
|
||||||
|
DocumentWSData::get_id,
|
||||||
|
));
|
||||||
|
::protobuf::reflect::MessageDescriptor::new_pb_name::<DocumentWSData>(
|
||||||
|
"DocumentWSData",
|
||||||
fields,
|
fields,
|
||||||
file_descriptor_proto()
|
file_descriptor_proto()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_instance() -> &'static WsDocumentData {
|
fn default_instance() -> &'static DocumentWSData {
|
||||||
static instance: ::protobuf::rt::LazyV2<WsDocumentData> = ::protobuf::rt::LazyV2::INIT;
|
static instance: ::protobuf::rt::LazyV2<DocumentWSData> = ::protobuf::rt::LazyV2::INIT;
|
||||||
instance.get(WsDocumentData::new)
|
instance.get(DocumentWSData::new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::Clear for WsDocumentData {
|
impl ::protobuf::Clear for DocumentWSData {
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.doc_id.clear();
|
self.doc_id.clear();
|
||||||
self.ty = WsDocumentDataType::Acked;
|
self.ty = DocumentWSDataType::Acked;
|
||||||
self.data.clear();
|
self.data.clear();
|
||||||
|
self.one_of_id = ::std::option::Option::None;
|
||||||
self.unknown_fields.clear();
|
self.unknown_fields.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Debug for WsDocumentData {
|
impl ::std::fmt::Debug for DocumentWSData {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
::protobuf::text_format::fmt(self, f)
|
::protobuf::text_format::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::reflect::ProtobufValue for WsDocumentData {
|
impl ::protobuf::reflect::ProtobufValue for DocumentWSData {
|
||||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||||
::protobuf::reflect::ReflectValueRef::Message(self)
|
::protobuf::reflect::ReflectValueRef::Message(self)
|
||||||
}
|
}
|
||||||
@ -492,34 +550,34 @@ impl ::protobuf::reflect::ProtobufValue for DocumentConnected {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
|
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
|
||||||
pub enum WsDocumentDataType {
|
pub enum DocumentWSDataType {
|
||||||
Acked = 0,
|
Acked = 0,
|
||||||
PushRev = 1,
|
PushRev = 1,
|
||||||
PullRev = 2,
|
PullRev = 2,
|
||||||
UserConnect = 3,
|
UserConnect = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::ProtobufEnum for WsDocumentDataType {
|
impl ::protobuf::ProtobufEnum for DocumentWSDataType {
|
||||||
fn value(&self) -> i32 {
|
fn value(&self) -> i32 {
|
||||||
*self as i32
|
*self as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_i32(value: i32) -> ::std::option::Option<WsDocumentDataType> {
|
fn from_i32(value: i32) -> ::std::option::Option<DocumentWSDataType> {
|
||||||
match value {
|
match value {
|
||||||
0 => ::std::option::Option::Some(WsDocumentDataType::Acked),
|
0 => ::std::option::Option::Some(DocumentWSDataType::Acked),
|
||||||
1 => ::std::option::Option::Some(WsDocumentDataType::PushRev),
|
1 => ::std::option::Option::Some(DocumentWSDataType::PushRev),
|
||||||
2 => ::std::option::Option::Some(WsDocumentDataType::PullRev),
|
2 => ::std::option::Option::Some(DocumentWSDataType::PullRev),
|
||||||
3 => ::std::option::Option::Some(WsDocumentDataType::UserConnect),
|
3 => ::std::option::Option::Some(DocumentWSDataType::UserConnect),
|
||||||
_ => ::std::option::Option::None
|
_ => ::std::option::Option::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn values() -> &'static [Self] {
|
fn values() -> &'static [Self] {
|
||||||
static values: &'static [WsDocumentDataType] = &[
|
static values: &'static [DocumentWSDataType] = &[
|
||||||
WsDocumentDataType::Acked,
|
DocumentWSDataType::Acked,
|
||||||
WsDocumentDataType::PushRev,
|
DocumentWSDataType::PushRev,
|
||||||
WsDocumentDataType::PullRev,
|
DocumentWSDataType::PullRev,
|
||||||
WsDocumentDataType::UserConnect,
|
DocumentWSDataType::UserConnect,
|
||||||
];
|
];
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
@ -527,63 +585,68 @@ impl ::protobuf::ProtobufEnum for WsDocumentDataType {
|
|||||||
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
|
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
|
||||||
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
||||||
descriptor.get(|| {
|
descriptor.get(|| {
|
||||||
::protobuf::reflect::EnumDescriptor::new_pb_name::<WsDocumentDataType>("WsDocumentDataType", file_descriptor_proto())
|
::protobuf::reflect::EnumDescriptor::new_pb_name::<DocumentWSDataType>("DocumentWSDataType", file_descriptor_proto())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::marker::Copy for WsDocumentDataType {
|
impl ::std::marker::Copy for DocumentWSDataType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::default::Default for WsDocumentDataType {
|
impl ::std::default::Default for DocumentWSDataType {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
WsDocumentDataType::Acked
|
DocumentWSDataType::Acked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::reflect::ProtobufValue for WsDocumentDataType {
|
impl ::protobuf::reflect::ProtobufValue for DocumentWSDataType {
|
||||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||||
::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
|
::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||||
\n\x08ws.proto\"`\n\x0eWsDocumentData\x12\x15\n\x06doc_id\x18\x01\x20\
|
\n\x08ws.proto\"\x7f\n\x0eDocumentWSData\x12\x15\n\x06doc_id\x18\x01\x20\
|
||||||
\x01(\tR\x05docId\x12#\n\x02ty\x18\x02\x20\x01(\x0e2\x13.WsDocumentDataT\
|
\x01(\tR\x05docId\x12#\n\x02ty\x18\x02\x20\x01(\x0e2\x13.DocumentWSDataT\
|
||||||
ypeR\x02ty\x12\x12\n\x04data\x18\x03\x20\x01(\x0cR\x04data\"Z\n\x11Docum\
|
ypeR\x02ty\x12\x12\n\x04data\x18\x03\x20\x01(\x0cR\x04data\x12\x10\n\x02\
|
||||||
entConnected\x12\x17\n\x07user_id\x18\x01\x20\x01(\tR\x06userId\x12\x15\
|
id\x18\x04\x20\x01(\x03H\0R\x02idB\x0b\n\tone_of_id\"Z\n\x11DocumentConn\
|
||||||
\n\x06doc_id\x18\x02\x20\x01(\tR\x05docId\x12\x15\n\x06rev_id\x18\x03\
|
ected\x12\x17\n\x07user_id\x18\x01\x20\x01(\tR\x06userId\x12\x15\n\x06do\
|
||||||
\x20\x01(\x03R\x05revId*J\n\x12WsDocumentDataType\x12\t\n\x05Acked\x10\0\
|
c_id\x18\x02\x20\x01(\tR\x05docId\x12\x15\n\x06rev_id\x18\x03\x20\x01(\
|
||||||
\x12\x0b\n\x07PushRev\x10\x01\x12\x0b\n\x07PullRev\x10\x02\x12\x0f\n\x0b\
|
\x03R\x05revId*J\n\x12DocumentWSDataType\x12\t\n\x05Acked\x10\0\x12\x0b\
|
||||||
UserConnect\x10\x03J\xc8\x04\n\x06\x12\x04\0\0\x11\x01\n\x08\n\x01\x0c\
|
\n\x07PushRev\x10\x01\x12\x0b\n\x07PullRev\x10\x02\x12\x0f\n\x0bUserConn\
|
||||||
\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x06\x01\n\n\n\x03\x04\0\
|
ect\x10\x03J\x9a\x05\n\x06\x12\x04\0\0\x12\x01\n\x08\n\x01\x0c\x12\x03\0\
|
||||||
\x01\x12\x03\x02\x08\x16\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x16\n\
|
\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x07\x01\n\n\n\x03\x04\0\x01\x12\x03\
|
||||||
\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\
|
\x02\x08\x16\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x16\n\x0c\n\x05\x04\
|
||||||
\x12\x03\x03\x0b\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x14\x15\n\
|
\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\
|
||||||
\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x1e\n\x0c\n\x05\x04\0\x02\x01\
|
\x0b\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x14\x15\n\x0b\n\x04\x04\
|
||||||
\x06\x12\x03\x04\x04\x16\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x17\
|
\0\x02\x01\x12\x03\x04\x04\x1e\n\x0c\n\x05\x04\0\x02\x01\x06\x12\x03\x04\
|
||||||
\x19\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x1c\x1d\n\x0b\n\x04\x04\0\
|
\x04\x16\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x17\x19\n\x0c\n\x05\
|
||||||
\x02\x02\x12\x03\x05\x04\x13\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\
|
\x04\0\x02\x01\x03\x12\x03\x04\x1c\x1d\n\x0b\n\x04\x04\0\x02\x02\x12\x03\
|
||||||
\x04\t\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\n\x0e\n\x0c\n\x05\x04\0\
|
\x05\x04\x13\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\t\n\x0c\n\x05\
|
||||||
\x02\x02\x03\x12\x03\x05\x11\x12\n\n\n\x02\x04\x01\x12\x04\x07\0\x0b\x01\
|
\x04\0\x02\x02\x01\x12\x03\x05\n\x0e\n\x0c\n\x05\x04\0\x02\x02\x03\x12\
|
||||||
\n\n\n\x03\x04\x01\x01\x12\x03\x07\x08\x19\n\x0b\n\x04\x04\x01\x02\0\x12\
|
\x03\x05\x11\x12\n\x0b\n\x04\x04\0\x08\0\x12\x03\x06\x04%\n\x0c\n\x05\
|
||||||
\x03\x08\x04\x17\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x08\x04\n\n\x0c\n\
|
\x04\0\x08\0\x01\x12\x03\x06\n\x13\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\
|
||||||
\x05\x04\x01\x02\0\x01\x12\x03\x08\x0b\x12\n\x0c\n\x05\x04\x01\x02\0\x03\
|
\x16#\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x06\x16\x1b\n\x0c\n\x05\x04\
|
||||||
\x12\x03\x08\x15\x16\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\t\x04\x16\n\x0c\
|
\0\x02\x03\x01\x12\x03\x06\x1c\x1e\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\
|
||||||
\n\x05\x04\x01\x02\x01\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\x01\x02\x01\
|
\x06!\"\n\n\n\x02\x04\x01\x12\x04\x08\0\x0c\x01\n\n\n\x03\x04\x01\x01\
|
||||||
\x01\x12\x03\t\x0b\x11\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\t\x14\x15\
|
\x12\x03\x08\x08\x19\n\x0b\n\x04\x04\x01\x02\0\x12\x03\t\x04\x17\n\x0c\n\
|
||||||
\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\n\x04\x15\n\x0c\n\x05\x04\x01\x02\
|
\x05\x04\x01\x02\0\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\
|
||||||
\x02\x05\x12\x03\n\x04\t\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\n\n\x10\
|
\x03\t\x0b\x12\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\t\x15\x16\n\x0b\n\
|
||||||
\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\n\x13\x14\n\n\n\x02\x05\0\x12\
|
\x04\x04\x01\x02\x01\x12\x03\n\x04\x16\n\x0c\n\x05\x04\x01\x02\x01\x05\
|
||||||
\x04\x0c\0\x11\x01\n\n\n\x03\x05\0\x01\x12\x03\x0c\x05\x17\n\x0b\n\x04\
|
\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\n\x0b\x11\n\x0c\
|
||||||
\x05\0\x02\0\x12\x03\r\x04\x0e\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\r\x04\
|
\n\x05\x04\x01\x02\x01\x03\x12\x03\n\x14\x15\n\x0b\n\x04\x04\x01\x02\x02\
|
||||||
\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\r\x0c\r\n\x0b\n\x04\x05\0\x02\x01\
|
\x12\x03\x0b\x04\x15\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x0b\x04\t\n\
|
||||||
\x12\x03\x0e\x04\x10\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x0e\x04\x0b\n\
|
\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x0b\n\x10\n\x0c\n\x05\x04\x01\x02\
|
||||||
\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x0e\x0e\x0f\n\x0b\n\x04\x05\0\x02\
|
\x02\x03\x12\x03\x0b\x13\x14\n\n\n\x02\x05\0\x12\x04\r\0\x12\x01\n\n\n\
|
||||||
\x02\x12\x03\x0f\x04\x10\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x0f\x04\
|
\x03\x05\0\x01\x12\x03\r\x05\x17\n\x0b\n\x04\x05\0\x02\0\x12\x03\x0e\x04\
|
||||||
\x0b\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x0f\x0e\x0f\n\x0b\n\x04\x05\0\
|
\x0e\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x0e\x04\t\n\x0c\n\x05\x05\0\x02\
|
||||||
\x02\x03\x12\x03\x10\x04\x14\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x10\
|
\0\x02\x12\x03\x0e\x0c\r\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x0f\x04\x10\n\
|
||||||
\x04\x0f\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\x10\x12\x13b\x06proto3\
|
\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x0f\x04\x0b\n\x0c\n\x05\x05\0\x02\
|
||||||
|
\x01\x02\x12\x03\x0f\x0e\x0f\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x10\x04\
|
||||||
|
\x10\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x10\x04\x0b\n\x0c\n\x05\x05\0\
|
||||||
|
\x02\x02\x02\x12\x03\x10\x0e\x0f\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x11\
|
||||||
|
\x04\x14\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x11\x04\x0f\n\x0c\n\x05\
|
||||||
|
\x05\0\x02\x03\x02\x12\x03\x11\x12\x13b\x06proto3\
|
||||||
";
|
";
|
||||||
|
|
||||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
message WsDocumentData {
|
message DocumentWSData {
|
||||||
string doc_id = 1;
|
string doc_id = 1;
|
||||||
WsDocumentDataType ty = 2;
|
DocumentWSDataType ty = 2;
|
||||||
bytes data = 3;
|
bytes data = 3;
|
||||||
|
oneof one_of_id { int64 id = 4; };
|
||||||
}
|
}
|
||||||
message DocumentConnected {
|
message DocumentConnected {
|
||||||
string user_id = 1;
|
string user_id = 1;
|
||||||
string doc_id = 2;
|
string doc_id = 2;
|
||||||
int64 rev_id = 3;
|
int64 rev_id = 3;
|
||||||
}
|
}
|
||||||
enum WsDocumentDataType {
|
enum DocumentWSDataType {
|
||||||
Acked = 0;
|
Acked = 0;
|
||||||
PushRev = 1;
|
PushRev = 1;
|
||||||
PullRev = 2;
|
PullRev = 2;
|
||||||
|
@ -60,10 +60,10 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
|
|||||||
| "DocDelta"
|
| "DocDelta"
|
||||||
| "NewDocUser"
|
| "NewDocUser"
|
||||||
| "DocIdentifier"
|
| "DocIdentifier"
|
||||||
| "WsDocumentData"
|
| "DocumentWSData"
|
||||||
| "DocumentConnected"
|
| "DocumentConnected"
|
||||||
| "WsError"
|
| "WSError"
|
||||||
| "WsMessage"
|
| "WSMessage"
|
||||||
| "Revision"
|
| "Revision"
|
||||||
| "RevId"
|
| "RevId"
|
||||||
| "RevisionRange"
|
| "RevisionRange"
|
||||||
@ -89,9 +89,9 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
|
|||||||
| "TrashType"
|
| "TrashType"
|
||||||
| "ViewType"
|
| "ViewType"
|
||||||
| "ExportType"
|
| "ExportType"
|
||||||
| "WsDocumentDataType"
|
| "DocumentWSDataType"
|
||||||
| "ErrorCode"
|
| "ErrorCode"
|
||||||
| "WsModule"
|
| "WSModule"
|
||||||
| "RevType"
|
| "RevType"
|
||||||
| "RevState"
|
| "RevState"
|
||||||
=> TypeCategory::Enum,
|
=> TypeCategory::Enum,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![allow(clippy::all)]
|
#![allow(clippy::all)]
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{internal_error, WsError},
|
errors::{internal_error, WSError},
|
||||||
MsgReceiver,
|
MsgReceiver,
|
||||||
MsgSender,
|
MsgSender,
|
||||||
};
|
};
|
||||||
@ -24,16 +24,16 @@ use tokio_tungstenite::{
|
|||||||
type WsConnectResult = Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response), Error>;
|
type WsConnectResult = Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response), Error>;
|
||||||
|
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
pub struct WsConnectionFuture {
|
pub struct WSConnectionFuture {
|
||||||
msg_tx: Option<MsgSender>,
|
msg_tx: Option<MsgSender>,
|
||||||
ws_rx: Option<MsgReceiver>,
|
ws_rx: Option<MsgReceiver>,
|
||||||
#[pin]
|
#[pin]
|
||||||
fut: Pin<Box<dyn Future<Output = WsConnectResult> + Send + Sync>>,
|
fut: Pin<Box<dyn Future<Output = WsConnectResult> + Send + Sync>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsConnectionFuture {
|
impl WSConnectionFuture {
|
||||||
pub fn new(msg_tx: MsgSender, ws_rx: MsgReceiver, addr: String) -> Self {
|
pub fn new(msg_tx: MsgSender, ws_rx: MsgReceiver, addr: String) -> Self {
|
||||||
WsConnectionFuture {
|
WSConnectionFuture {
|
||||||
msg_tx: Some(msg_tx),
|
msg_tx: Some(msg_tx),
|
||||||
ws_rx: Some(ws_rx),
|
ws_rx: Some(ws_rx),
|
||||||
fut: Box::pin(async move { connect_async(&addr).await }),
|
fut: Box::pin(async move { connect_async(&addr).await }),
|
||||||
@ -41,8 +41,8 @@ impl WsConnectionFuture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for WsConnectionFuture {
|
impl Future for WSConnectionFuture {
|
||||||
type Output = Result<WsStream, WsError>;
|
type Output = Result<WSStream, WSError>;
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
// [[pin]]
|
// [[pin]]
|
||||||
// poll async function. The following methods not work.
|
// poll async function. The following methods not work.
|
||||||
@ -66,7 +66,7 @@ impl Future for WsConnectionFuture {
|
|||||||
self.msg_tx.take().expect("WsConnection should be call once "),
|
self.msg_tx.take().expect("WsConnection should be call once "),
|
||||||
self.ws_rx.take().expect("WsConnection should be call once "),
|
self.ws_rx.take().expect("WsConnection should be call once "),
|
||||||
);
|
);
|
||||||
Poll::Ready(Ok(WsStream::new(msg_tx, ws_rx, stream)))
|
Poll::Ready(Ok(WSStream::new(msg_tx, ws_rx, stream)))
|
||||||
},
|
},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
tracing::debug!("🐴 ws connect failed: {:?}", error);
|
tracing::debug!("🐴 ws connect failed: {:?}", error);
|
||||||
@ -77,16 +77,16 @@ impl Future for WsConnectionFuture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Fut = BoxFuture<'static, Result<(), WsError>>;
|
type Fut = BoxFuture<'static, Result<(), WSError>>;
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
pub struct WsStream {
|
pub struct WSStream {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
msg_tx: MsgSender,
|
msg_tx: MsgSender,
|
||||||
#[pin]
|
#[pin]
|
||||||
inner: Option<(Fut, Fut)>,
|
inner: Option<(Fut, Fut)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsStream {
|
impl WSStream {
|
||||||
pub fn new(msg_tx: MsgSender, ws_rx: MsgReceiver, stream: WebSocketStream<MaybeTlsStream<TcpStream>>) -> Self {
|
pub fn new(msg_tx: MsgSender, ws_rx: MsgReceiver, stream: WebSocketStream<MaybeTlsStream<TcpStream>>) -> Self {
|
||||||
let (ws_write, ws_read) = stream.split();
|
let (ws_write, ws_read) = stream.split();
|
||||||
Self {
|
Self {
|
||||||
@ -110,7 +110,7 @@ impl WsStream {
|
|||||||
loop {
|
loop {
|
||||||
match rx.recv().await {
|
match rx.recv().await {
|
||||||
None => {
|
None => {
|
||||||
return Err(WsError::internal().context("WsStream rx closed unexpectedly"));
|
return Err(WSError::internal().context("WsStream rx closed unexpectedly"));
|
||||||
},
|
},
|
||||||
Some(result) => {
|
Some(result) => {
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
@ -136,12 +136,12 @@ impl WsStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for WsStream {
|
impl fmt::Debug for WSStream {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("WsStream").finish() }
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("WsStream").finish() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for WsStream {
|
impl Future for WSStream {
|
||||||
type Output = Result<(), WsError>;
|
type Output = Result<(), WSError>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let (mut ws_read, mut ws_write) = self.inner.take().unwrap();
|
let (mut ws_read, mut ws_write) = self.inner.take().unwrap();
|
||||||
@ -161,11 +161,11 @@ impl Future for WsStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_message(msg_tx: MsgSender, message: Result<Message, Error>) -> Result<(), WsError> {
|
fn send_message(msg_tx: MsgSender, message: Result<Message, Error>) -> Result<(), WSError> {
|
||||||
match message {
|
match message {
|
||||||
Ok(Message::Binary(bytes)) => msg_tx.unbounded_send(Message::Binary(bytes)).map_err(internal_error),
|
Ok(Message::Binary(bytes)) => msg_tx.unbounded_send(Message::Binary(bytes)).map_err(internal_error),
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(e) => Err(WsError::internal().context(e)),
|
Err(e) => Err(WSError::internal().context(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -6,7 +6,7 @@ use tokio_tungstenite::tungstenite::{http::StatusCode, Message};
|
|||||||
use url::ParseError;
|
use url::ParseError;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||||
pub struct WsError {
|
pub struct WSError {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
pub code: ErrorCode,
|
pub code: ErrorCode,
|
||||||
|
|
||||||
@ -14,11 +14,11 @@ pub struct WsError {
|
|||||||
pub msg: String,
|
pub msg: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! static_user_error {
|
macro_rules! static_ws_error {
|
||||||
($name:ident, $status:expr) => {
|
($name:ident, $status:expr) => {
|
||||||
#[allow(non_snake_case, missing_docs)]
|
#[allow(non_snake_case, missing_docs)]
|
||||||
pub fn $name() -> WsError {
|
pub fn $name() -> WSError {
|
||||||
WsError {
|
WSError {
|
||||||
code: $status,
|
code: $status,
|
||||||
msg: format!("{}", $status),
|
msg: format!("{}", $status),
|
||||||
}
|
}
|
||||||
@ -26,10 +26,10 @@ macro_rules! static_user_error {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsError {
|
impl WSError {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn new(code: ErrorCode) -> WsError {
|
pub(crate) fn new(code: ErrorCode) -> WSError {
|
||||||
WsError {
|
WSError {
|
||||||
code,
|
code,
|
||||||
msg: "".to_string(),
|
msg: "".to_string(),
|
||||||
}
|
}
|
||||||
@ -40,16 +40,16 @@ impl WsError {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
static_user_error!(internal, ErrorCode::InternalError);
|
static_ws_error!(internal, ErrorCode::InternalError);
|
||||||
static_user_error!(unsupported_message, ErrorCode::UnsupportedMessage);
|
static_ws_error!(unsupported_message, ErrorCode::UnsupportedMessage);
|
||||||
static_user_error!(unauthorized, ErrorCode::Unauthorized);
|
static_ws_error!(unauthorized, ErrorCode::Unauthorized);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn internal_error<T>(e: T) -> WsError
|
pub fn internal_error<T>(e: T) -> WSError
|
||||||
where
|
where
|
||||||
T: std::fmt::Debug,
|
T: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
WsError::internal().context(e)
|
WSError::internal().context(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, ProtoBuf_Enum, Display, PartialEq, Eq)]
|
#[derive(Debug, Clone, ProtoBuf_Enum, Display, PartialEq, Eq)]
|
||||||
@ -63,29 +63,29 @@ impl std::default::Default for ErrorCode {
|
|||||||
fn default() -> Self { ErrorCode::InternalError }
|
fn default() -> Self { ErrorCode::InternalError }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<url::ParseError> for WsError {
|
impl std::convert::From<url::ParseError> for WSError {
|
||||||
fn from(error: ParseError) -> Self { WsError::internal().context(error) }
|
fn from(error: ParseError) -> Self { WSError::internal().context(error) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<protobuf::ProtobufError> for WsError {
|
impl std::convert::From<protobuf::ProtobufError> for WSError {
|
||||||
fn from(error: protobuf::ProtobufError) -> Self { WsError::internal().context(error) }
|
fn from(error: protobuf::ProtobufError) -> Self { WSError::internal().context(error) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<futures_channel::mpsc::TrySendError<Message>> for WsError {
|
impl std::convert::From<futures_channel::mpsc::TrySendError<Message>> for WSError {
|
||||||
fn from(error: TrySendError<Message>) -> Self { WsError::internal().context(error) }
|
fn from(error: TrySendError<Message>) -> Self { WSError::internal().context(error) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<tokio_tungstenite::tungstenite::Error> for WsError {
|
impl std::convert::From<tokio_tungstenite::tungstenite::Error> for WSError {
|
||||||
fn from(error: tokio_tungstenite::tungstenite::Error) -> Self {
|
fn from(error: tokio_tungstenite::tungstenite::Error) -> Self {
|
||||||
match error {
|
match error {
|
||||||
tokio_tungstenite::tungstenite::Error::Http(response) => {
|
tokio_tungstenite::tungstenite::Error::Http(response) => {
|
||||||
if response.status() == StatusCode::UNAUTHORIZED {
|
if response.status() == StatusCode::UNAUTHORIZED {
|
||||||
WsError::unauthorized()
|
WSError::unauthorized()
|
||||||
} else {
|
} else {
|
||||||
WsError::internal().context(response)
|
WSError::internal().context(response)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => WsError::internal().context(error),
|
_ => WSError::internal().context(error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,33 +5,33 @@ use tokio_tungstenite::tungstenite::Message as TokioMessage;
|
|||||||
|
|
||||||
// Opti: using four bytes of the data to represent the source
|
// Opti: using four bytes of the data to represent the source
|
||||||
#[derive(ProtoBuf, Debug, Clone, Default)]
|
#[derive(ProtoBuf, Debug, Clone, Default)]
|
||||||
pub struct WsMessage {
|
pub struct WSMessage {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
pub module: WsModule,
|
pub module: WSModule,
|
||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ProtoBuf_Enum, Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(ProtoBuf_Enum, Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum WsModule {
|
pub enum WSModule {
|
||||||
Doc = 0,
|
Doc = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for WsModule {
|
impl std::default::Default for WSModule {
|
||||||
fn default() -> Self { WsModule::Doc }
|
fn default() -> Self { WSModule::Doc }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for WsModule {
|
impl ToString for WSModule {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
WsModule::Doc => "0".to_string(),
|
WSModule::Doc => "0".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<WsMessage> for TokioMessage {
|
impl std::convert::From<WSMessage> for TokioMessage {
|
||||||
fn from(msg: WsMessage) -> Self {
|
fn from(msg: WSMessage) -> Self {
|
||||||
let result: Result<Bytes, ::protobuf::ProtobufError> = msg.try_into();
|
let result: Result<Bytes, ::protobuf::ProtobufError> = msg.try_into();
|
||||||
match result {
|
match result {
|
||||||
Ok(bytes) => TokioMessage::Binary(bytes.to_vec()),
|
Ok(bytes) => TokioMessage::Binary(bytes.to_vec()),
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
|
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
|
||||||
|
|
||||||
#[derive(PartialEq,Clone,Default)]
|
#[derive(PartialEq,Clone,Default)]
|
||||||
pub struct WsError {
|
pub struct WSError {
|
||||||
// message fields
|
// message fields
|
||||||
pub code: ErrorCode,
|
pub code: ErrorCode,
|
||||||
pub msg: ::std::string::String,
|
pub msg: ::std::string::String,
|
||||||
@ -33,14 +33,14 @@ pub struct WsError {
|
|||||||
pub cached_size: ::protobuf::CachedSize,
|
pub cached_size: ::protobuf::CachedSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ::std::default::Default for &'a WsError {
|
impl<'a> ::std::default::Default for &'a WSError {
|
||||||
fn default() -> &'a WsError {
|
fn default() -> &'a WSError {
|
||||||
<WsError as ::protobuf::Message>::default_instance()
|
<WSError as ::protobuf::Message>::default_instance()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsError {
|
impl WSError {
|
||||||
pub fn new() -> WsError {
|
pub fn new() -> WSError {
|
||||||
::std::default::Default::default()
|
::std::default::Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ impl WsError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::Message for WsError {
|
impl ::protobuf::Message for WSError {
|
||||||
fn is_initialized(&self) -> bool {
|
fn is_initialized(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -161,8 +161,8 @@ impl ::protobuf::Message for WsError {
|
|||||||
Self::descriptor_static()
|
Self::descriptor_static()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> WsError {
|
fn new() -> WSError {
|
||||||
WsError::new()
|
WSError::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||||
@ -171,29 +171,29 @@ impl ::protobuf::Message for WsError {
|
|||||||
let mut fields = ::std::vec::Vec::new();
|
let mut fields = ::std::vec::Vec::new();
|
||||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ErrorCode>>(
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ErrorCode>>(
|
||||||
"code",
|
"code",
|
||||||
|m: &WsError| { &m.code },
|
|m: &WSError| { &m.code },
|
||||||
|m: &mut WsError| { &mut m.code },
|
|m: &mut WSError| { &mut m.code },
|
||||||
));
|
));
|
||||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
|
||||||
"msg",
|
"msg",
|
||||||
|m: &WsError| { &m.msg },
|
|m: &WSError| { &m.msg },
|
||||||
|m: &mut WsError| { &mut m.msg },
|
|m: &mut WSError| { &mut m.msg },
|
||||||
));
|
));
|
||||||
::protobuf::reflect::MessageDescriptor::new_pb_name::<WsError>(
|
::protobuf::reflect::MessageDescriptor::new_pb_name::<WSError>(
|
||||||
"WsError",
|
"WSError",
|
||||||
fields,
|
fields,
|
||||||
file_descriptor_proto()
|
file_descriptor_proto()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_instance() -> &'static WsError {
|
fn default_instance() -> &'static WSError {
|
||||||
static instance: ::protobuf::rt::LazyV2<WsError> = ::protobuf::rt::LazyV2::INIT;
|
static instance: ::protobuf::rt::LazyV2<WSError> = ::protobuf::rt::LazyV2::INIT;
|
||||||
instance.get(WsError::new)
|
instance.get(WSError::new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::Clear for WsError {
|
impl ::protobuf::Clear for WSError {
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.code = ErrorCode::InternalError;
|
self.code = ErrorCode::InternalError;
|
||||||
self.msg.clear();
|
self.msg.clear();
|
||||||
@ -201,13 +201,13 @@ impl ::protobuf::Clear for WsError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Debug for WsError {
|
impl ::std::fmt::Debug for WSError {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
::protobuf::text_format::fmt(self, f)
|
::protobuf::text_format::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::reflect::ProtobufValue for WsError {
|
impl ::protobuf::reflect::ProtobufValue for WSError {
|
||||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||||
::protobuf::reflect::ReflectValueRef::Message(self)
|
::protobuf::reflect::ReflectValueRef::Message(self)
|
||||||
}
|
}
|
||||||
@ -267,7 +267,7 @@ impl ::protobuf::reflect::ProtobufValue for ErrorCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||||
\n\x0cerrors.proto\";\n\x07WsError\x12\x1e\n\x04code\x18\x01\x20\x01(\
|
\n\x0cerrors.proto\";\n\x07WSError\x12\x1e\n\x04code\x18\x01\x20\x01(\
|
||||||
\x0e2\n.ErrorCodeR\x04code\x12\x10\n\x03msg\x18\x02\x20\x01(\tR\x03msg*H\
|
\x0e2\n.ErrorCodeR\x04code\x12\x10\n\x03msg\x18\x02\x20\x01(\tR\x03msg*H\
|
||||||
\n\tErrorCode\x12\x11\n\rInternalError\x10\0\x12\x16\n\x12UnsupportedMes\
|
\n\tErrorCode\x12\x11\n\rInternalError\x10\0\x12\x16\n\x12UnsupportedMes\
|
||||||
sage\x10\x01\x12\x10\n\x0cUnauthorized\x10\x02J\xab\x02\n\x06\x12\x04\0\
|
sage\x10\x01\x12\x10\n\x0cUnauthorized\x10\x02J\xab\x02\n\x06\x12\x04\0\
|
||||||
|
@ -24,38 +24,38 @@
|
|||||||
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
|
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
|
||||||
|
|
||||||
#[derive(PartialEq,Clone,Default)]
|
#[derive(PartialEq,Clone,Default)]
|
||||||
pub struct WsMessage {
|
pub struct WSMessage {
|
||||||
// message fields
|
// message fields
|
||||||
pub module: WsModule,
|
pub module: WSModule,
|
||||||
pub data: ::std::vec::Vec<u8>,
|
pub data: ::std::vec::Vec<u8>,
|
||||||
// special fields
|
// special fields
|
||||||
pub unknown_fields: ::protobuf::UnknownFields,
|
pub unknown_fields: ::protobuf::UnknownFields,
|
||||||
pub cached_size: ::protobuf::CachedSize,
|
pub cached_size: ::protobuf::CachedSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ::std::default::Default for &'a WsMessage {
|
impl<'a> ::std::default::Default for &'a WSMessage {
|
||||||
fn default() -> &'a WsMessage {
|
fn default() -> &'a WSMessage {
|
||||||
<WsMessage as ::protobuf::Message>::default_instance()
|
<WSMessage as ::protobuf::Message>::default_instance()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsMessage {
|
impl WSMessage {
|
||||||
pub fn new() -> WsMessage {
|
pub fn new() -> WSMessage {
|
||||||
::std::default::Default::default()
|
::std::default::Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
// .WsModule module = 1;
|
// .WSModule module = 1;
|
||||||
|
|
||||||
|
|
||||||
pub fn get_module(&self) -> WsModule {
|
pub fn get_module(&self) -> WSModule {
|
||||||
self.module
|
self.module
|
||||||
}
|
}
|
||||||
pub fn clear_module(&mut self) {
|
pub fn clear_module(&mut self) {
|
||||||
self.module = WsModule::Doc;
|
self.module = WSModule::Doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Param is passed by value, moved
|
// Param is passed by value, moved
|
||||||
pub fn set_module(&mut self, v: WsModule) {
|
pub fn set_module(&mut self, v: WSModule) {
|
||||||
self.module = v;
|
self.module = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ impl WsMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::Message for WsMessage {
|
impl ::protobuf::Message for WSMessage {
|
||||||
fn is_initialized(&self) -> bool {
|
fn is_initialized(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ impl ::protobuf::Message for WsMessage {
|
|||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn compute_size(&self) -> u32 {
|
fn compute_size(&self) -> u32 {
|
||||||
let mut my_size = 0;
|
let mut my_size = 0;
|
||||||
if self.module != WsModule::Doc {
|
if self.module != WSModule::Doc {
|
||||||
my_size += ::protobuf::rt::enum_size(1, self.module);
|
my_size += ::protobuf::rt::enum_size(1, self.module);
|
||||||
}
|
}
|
||||||
if !self.data.is_empty() {
|
if !self.data.is_empty() {
|
||||||
@ -125,7 +125,7 @@ impl ::protobuf::Message for WsMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
||||||
if self.module != WsModule::Doc {
|
if self.module != WSModule::Doc {
|
||||||
os.write_enum(1, ::protobuf::ProtobufEnum::value(&self.module))?;
|
os.write_enum(1, ::protobuf::ProtobufEnum::value(&self.module))?;
|
||||||
}
|
}
|
||||||
if !self.data.is_empty() {
|
if !self.data.is_empty() {
|
||||||
@ -161,78 +161,78 @@ impl ::protobuf::Message for WsMessage {
|
|||||||
Self::descriptor_static()
|
Self::descriptor_static()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> WsMessage {
|
fn new() -> WSMessage {
|
||||||
WsMessage::new()
|
WSMessage::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||||
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
||||||
descriptor.get(|| {
|
descriptor.get(|| {
|
||||||
let mut fields = ::std::vec::Vec::new();
|
let mut fields = ::std::vec::Vec::new();
|
||||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<WsModule>>(
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<WSModule>>(
|
||||||
"module",
|
"module",
|
||||||
|m: &WsMessage| { &m.module },
|
|m: &WSMessage| { &m.module },
|
||||||
|m: &mut WsMessage| { &mut m.module },
|
|m: &mut WSMessage| { &mut m.module },
|
||||||
));
|
));
|
||||||
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
|
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
|
||||||
"data",
|
"data",
|
||||||
|m: &WsMessage| { &m.data },
|
|m: &WSMessage| { &m.data },
|
||||||
|m: &mut WsMessage| { &mut m.data },
|
|m: &mut WSMessage| { &mut m.data },
|
||||||
));
|
));
|
||||||
::protobuf::reflect::MessageDescriptor::new_pb_name::<WsMessage>(
|
::protobuf::reflect::MessageDescriptor::new_pb_name::<WSMessage>(
|
||||||
"WsMessage",
|
"WSMessage",
|
||||||
fields,
|
fields,
|
||||||
file_descriptor_proto()
|
file_descriptor_proto()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_instance() -> &'static WsMessage {
|
fn default_instance() -> &'static WSMessage {
|
||||||
static instance: ::protobuf::rt::LazyV2<WsMessage> = ::protobuf::rt::LazyV2::INIT;
|
static instance: ::protobuf::rt::LazyV2<WSMessage> = ::protobuf::rt::LazyV2::INIT;
|
||||||
instance.get(WsMessage::new)
|
instance.get(WSMessage::new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::Clear for WsMessage {
|
impl ::protobuf::Clear for WSMessage {
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.module = WsModule::Doc;
|
self.module = WSModule::Doc;
|
||||||
self.data.clear();
|
self.data.clear();
|
||||||
self.unknown_fields.clear();
|
self.unknown_fields.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Debug for WsMessage {
|
impl ::std::fmt::Debug for WSMessage {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
::protobuf::text_format::fmt(self, f)
|
::protobuf::text_format::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::reflect::ProtobufValue for WsMessage {
|
impl ::protobuf::reflect::ProtobufValue for WSMessage {
|
||||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||||
::protobuf::reflect::ReflectValueRef::Message(self)
|
::protobuf::reflect::ReflectValueRef::Message(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
|
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
|
||||||
pub enum WsModule {
|
pub enum WSModule {
|
||||||
Doc = 0,
|
Doc = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::ProtobufEnum for WsModule {
|
impl ::protobuf::ProtobufEnum for WSModule {
|
||||||
fn value(&self) -> i32 {
|
fn value(&self) -> i32 {
|
||||||
*self as i32
|
*self as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_i32(value: i32) -> ::std::option::Option<WsModule> {
|
fn from_i32(value: i32) -> ::std::option::Option<WSModule> {
|
||||||
match value {
|
match value {
|
||||||
0 => ::std::option::Option::Some(WsModule::Doc),
|
0 => ::std::option::Option::Some(WSModule::Doc),
|
||||||
_ => ::std::option::Option::None
|
_ => ::std::option::Option::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn values() -> &'static [Self] {
|
fn values() -> &'static [Self] {
|
||||||
static values: &'static [WsModule] = &[
|
static values: &'static [WSModule] = &[
|
||||||
WsModule::Doc,
|
WSModule::Doc,
|
||||||
];
|
];
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
@ -240,30 +240,30 @@ impl ::protobuf::ProtobufEnum for WsModule {
|
|||||||
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
|
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
|
||||||
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
||||||
descriptor.get(|| {
|
descriptor.get(|| {
|
||||||
::protobuf::reflect::EnumDescriptor::new_pb_name::<WsModule>("WsModule", file_descriptor_proto())
|
::protobuf::reflect::EnumDescriptor::new_pb_name::<WSModule>("WSModule", file_descriptor_proto())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::marker::Copy for WsModule {
|
impl ::std::marker::Copy for WSModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::default::Default for WsModule {
|
impl ::std::default::Default for WSModule {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
WsModule::Doc
|
WSModule::Doc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::reflect::ProtobufValue for WsModule {
|
impl ::protobuf::reflect::ProtobufValue for WSModule {
|
||||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||||
::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
|
::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||||
\n\tmsg.proto\"B\n\tWsMessage\x12!\n\x06module\x18\x01\x20\x01(\x0e2\t.W\
|
\n\tmsg.proto\"B\n\tWSMessage\x12!\n\x06module\x18\x01\x20\x01(\x0e2\t.W\
|
||||||
sModuleR\x06module\x12\x12\n\x04data\x18\x02\x20\x01(\x0cR\x04data*\x13\
|
SModuleR\x06module\x12\x12\n\x04data\x18\x02\x20\x01(\x0cR\x04data*\x13\
|
||||||
\n\x08WsModule\x12\x07\n\x03Doc\x10\0J\xd9\x01\n\x06\x12\x04\0\0\x08\x01\
|
\n\x08WSModule\x12\x07\n\x03Doc\x10\0J\xd9\x01\n\x06\x12\x04\0\0\x08\x01\
|
||||||
\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\
|
\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\
|
||||||
\n\n\x03\x04\0\x01\x12\x03\x02\x08\x11\n\x0b\n\x04\x04\0\x02\0\x12\x03\
|
\n\n\x03\x04\0\x01\x12\x03\x02\x08\x11\n\x0b\n\x04\x04\0\x02\0\x12\x03\
|
||||||
\x03\x04\x18\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x03\x04\x0c\n\x0c\n\x05\
|
\x03\x04\x18\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x03\x04\x0c\n\x0c\n\x05\
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
message WsError {
|
message WSError {
|
||||||
ErrorCode code = 1;
|
ErrorCode code = 1;
|
||||||
string msg = 2;
|
string msg = 2;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
message WsMessage {
|
message WSMessage {
|
||||||
WsModule module = 1;
|
WSModule module = 1;
|
||||||
bytes data = 2;
|
bytes data = 2;
|
||||||
}
|
}
|
||||||
enum WsModule {
|
enum WSModule {
|
||||||
Doc = 0;
|
Doc = 0;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::{WsConnectionFuture, WsStream},
|
connect::{WSConnectionFuture, WSStream},
|
||||||
errors::WsError,
|
errors::WSError,
|
||||||
WsMessage,
|
WSMessage,
|
||||||
WsModule,
|
WSModule,
|
||||||
};
|
};
|
||||||
use backend_service::errors::ServerError;
|
use backend_service::errors::ServerError;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
@ -30,36 +30,36 @@ use tokio_tungstenite::tungstenite::{
|
|||||||
|
|
||||||
pub type MsgReceiver = UnboundedReceiver<Message>;
|
pub type MsgReceiver = UnboundedReceiver<Message>;
|
||||||
pub type MsgSender = UnboundedSender<Message>;
|
pub type MsgSender = UnboundedSender<Message>;
|
||||||
type Handlers = DashMap<WsModule, Arc<dyn WsMessageReceiver>>;
|
type Handlers = DashMap<WSModule, Arc<dyn WSMessageReceiver>>;
|
||||||
|
|
||||||
pub trait WsMessageReceiver: Sync + Send + 'static {
|
pub trait WSMessageReceiver: Sync + Send + 'static {
|
||||||
fn source(&self) -> WsModule;
|
fn source(&self) -> WSModule;
|
||||||
fn receive_message(&self, msg: WsMessage);
|
fn receive_message(&self, msg: WSMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WsController {
|
pub struct WSController {
|
||||||
handlers: Handlers,
|
handlers: Handlers,
|
||||||
state_notify: Arc<broadcast::Sender<WsConnectState>>,
|
state_notify: Arc<broadcast::Sender<WSConnectState>>,
|
||||||
sender_ctrl: Arc<RwLock<WsSenderController>>,
|
sender_ctrl: Arc<RwLock<WSSenderController>>,
|
||||||
addr: Arc<RwLock<Option<String>>>,
|
addr: Arc<RwLock<Option<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for WsController {
|
impl std::default::Default for WSController {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let (state_notify, _) = broadcast::channel(16);
|
let (state_notify, _) = broadcast::channel(16);
|
||||||
Self {
|
Self {
|
||||||
handlers: DashMap::new(),
|
handlers: DashMap::new(),
|
||||||
sender_ctrl: Arc::new(RwLock::new(WsSenderController::default())),
|
sender_ctrl: Arc::new(RwLock::new(WSSenderController::default())),
|
||||||
state_notify: Arc::new(state_notify),
|
state_notify: Arc::new(state_notify),
|
||||||
addr: Arc::new(RwLock::new(None)),
|
addr: Arc::new(RwLock::new(None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsController {
|
impl WSController {
|
||||||
pub fn new() -> Self { WsController::default() }
|
pub fn new() -> Self { WSController::default() }
|
||||||
|
|
||||||
pub fn add_receiver(&self, handler: Arc<dyn WsMessageReceiver>) -> Result<(), WsError> {
|
pub fn add_receiver(&self, handler: Arc<dyn WSMessageReceiver>) -> Result<(), WSError> {
|
||||||
let source = handler.source();
|
let source = handler.source();
|
||||||
if self.handlers.contains_key(&source) {
|
if self.handlers.contains_key(&source) {
|
||||||
log::error!("WsSource's {:?} is already registered", source);
|
log::error!("WsSource's {:?} is already registered", source);
|
||||||
@ -74,7 +74,7 @@ impl WsController {
|
|||||||
self.connect(addr, strategy).await
|
self.connect(addr, strategy).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn stop(&self) { self.sender_ctrl.write().set_state(WsConnectState::Disconnected); }
|
pub async fn stop(&self) { self.sender_ctrl.write().set_state(WSConnectState::Disconnected); }
|
||||||
|
|
||||||
async fn connect<T, I>(&self, addr: String, strategy: T) -> Result<(), ServerError>
|
async fn connect<T, I>(&self, addr: String, strategy: T) -> Result<(), ServerError>
|
||||||
where
|
where
|
||||||
@ -83,25 +83,25 @@ impl WsController {
|
|||||||
{
|
{
|
||||||
let (ret, rx) = oneshot::channel::<Result<(), ServerError>>();
|
let (ret, rx) = oneshot::channel::<Result<(), ServerError>>();
|
||||||
*self.addr.write() = Some(addr.clone());
|
*self.addr.write() = Some(addr.clone());
|
||||||
let action = WsConnectAction {
|
let action = WSConnectAction {
|
||||||
addr,
|
addr,
|
||||||
handlers: self.handlers.clone(),
|
handlers: self.handlers.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let retry = Retry::spawn(strategy, action);
|
let retry = Retry::spawn(strategy, action);
|
||||||
let sender_ctrl = self.sender_ctrl.clone();
|
let sender_ctrl = self.sender_ctrl.clone();
|
||||||
sender_ctrl.write().set_state(WsConnectState::Connecting);
|
sender_ctrl.write().set_state(WSConnectState::Connecting);
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
match retry.await {
|
match retry.await {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
let WsConnectResult {
|
let WSConnectResult {
|
||||||
stream,
|
stream,
|
||||||
handlers_fut,
|
handlers_fut,
|
||||||
sender,
|
sender,
|
||||||
} = result;
|
} = result;
|
||||||
sender_ctrl.write().set_sender(sender);
|
sender_ctrl.write().set_sender(sender);
|
||||||
sender_ctrl.write().set_state(WsConnectState::Connected);
|
sender_ctrl.write().set_state(WSConnectState::Connected);
|
||||||
let _ = ret.send(Ok(()));
|
let _ = ret.send(Ok(()));
|
||||||
spawn_stream_and_handlers(stream, handlers_fut, sender_ctrl.clone()).await;
|
spawn_stream_and_handlers(stream, handlers_fut, sender_ctrl.clone()).await;
|
||||||
},
|
},
|
||||||
@ -131,20 +131,20 @@ impl WsController {
|
|||||||
self.connect(addr, strategy).await
|
self.connect(addr, strategy).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe_state(&self) -> broadcast::Receiver<WsConnectState> { self.state_notify.subscribe() }
|
pub fn subscribe_state(&self) -> broadcast::Receiver<WSConnectState> { self.state_notify.subscribe() }
|
||||||
|
|
||||||
pub fn sender(&self) -> Result<Arc<WsSender>, WsError> {
|
pub fn sender(&self) -> Result<Arc<WSSender>, WSError> {
|
||||||
match self.sender_ctrl.read().sender() {
|
match self.sender_ctrl.read().sender() {
|
||||||
None => Err(WsError::internal().context("WsSender is not initialized, should call connect first")),
|
None => Err(WSError::internal().context("WsSender is not initialized, should call connect first")),
|
||||||
Some(sender) => Ok(sender),
|
Some(sender) => Ok(sender),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn spawn_stream_and_handlers(
|
async fn spawn_stream_and_handlers(
|
||||||
stream: WsStream,
|
stream: WSStream,
|
||||||
handlers: WsHandlerFuture,
|
handlers: WSHandlerFuture,
|
||||||
sender_ctrl: Arc<RwLock<WsSenderController>>,
|
sender_ctrl: Arc<RwLock<WSSenderController>>,
|
||||||
) {
|
) {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
result = stream => {
|
result = stream => {
|
||||||
@ -157,14 +157,14 @@ async fn spawn_stream_and_handlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
pub struct WsHandlerFuture {
|
pub struct WSHandlerFuture {
|
||||||
#[pin]
|
#[pin]
|
||||||
msg_rx: MsgReceiver,
|
msg_rx: MsgReceiver,
|
||||||
// Opti: Hashmap would be better
|
// Opti: Hashmap would be better
|
||||||
handlers: Handlers,
|
handlers: Handlers,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsHandlerFuture {
|
impl WSHandlerFuture {
|
||||||
fn new(handlers: Handlers, msg_rx: MsgReceiver) -> Self { Self { msg_rx, handlers } }
|
fn new(handlers: Handlers, msg_rx: MsgReceiver) -> Self { Self { msg_rx, handlers } }
|
||||||
|
|
||||||
fn handler_ws_message(&self, message: Message) {
|
fn handler_ws_message(&self, message: Message) {
|
||||||
@ -175,7 +175,7 @@ impl WsHandlerFuture {
|
|||||||
|
|
||||||
fn handle_binary_message(&self, bytes: Vec<u8>) {
|
fn handle_binary_message(&self, bytes: Vec<u8>) {
|
||||||
let bytes = Bytes::from(bytes);
|
let bytes = Bytes::from(bytes);
|
||||||
match WsMessage::try_from(bytes) {
|
match WSMessage::try_from(bytes) {
|
||||||
Ok(message) => match self.handlers.get(&message.module) {
|
Ok(message) => match self.handlers.get(&message.module) {
|
||||||
None => log::error!("Can't find any handler for message: {:?}", message),
|
None => log::error!("Can't find any handler for message: {:?}", message),
|
||||||
Some(handler) => handler.receive_message(message.clone()),
|
Some(handler) => handler.receive_message(message.clone()),
|
||||||
@ -187,7 +187,7 @@ impl WsHandlerFuture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for WsHandlerFuture {
|
impl Future for WSHandlerFuture {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
loop {
|
loop {
|
||||||
@ -202,37 +202,37 @@ impl Future for WsHandlerFuture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct WsSender {
|
pub struct WSSender {
|
||||||
ws_tx: MsgSender,
|
ws_tx: MsgSender,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsSender {
|
impl WSSender {
|
||||||
pub fn send_msg<T: Into<WsMessage>>(&self, msg: T) -> Result<(), WsError> {
|
pub fn send_msg<T: Into<WSMessage>>(&self, msg: T) -> Result<(), WSError> {
|
||||||
let msg = msg.into();
|
let msg = msg.into();
|
||||||
let _ = self
|
let _ = self
|
||||||
.ws_tx
|
.ws_tx
|
||||||
.unbounded_send(msg.into())
|
.unbounded_send(msg.into())
|
||||||
.map_err(|e| WsError::internal().context(e))?;
|
.map_err(|e| WSError::internal().context(e))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_text(&self, source: &WsModule, text: &str) -> Result<(), WsError> {
|
pub fn send_text(&self, source: &WSModule, text: &str) -> Result<(), WSError> {
|
||||||
let msg = WsMessage {
|
let msg = WSMessage {
|
||||||
module: source.clone(),
|
module: source.clone(),
|
||||||
data: text.as_bytes().to_vec(),
|
data: text.as_bytes().to_vec(),
|
||||||
};
|
};
|
||||||
self.send_msg(msg)
|
self.send_msg(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_binary(&self, source: &WsModule, bytes: Vec<u8>) -> Result<(), WsError> {
|
pub fn send_binary(&self, source: &WSModule, bytes: Vec<u8>) -> Result<(), WSError> {
|
||||||
let msg = WsMessage {
|
let msg = WSMessage {
|
||||||
module: source.clone(),
|
module: source.clone(),
|
||||||
data: bytes,
|
data: bytes,
|
||||||
};
|
};
|
||||||
self.send_msg(msg)
|
self.send_msg(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_disconnect(&self, reason: &str) -> Result<(), WsError> {
|
pub fn send_disconnect(&self, reason: &str) -> Result<(), WSError> {
|
||||||
let frame = CloseFrame {
|
let frame = CloseFrame {
|
||||||
code: CloseCode::Normal,
|
code: CloseCode::Normal,
|
||||||
reason: reason.to_owned().into(),
|
reason: reason.to_owned().into(),
|
||||||
@ -241,44 +241,44 @@ impl WsSender {
|
|||||||
let _ = self
|
let _ = self
|
||||||
.ws_tx
|
.ws_tx
|
||||||
.unbounded_send(msg)
|
.unbounded_send(msg)
|
||||||
.map_err(|e| WsError::internal().context(e))?;
|
.map_err(|e| WSError::internal().context(e))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WsConnectAction {
|
struct WSConnectAction {
|
||||||
addr: String,
|
addr: String,
|
||||||
handlers: Handlers,
|
handlers: Handlers,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Action for WsConnectAction {
|
impl Action for WSConnectAction {
|
||||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Item, Self::Error>> + Send + Sync>>;
|
type Future = Pin<Box<dyn Future<Output = Result<Self::Item, Self::Error>> + Send + Sync>>;
|
||||||
type Item = WsConnectResult;
|
type Item = WSConnectResult;
|
||||||
type Error = WsError;
|
type Error = WSError;
|
||||||
|
|
||||||
fn run(&mut self) -> Self::Future {
|
fn run(&mut self) -> Self::Future {
|
||||||
let addr = self.addr.clone();
|
let addr = self.addr.clone();
|
||||||
let handlers = self.handlers.clone();
|
let handlers = self.handlers.clone();
|
||||||
Box::pin(WsConnectActionFut::new(addr, handlers))
|
Box::pin(WSConnectActionFut::new(addr, handlers))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WsConnectResult {
|
struct WSConnectResult {
|
||||||
stream: WsStream,
|
stream: WSStream,
|
||||||
handlers_fut: WsHandlerFuture,
|
handlers_fut: WSHandlerFuture,
|
||||||
sender: WsSender,
|
sender: WSSender,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
struct WsConnectActionFut {
|
struct WSConnectActionFut {
|
||||||
addr: String,
|
addr: String,
|
||||||
#[pin]
|
#[pin]
|
||||||
conn: WsConnectionFuture,
|
conn: WSConnectionFuture,
|
||||||
handlers_fut: Option<WsHandlerFuture>,
|
handlers_fut: Option<WSHandlerFuture>,
|
||||||
sender: Option<WsSender>,
|
sender: Option<WSSender>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsConnectActionFut {
|
impl WSConnectActionFut {
|
||||||
fn new(addr: String, handlers: Handlers) -> Self {
|
fn new(addr: String, handlers: Handlers) -> Self {
|
||||||
// Stream User
|
// Stream User
|
||||||
// ┌───────────────┐ ┌──────────────┐
|
// ┌───────────────┐ ┌──────────────┐
|
||||||
@ -292,9 +292,9 @@ impl WsConnectActionFut {
|
|||||||
// └───────────────┘ └──────────────┘
|
// └───────────────┘ └──────────────┘
|
||||||
let (msg_tx, msg_rx) = futures_channel::mpsc::unbounded();
|
let (msg_tx, msg_rx) = futures_channel::mpsc::unbounded();
|
||||||
let (ws_tx, ws_rx) = futures_channel::mpsc::unbounded();
|
let (ws_tx, ws_rx) = futures_channel::mpsc::unbounded();
|
||||||
let sender = WsSender { ws_tx };
|
let sender = WSSender { ws_tx };
|
||||||
let handlers_fut = WsHandlerFuture::new(handlers, msg_rx);
|
let handlers_fut = WSHandlerFuture::new(handlers, msg_rx);
|
||||||
let conn = WsConnectionFuture::new(msg_tx, ws_rx, addr.clone());
|
let conn = WSConnectionFuture::new(msg_tx, ws_rx, addr.clone());
|
||||||
Self {
|
Self {
|
||||||
addr,
|
addr,
|
||||||
conn,
|
conn,
|
||||||
@ -304,15 +304,15 @@ impl WsConnectActionFut {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for WsConnectActionFut {
|
impl Future for WSConnectActionFut {
|
||||||
type Output = Result<WsConnectResult, WsError>;
|
type Output = Result<WSConnectResult, WSError>;
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let mut this = self.project();
|
let mut this = self.project();
|
||||||
match ready!(this.conn.as_mut().poll(cx)) {
|
match ready!(this.conn.as_mut().poll(cx)) {
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
let handlers_fut = this.handlers_fut.take().expect("Only take once");
|
let handlers_fut = this.handlers_fut.take().expect("Only take once");
|
||||||
let sender = this.sender.take().expect("Only take once");
|
let sender = this.sender.take().expect("Only take once");
|
||||||
Poll::Ready(Ok(WsConnectResult {
|
Poll::Ready(Ok(WSConnectResult {
|
||||||
stream,
|
stream,
|
||||||
handlers_fut,
|
handlers_fut,
|
||||||
sender,
|
sender,
|
||||||
@ -324,39 +324,39 @@ impl Future for WsConnectActionFut {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub enum WsConnectState {
|
pub enum WSConnectState {
|
||||||
Init,
|
Init,
|
||||||
Connecting,
|
Connecting,
|
||||||
Connected,
|
Connected,
|
||||||
Disconnected,
|
Disconnected,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for WsConnectState {
|
impl std::fmt::Display for WSConnectState {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
WsConnectState::Init => f.write_str("Init"),
|
WSConnectState::Init => f.write_str("Init"),
|
||||||
WsConnectState::Connected => f.write_str("Connecting"),
|
WSConnectState::Connected => f.write_str("Connecting"),
|
||||||
WsConnectState::Connecting => f.write_str("Connected"),
|
WSConnectState::Connecting => f.write_str("Connected"),
|
||||||
WsConnectState::Disconnected => f.write_str("Disconnected"),
|
WSConnectState::Disconnected => f.write_str("Disconnected"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for WsConnectState {
|
impl std::fmt::Debug for WSConnectState {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&format!("{}", self)) }
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&format!("{}", self)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WsSenderController {
|
struct WSSenderController {
|
||||||
state: WsConnectState,
|
state: WSConnectState,
|
||||||
state_notify: Arc<broadcast::Sender<WsConnectState>>,
|
state_notify: Arc<broadcast::Sender<WSConnectState>>,
|
||||||
sender: Option<Arc<WsSender>>,
|
sender: Option<Arc<WSSender>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsSenderController {
|
impl WSSenderController {
|
||||||
fn set_sender(&mut self, sender: WsSender) { self.sender = Some(Arc::new(sender)); }
|
fn set_sender(&mut self, sender: WSSender) { self.sender = Some(Arc::new(sender)); }
|
||||||
|
|
||||||
fn set_state(&mut self, state: WsConnectState) {
|
fn set_state(&mut self, state: WSConnectState) {
|
||||||
if state != WsConnectState::Connected {
|
if state != WSConnectState::Connected {
|
||||||
self.sender = None;
|
self.sender = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,24 +364,24 @@ impl WsSenderController {
|
|||||||
let _ = self.state_notify.send(self.state.clone());
|
let _ = self.state_notify.send(self.state.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_error(&mut self, error: WsError) {
|
fn set_error(&mut self, error: WSError) {
|
||||||
log::error!("{:?}", error);
|
log::error!("{:?}", error);
|
||||||
self.set_state(WsConnectState::Disconnected);
|
self.set_state(WSConnectState::Disconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sender(&self) -> Option<Arc<WsSender>> { self.sender.clone() }
|
fn sender(&self) -> Option<Arc<WSSender>> { self.sender.clone() }
|
||||||
|
|
||||||
fn is_connecting(&self) -> bool { self.state == WsConnectState::Connecting }
|
fn is_connecting(&self) -> bool { self.state == WSConnectState::Connecting }
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn is_connected(&self) -> bool { self.state == WsConnectState::Connected }
|
fn is_connected(&self) -> bool { self.state == WSConnectState::Connected }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for WsSenderController {
|
impl std::default::Default for WSSenderController {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let (state_notify, _) = broadcast::channel(16);
|
let (state_notify, _) = broadcast::channel(16);
|
||||||
WsSenderController {
|
WSSenderController {
|
||||||
state: WsConnectState::Init,
|
state: WSConnectState::Init,
|
||||||
state_notify: Arc::new(state_notify),
|
state_notify: Arc::new(state_notify),
|
||||||
sender: None,
|
sender: None,
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user