chore: rename struct

This commit is contained in:
appflowy 2022-03-10 17:14:10 +08:00
parent e45be3b81e
commit 7ac6a1dc89
72 changed files with 1788 additions and 785 deletions

View File

@ -13,6 +13,7 @@ import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
import 'package:get_it/get_it.dart';

View File

@ -1,4 +1,5 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';

View File

@ -1,4 +1,5 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';

View File

@ -1,4 +1,5 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';

View File

@ -1,4 +1,5 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';

View File

@ -1,4 +1,5 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';

View File

@ -1,4 +1,4 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';

View File

@ -1,5 +1,6 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:equatable/equatable.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
class GridInfo {
List<Row> rows;

View File

@ -3,6 +3,7 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
class GridService {
Future<Either<Grid, FlowyError>> openGrid({required String gridId}) async {

View File

@ -6,7 +6,7 @@ import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scrollview.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/material.dart';
import 'package:styled_widget/styled_widget.dart';

View File

@ -1,4 +1,4 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'sizes.dart';

View File

@ -1,4 +1,5 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter/widgets.dart';
import 'checkbox_cell.dart';
import 'date_cell.dart';

View File

@ -1,6 +1,5 @@
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -1,6 +1,7 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -1,6 +1,7 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/cell_bloc/date_cell_bloc.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -1,6 +1,7 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/cell_bloc/number_cell_bloc.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -1,6 +1,7 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter/material.dart';
class SingleSelectCell extends StatefulWidget {

View File

@ -1,6 +1,7 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/cell_bloc/text_cell_bloc.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -5,7 +5,7 @@ import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row;
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -2,7 +2,7 @@ import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.d
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -22,7 +22,6 @@ import 'package:flowy_sdk/protobuf/flowy-user-data-model/protobuf.dart';
import 'package:flowy_sdk/protobuf/dart-ffi/protobuf.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/protobuf.dart';
import 'package:flowy_sdk/protobuf/flowy-block/protobuf.dart';
import 'package:flowy_sdk/protobuf/flowy-collaboration/protobuf.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart';
// ignore: unused_import

View File

@ -1,5 +1,5 @@
// Auto-generated, do not edit
export './folder_info.pb.dart';
export './ws_data.pb.dart';
export './text_block_info.pb.dart';
export './revision.pb.dart';
export './document_info.pb.dart';

View File

@ -0,0 +1,412 @@
///
// Generated code. Do not modify.
// source: text_block_info.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
import 'dart:core' as $core;
import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb;
import 'revision.pb.dart' as $0;
class CreateTextBlockParams extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateTextBlockParams', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions', subBuilder: $0.RepeatedRevision.create)
..hasRequiredFields = false
;
CreateTextBlockParams._() : super();
factory CreateTextBlockParams({
$core.String? id,
$0.RepeatedRevision? revisions,
}) {
final _result = create();
if (id != null) {
_result.id = id;
}
if (revisions != null) {
_result.revisions = revisions;
}
return _result;
}
factory CreateTextBlockParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory CreateTextBlockParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
CreateTextBlockParams clone() => CreateTextBlockParams()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
CreateTextBlockParams copyWith(void Function(CreateTextBlockParams) updates) => super.copyWith((message) => updates(message as CreateTextBlockParams)) as CreateTextBlockParams; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static CreateTextBlockParams create() => CreateTextBlockParams._();
CreateTextBlockParams createEmptyInstance() => create();
static $pb.PbList<CreateTextBlockParams> createRepeated() => $pb.PbList<CreateTextBlockParams>();
@$core.pragma('dart2js:noInline')
static CreateTextBlockParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreateTextBlockParams>(create);
static CreateTextBlockParams? _defaultInstance;
@$pb.TagNumber(1)
$core.String get id => $_getSZ(0);
@$pb.TagNumber(1)
set id($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasId() => $_has(0);
@$pb.TagNumber(1)
void clearId() => clearField(1);
@$pb.TagNumber(2)
$0.RepeatedRevision get revisions => $_getN(1);
@$pb.TagNumber(2)
set revisions($0.RepeatedRevision v) { setField(2, v); }
@$pb.TagNumber(2)
$core.bool hasRevisions() => $_has(1);
@$pb.TagNumber(2)
void clearRevisions() => clearField(2);
@$pb.TagNumber(2)
$0.RepeatedRevision ensureRevisions() => $_ensure(1);
}
class TextBlockInfo extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TextBlockInfo', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'text')
..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId')
..aInt64(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'baseRevId')
..hasRequiredFields = false
;
TextBlockInfo._() : super();
factory TextBlockInfo({
$core.String? blockId,
$core.String? text,
$fixnum.Int64? revId,
$fixnum.Int64? baseRevId,
}) {
final _result = create();
if (blockId != null) {
_result.blockId = blockId;
}
if (text != null) {
_result.text = text;
}
if (revId != null) {
_result.revId = revId;
}
if (baseRevId != null) {
_result.baseRevId = baseRevId;
}
return _result;
}
factory TextBlockInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory TextBlockInfo.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
TextBlockInfo clone() => TextBlockInfo()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
TextBlockInfo copyWith(void Function(TextBlockInfo) updates) => super.copyWith((message) => updates(message as TextBlockInfo)) as TextBlockInfo; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static TextBlockInfo create() => TextBlockInfo._();
TextBlockInfo createEmptyInstance() => create();
static $pb.PbList<TextBlockInfo> createRepeated() => $pb.PbList<TextBlockInfo>();
@$core.pragma('dart2js:noInline')
static TextBlockInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<TextBlockInfo>(create);
static TextBlockInfo? _defaultInstance;
@$pb.TagNumber(1)
$core.String get blockId => $_getSZ(0);
@$pb.TagNumber(1)
set blockId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasBlockId() => $_has(0);
@$pb.TagNumber(1)
void clearBlockId() => clearField(1);
@$pb.TagNumber(2)
$core.String get text => $_getSZ(1);
@$pb.TagNumber(2)
set text($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasText() => $_has(1);
@$pb.TagNumber(2)
void clearText() => clearField(2);
@$pb.TagNumber(3)
$fixnum.Int64 get revId => $_getI64(2);
@$pb.TagNumber(3)
set revId($fixnum.Int64 v) { $_setInt64(2, v); }
@$pb.TagNumber(3)
$core.bool hasRevId() => $_has(2);
@$pb.TagNumber(3)
void clearRevId() => clearField(3);
@$pb.TagNumber(4)
$fixnum.Int64 get baseRevId => $_getI64(3);
@$pb.TagNumber(4)
set baseRevId($fixnum.Int64 v) { $_setInt64(3, v); }
@$pb.TagNumber(4)
$core.bool hasBaseRevId() => $_has(3);
@$pb.TagNumber(4)
void clearBaseRevId() => clearField(4);
}
class ResetTextBlockParams extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ResetTextBlockParams', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions', subBuilder: $0.RepeatedRevision.create)
..hasRequiredFields = false
;
ResetTextBlockParams._() : super();
factory ResetTextBlockParams({
$core.String? blockId,
$0.RepeatedRevision? revisions,
}) {
final _result = create();
if (blockId != null) {
_result.blockId = blockId;
}
if (revisions != null) {
_result.revisions = revisions;
}
return _result;
}
factory ResetTextBlockParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory ResetTextBlockParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
ResetTextBlockParams clone() => ResetTextBlockParams()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
ResetTextBlockParams copyWith(void Function(ResetTextBlockParams) updates) => super.copyWith((message) => updates(message as ResetTextBlockParams)) as ResetTextBlockParams; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static ResetTextBlockParams create() => ResetTextBlockParams._();
ResetTextBlockParams createEmptyInstance() => create();
static $pb.PbList<ResetTextBlockParams> createRepeated() => $pb.PbList<ResetTextBlockParams>();
@$core.pragma('dart2js:noInline')
static ResetTextBlockParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ResetTextBlockParams>(create);
static ResetTextBlockParams? _defaultInstance;
@$pb.TagNumber(1)
$core.String get blockId => $_getSZ(0);
@$pb.TagNumber(1)
set blockId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasBlockId() => $_has(0);
@$pb.TagNumber(1)
void clearBlockId() => clearField(1);
@$pb.TagNumber(2)
$0.RepeatedRevision get revisions => $_getN(1);
@$pb.TagNumber(2)
set revisions($0.RepeatedRevision v) { setField(2, v); }
@$pb.TagNumber(2)
$core.bool hasRevisions() => $_has(1);
@$pb.TagNumber(2)
void clearRevisions() => clearField(2);
@$pb.TagNumber(2)
$0.RepeatedRevision ensureRevisions() => $_ensure(1);
}
class TextBlockDelta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TextBlockDelta', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deltaStr')
..hasRequiredFields = false
;
TextBlockDelta._() : super();
factory TextBlockDelta({
$core.String? blockId,
$core.String? deltaStr,
}) {
final _result = create();
if (blockId != null) {
_result.blockId = blockId;
}
if (deltaStr != null) {
_result.deltaStr = deltaStr;
}
return _result;
}
factory TextBlockDelta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory TextBlockDelta.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
TextBlockDelta clone() => TextBlockDelta()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
TextBlockDelta copyWith(void Function(TextBlockDelta) updates) => super.copyWith((message) => updates(message as TextBlockDelta)) as TextBlockDelta; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static TextBlockDelta create() => TextBlockDelta._();
TextBlockDelta createEmptyInstance() => create();
static $pb.PbList<TextBlockDelta> createRepeated() => $pb.PbList<TextBlockDelta>();
@$core.pragma('dart2js:noInline')
static TextBlockDelta getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<TextBlockDelta>(create);
static TextBlockDelta? _defaultInstance;
@$pb.TagNumber(1)
$core.String get blockId => $_getSZ(0);
@$pb.TagNumber(1)
set blockId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasBlockId() => $_has(0);
@$pb.TagNumber(1)
void clearBlockId() => clearField(1);
@$pb.TagNumber(2)
$core.String get deltaStr => $_getSZ(1);
@$pb.TagNumber(2)
set deltaStr($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasDeltaStr() => $_has(1);
@$pb.TagNumber(2)
void clearDeltaStr() => clearField(2);
}
class NewDocUser extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'NewDocUser', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'userId')
..aInt64(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId')
..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
..hasRequiredFields = false
;
NewDocUser._() : super();
factory NewDocUser({
$core.String? userId,
$fixnum.Int64? revId,
$core.String? docId,
}) {
final _result = create();
if (userId != null) {
_result.userId = userId;
}
if (revId != null) {
_result.revId = revId;
}
if (docId != null) {
_result.docId = docId;
}
return _result;
}
factory NewDocUser.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory NewDocUser.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
NewDocUser clone() => NewDocUser()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
NewDocUser copyWith(void Function(NewDocUser) updates) => super.copyWith((message) => updates(message as NewDocUser)) as NewDocUser; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static NewDocUser create() => NewDocUser._();
NewDocUser createEmptyInstance() => create();
static $pb.PbList<NewDocUser> createRepeated() => $pb.PbList<NewDocUser>();
@$core.pragma('dart2js:noInline')
static NewDocUser getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<NewDocUser>(create);
static NewDocUser? _defaultInstance;
@$pb.TagNumber(1)
$core.String get userId => $_getSZ(0);
@$pb.TagNumber(1)
set userId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasUserId() => $_has(0);
@$pb.TagNumber(1)
void clearUserId() => clearField(1);
@$pb.TagNumber(2)
$fixnum.Int64 get revId => $_getI64(1);
@$pb.TagNumber(2)
set revId($fixnum.Int64 v) { $_setInt64(1, v); }
@$pb.TagNumber(2)
$core.bool hasRevId() => $_has(1);
@$pb.TagNumber(2)
void clearRevId() => clearField(2);
@$pb.TagNumber(3)
$core.String get docId => $_getSZ(2);
@$pb.TagNumber(3)
set docId($core.String v) { $_setString(2, v); }
@$pb.TagNumber(3)
$core.bool hasDocId() => $_has(2);
@$pb.TagNumber(3)
void clearDocId() => clearField(3);
}
class TextBlockId extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TextBlockId', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value')
..hasRequiredFields = false
;
TextBlockId._() : super();
factory TextBlockId({
$core.String? value,
}) {
final _result = create();
if (value != null) {
_result.value = value;
}
return _result;
}
factory TextBlockId.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory TextBlockId.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
TextBlockId clone() => TextBlockId()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
TextBlockId copyWith(void Function(TextBlockId) updates) => super.copyWith((message) => updates(message as TextBlockId)) as TextBlockId; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static TextBlockId create() => TextBlockId._();
TextBlockId createEmptyInstance() => create();
static $pb.PbList<TextBlockId> createRepeated() => $pb.PbList<TextBlockId>();
@$core.pragma('dart2js:noInline')
static TextBlockId getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<TextBlockId>(create);
static TextBlockId? _defaultInstance;
@$pb.TagNumber(1)
$core.String get value => $_getSZ(0);
@$pb.TagNumber(1)
set value($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasValue() => $_has(0);
@$pb.TagNumber(1)
void clearValue() => clearField(1);
}

View File

@ -0,0 +1,7 @@
///
// Generated code. Do not modify.
// source: text_block_info.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields

View File

@ -0,0 +1,78 @@
///
// Generated code. Do not modify.
// source: text_block_info.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
import 'dart:core' as $core;
import 'dart:convert' as $convert;
import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use createTextBlockParamsDescriptor instead')
const CreateTextBlockParams$json = const {
'1': 'CreateTextBlockParams',
'2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
const {'1': 'revisions', '3': 2, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'revisions'},
],
};
/// Descriptor for `CreateTextBlockParams`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List createTextBlockParamsDescriptor = $convert.base64Decode('ChVDcmVhdGVUZXh0QmxvY2tQYXJhbXMSDgoCaWQYASABKAlSAmlkEi8KCXJldmlzaW9ucxgCIAEoCzIRLlJlcGVhdGVkUmV2aXNpb25SCXJldmlzaW9ucw==');
@$core.Deprecated('Use textBlockInfoDescriptor instead')
const TextBlockInfo$json = const {
'1': 'TextBlockInfo',
'2': const [
const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
const {'1': 'text', '3': 2, '4': 1, '5': 9, '10': 'text'},
const {'1': 'rev_id', '3': 3, '4': 1, '5': 3, '10': 'revId'},
const {'1': 'base_rev_id', '3': 4, '4': 1, '5': 3, '10': 'baseRevId'},
],
};
/// Descriptor for `TextBlockInfo`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List textBlockInfoDescriptor = $convert.base64Decode('Cg1UZXh0QmxvY2tJbmZvEhkKCGJsb2NrX2lkGAEgASgJUgdibG9ja0lkEhIKBHRleHQYAiABKAlSBHRleHQSFQoGcmV2X2lkGAMgASgDUgVyZXZJZBIeCgtiYXNlX3Jldl9pZBgEIAEoA1IJYmFzZVJldklk');
@$core.Deprecated('Use resetTextBlockParamsDescriptor instead')
const ResetTextBlockParams$json = const {
'1': 'ResetTextBlockParams',
'2': const [
const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
const {'1': 'revisions', '3': 2, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'revisions'},
],
};
/// Descriptor for `ResetTextBlockParams`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List resetTextBlockParamsDescriptor = $convert.base64Decode('ChRSZXNldFRleHRCbG9ja1BhcmFtcxIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIvCglyZXZpc2lvbnMYAiABKAsyES5SZXBlYXRlZFJldmlzaW9uUglyZXZpc2lvbnM=');
@$core.Deprecated('Use textBlockDeltaDescriptor instead')
const TextBlockDelta$json = const {
'1': 'TextBlockDelta',
'2': const [
const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
const {'1': 'delta_str', '3': 2, '4': 1, '5': 9, '10': 'deltaStr'},
],
};
/// Descriptor for `TextBlockDelta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List textBlockDeltaDescriptor = $convert.base64Decode('Cg5UZXh0QmxvY2tEZWx0YRIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIbCglkZWx0YV9zdHIYAiABKAlSCGRlbHRhU3Ry');
@$core.Deprecated('Use newDocUserDescriptor instead')
const NewDocUser$json = const {
'1': 'NewDocUser',
'2': const [
const {'1': 'user_id', '3': 1, '4': 1, '5': 9, '10': 'userId'},
const {'1': 'rev_id', '3': 2, '4': 1, '5': 3, '10': 'revId'},
const {'1': 'doc_id', '3': 3, '4': 1, '5': 9, '10': 'docId'},
],
};
/// Descriptor for `NewDocUser`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List newDocUserDescriptor = $convert.base64Decode('CgpOZXdEb2NVc2VyEhcKB3VzZXJfaWQYASABKAlSBnVzZXJJZBIVCgZyZXZfaWQYAiABKANSBXJldklkEhUKBmRvY19pZBgDIAEoCVIFZG9jSWQ=');
@$core.Deprecated('Use textBlockIdDescriptor instead')
const TextBlockId$json = const {
'1': 'TextBlockId',
'2': const [
const {'1': 'value', '3': 1, '4': 1, '5': 9, '10': 'value'},
],
};
/// Descriptor for `TextBlockId`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List textBlockIdDescriptor = $convert.base64Decode('CgtUZXh0QmxvY2tJZBIUCgV2YWx1ZRgBIAEoCVIFdmFsdWU=');

View File

@ -0,0 +1,9 @@
///
// Generated code. Do not modify.
// source: text_block_info.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
export 'text_block_info.pb.dart';

View File

@ -17,7 +17,7 @@ class GridMeta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridMeta', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId')
..pc<Field>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fields', $pb.PbFieldType.PM, subBuilder: Field.create)
..pc<RowMeta>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rows', $pb.PbFieldType.PM, subBuilder: RowMeta.create)
..pc<Block>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blocks', $pb.PbFieldType.PM, subBuilder: Block.create)
..hasRequiredFields = false
;
@ -25,7 +25,7 @@ class GridMeta extends $pb.GeneratedMessage {
factory GridMeta({
$core.String? gridId,
$core.Iterable<Field>? fields,
$core.Iterable<RowMeta>? rows,
$core.Iterable<Block>? blocks,
}) {
final _result = create();
if (gridId != null) {
@ -34,8 +34,8 @@ class GridMeta extends $pb.GeneratedMessage {
if (fields != null) {
_result.fields.addAll(fields);
}
if (rows != null) {
_result.rows.addAll(rows);
if (blocks != null) {
_result.blocks.addAll(blocks);
}
return _result;
}
@ -73,50 +73,55 @@ class GridMeta extends $pb.GeneratedMessage {
$core.List<Field> get fields => $_getList(1);
@$pb.TagNumber(3)
$core.List<RowMeta> get rows => $_getList(2);
$core.List<Block> get blocks => $_getList(2);
}
class GridBlock extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlock', createEmptyInstance: create)
class Block extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Block', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
..pc<RowMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rows', $pb.PbFieldType.PM, subBuilder: RowMeta.create)
..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'startRowIndex', $pb.PbFieldType.O3)
..a<$core.int>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowCount', $pb.PbFieldType.O3)
..hasRequiredFields = false
;
GridBlock._() : super();
factory GridBlock({
Block._() : super();
factory Block({
$core.String? id,
$core.Iterable<RowMeta>? rows,
$core.int? startRowIndex,
$core.int? rowCount,
}) {
final _result = create();
if (id != null) {
_result.id = id;
}
if (rows != null) {
_result.rows.addAll(rows);
if (startRowIndex != null) {
_result.startRowIndex = startRowIndex;
}
if (rowCount != null) {
_result.rowCount = rowCount;
}
return _result;
}
factory GridBlock.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory GridBlock.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
factory Block.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory Block.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
GridBlock clone() => GridBlock()..mergeFromMessage(this);
Block clone() => Block()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
GridBlock copyWith(void Function(GridBlock) updates) => super.copyWith((message) => updates(message as GridBlock)) as GridBlock; // ignore: deprecated_member_use
Block copyWith(void Function(Block) updates) => super.copyWith((message) => updates(message as Block)) as Block; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GridBlock create() => GridBlock._();
GridBlock createEmptyInstance() => create();
static $pb.PbList<GridBlock> createRepeated() => $pb.PbList<GridBlock>();
static Block create() => Block._();
Block createEmptyInstance() => create();
static $pb.PbList<Block> createRepeated() => $pb.PbList<Block>();
@$core.pragma('dart2js:noInline')
static GridBlock getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GridBlock>(create);
static GridBlock? _defaultInstance;
static Block getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Block>(create);
static Block? _defaultInstance;
@$pb.TagNumber(1)
$core.String get id => $_getSZ(0);
@ -127,6 +132,76 @@ class GridBlock extends $pb.GeneratedMessage {
@$pb.TagNumber(1)
void clearId() => clearField(1);
@$pb.TagNumber(2)
$core.int get startRowIndex => $_getIZ(1);
@$pb.TagNumber(2)
set startRowIndex($core.int v) { $_setSignedInt32(1, v); }
@$pb.TagNumber(2)
$core.bool hasStartRowIndex() => $_has(1);
@$pb.TagNumber(2)
void clearStartRowIndex() => clearField(2);
@$pb.TagNumber(3)
$core.int get rowCount => $_getIZ(2);
@$pb.TagNumber(3)
set rowCount($core.int v) { $_setSignedInt32(2, v); }
@$pb.TagNumber(3)
$core.bool hasRowCount() => $_has(2);
@$pb.TagNumber(3)
void clearRowCount() => clearField(3);
}
class BlockMeta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockMeta', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
..pc<RowMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rows', $pb.PbFieldType.PM, subBuilder: RowMeta.create)
..hasRequiredFields = false
;
BlockMeta._() : super();
factory BlockMeta({
$core.String? blockId,
$core.Iterable<RowMeta>? rows,
}) {
final _result = create();
if (blockId != null) {
_result.blockId = blockId;
}
if (rows != null) {
_result.rows.addAll(rows);
}
return _result;
}
factory BlockMeta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory BlockMeta.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
BlockMeta clone() => BlockMeta()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
BlockMeta copyWith(void Function(BlockMeta) updates) => super.copyWith((message) => updates(message as BlockMeta)) as BlockMeta; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static BlockMeta create() => BlockMeta._();
BlockMeta createEmptyInstance() => create();
static $pb.PbList<BlockMeta> createRepeated() => $pb.PbList<BlockMeta>();
@$core.pragma('dart2js:noInline')
static BlockMeta getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BlockMeta>(create);
static BlockMeta? _defaultInstance;
@$pb.TagNumber(1)
$core.String get blockId => $_getSZ(0);
@$pb.TagNumber(1)
set blockId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasBlockId() => $_has(0);
@$pb.TagNumber(1)
void clearBlockId() => clearField(1);
@$pb.TagNumber(2)
$core.List<RowMeta> get rows => $_getList(1);
}

View File

@ -29,23 +29,35 @@ const GridMeta$json = const {
'2': const [
const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'},
const {'1': 'fields', '3': 2, '4': 3, '5': 11, '6': '.Field', '10': 'fields'},
const {'1': 'rows', '3': 3, '4': 3, '5': 11, '6': '.RowMeta', '10': 'rows'},
const {'1': 'blocks', '3': 3, '4': 3, '5': 11, '6': '.Block', '10': 'blocks'},
],
};
/// Descriptor for `GridMeta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridMetaDescriptor = $convert.base64Decode('CghHcmlkTWV0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSHgoGZmllbGRzGAIgAygLMgYuRmllbGRSBmZpZWxkcxIcCgRyb3dzGAMgAygLMgguUm93TWV0YVIEcm93cw==');
@$core.Deprecated('Use gridBlockDescriptor instead')
const GridBlock$json = const {
'1': 'GridBlock',
final $typed_data.Uint8List gridMetaDescriptor = $convert.base64Decode('CghHcmlkTWV0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSHgoGZmllbGRzGAIgAygLMgYuRmllbGRSBmZpZWxkcxIeCgZibG9ja3MYAyADKAsyBi5CbG9ja1IGYmxvY2tz');
@$core.Deprecated('Use blockDescriptor instead')
const Block$json = const {
'1': 'Block',
'2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
const {'1': 'start_row_index', '3': 2, '4': 1, '5': 5, '10': 'startRowIndex'},
const {'1': 'row_count', '3': 3, '4': 1, '5': 5, '10': 'rowCount'},
],
};
/// Descriptor for `Block`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List blockDescriptor = $convert.base64Decode('CgVCbG9jaxIOCgJpZBgBIAEoCVICaWQSJgoPc3RhcnRfcm93X2luZGV4GAIgASgFUg1zdGFydFJvd0luZGV4EhsKCXJvd19jb3VudBgDIAEoBVIIcm93Q291bnQ=');
@$core.Deprecated('Use blockMetaDescriptor instead')
const BlockMeta$json = const {
'1': 'BlockMeta',
'2': const [
const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
const {'1': 'rows', '3': 2, '4': 3, '5': 11, '6': '.RowMeta', '10': 'rows'},
],
};
/// Descriptor for `GridBlock`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridBlockDescriptor = $convert.base64Decode('CglHcmlkQmxvY2sSDgoCaWQYASABKAlSAmlkEhwKBHJvd3MYAiADKAsyCC5Sb3dNZXRhUgRyb3dz');
/// Descriptor for `BlockMeta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List blockMetaDescriptor = $convert.base64Decode('CglCbG9ja01ldGESGQoIYmxvY2tfaWQYASABKAlSB2Jsb2NrSWQSHAoEcm93cxgCIAMoCzIILlJvd01ldGFSBHJvd3M=');
@$core.Deprecated('Use fieldDescriptor instead')
const Field$json = const {
'1': 'Field',

View File

@ -3,12 +3,12 @@ use crate::web_socket::{make_block_ws_manager, EditorCommandSender};
use crate::{
errors::FlowyError,
queue::{EditBlockQueue, EditorCommand},
BlockUser,
TextBlockUser,
};
use bytes::Bytes;
use flowy_collaboration::entities::ws_data::ServerRevisionWSData;
use flowy_collaboration::{
entities::{document_info::BlockInfo, revision::Revision},
entities::{revision::Revision, text_block_info::TextBlockInfo},
errors::CollaborateResult,
util::make_delta_from_revisions,
};
@ -24,7 +24,7 @@ use lib_ws::WSConnectState;
use std::sync::Arc;
use tokio::sync::{mpsc, oneshot};
pub struct ClientBlockEditor {
pub struct ClientTextBlockEditor {
pub doc_id: String,
#[allow(dead_code)]
rev_manager: Arc<RevisionManager>,
@ -32,10 +32,10 @@ pub struct ClientBlockEditor {
edit_cmd_tx: EditorCommandSender,
}
impl ClientBlockEditor {
impl ClientTextBlockEditor {
pub(crate) async fn new(
doc_id: &str,
user: Arc<dyn BlockUser>,
user: Arc<dyn TextBlockUser>,
mut rev_manager: RevisionManager,
rev_web_socket: Arc<dyn RevisionWebSocket>,
cloud_service: Arc<dyn RevisionCloudService>,
@ -174,7 +174,7 @@ impl ClientBlockEditor {
}
}
impl std::ops::Drop for ClientBlockEditor {
impl std::ops::Drop for ClientTextBlockEditor {
fn drop(&mut self) {
tracing::trace!("{} ClientBlockEditor was dropped", self.doc_id)
}
@ -182,7 +182,7 @@ impl std::ops::Drop for ClientBlockEditor {
// The edit queue will exit after the EditorCommandSender was dropped.
fn spawn_edit_queue(
user: Arc<dyn BlockUser>,
user: Arc<dyn TextBlockUser>,
rev_manager: Arc<RevisionManager>,
delta: RichTextDelta,
) -> EditorCommandSender {
@ -193,7 +193,7 @@ fn spawn_edit_queue(
}
#[cfg(feature = "flowy_unit_test")]
impl ClientBlockEditor {
impl ClientTextBlockEditor {
pub async fn doc_json(&self) -> FlowyResult<String> {
let (ret, rx) = oneshot::channel::<CollaborateResult<String>>();
let msg = EditorCommand::ReadDeltaStr { ret };
@ -217,14 +217,14 @@ impl ClientBlockEditor {
struct BlockInfoBuilder();
impl RevisionObjectBuilder for BlockInfoBuilder {
type Output = BlockInfo;
type Output = TextBlockInfo;
fn build_object(object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output> {
let (base_rev_id, rev_id) = revisions.last().unwrap().pair_rev_id();
let mut delta = make_delta_from_revisions(revisions)?;
correct_delta(&mut delta);
Result::<BlockInfo, FlowyError>::Ok(BlockInfo {
Result::<TextBlockInfo, FlowyError>::Ok(TextBlockInfo {
block_id: object_id.to_owned(),
text: delta.to_delta_str(),
rev_id,

View File

@ -1,28 +1,28 @@
use crate::entities::{ExportData, ExportParams, ExportPayload};
use crate::BlockManager;
use flowy_collaboration::entities::document_info::{BlockDelta, BlockId};
use crate::TextBlockManager;
use flowy_collaboration::entities::text_block_info::{TextBlockDelta, TextBlockId};
use flowy_error::FlowyError;
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
use std::convert::TryInto;
use std::sync::Arc;
pub(crate) async fn get_block_data_handler(
data: Data<BlockId>,
manager: AppData<Arc<BlockManager>>,
) -> DataResult<BlockDelta, FlowyError> {
let block_id: BlockId = data.into_inner();
data: Data<TextBlockId>,
manager: AppData<Arc<TextBlockManager>>,
) -> DataResult<TextBlockDelta, FlowyError> {
let block_id: TextBlockId = data.into_inner();
let editor = manager.open_block(&block_id).await?;
let delta_str = editor.delta_str().await?;
data_result(BlockDelta {
data_result(TextBlockDelta {
block_id: block_id.into(),
delta_str,
})
}
pub(crate) async fn apply_delta_handler(
data: Data<BlockDelta>,
manager: AppData<Arc<BlockManager>>,
) -> DataResult<BlockDelta, FlowyError> {
data: Data<TextBlockDelta>,
manager: AppData<Arc<TextBlockManager>>,
) -> DataResult<TextBlockDelta, FlowyError> {
let block_delta = manager.receive_local_delta(data.into_inner()).await?;
data_result(block_delta)
}
@ -30,7 +30,7 @@ pub(crate) async fn apply_delta_handler(
#[tracing::instrument(skip(data, manager), err)]
pub(crate) async fn export_handler(
data: Data<ExportPayload>,
manager: AppData<Arc<BlockManager>>,
manager: AppData<Arc<TextBlockManager>>,
) -> DataResult<ExportData, FlowyError> {
let params: ExportParams = data.into_inner().try_into()?;
let editor = manager.open_block(&params.view_id).await?;

View File

@ -1,11 +1,11 @@
use crate::event_handler::*;
use crate::BlockManager;
use crate::TextBlockManager;
use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
use lib_dispatch::prelude::Module;
use std::sync::Arc;
use strum_macros::Display;
pub fn create(block_manager: Arc<BlockManager>) -> Module {
pub fn create(block_manager: Arc<TextBlockManager>) -> Module {
let mut module = Module::new().name(env!("CARGO_PKG_NAME")).data(block_manager);
module = module

View File

@ -1,4 +1,4 @@
pub mod block_editor;
pub mod editor;
mod entities;
mod event_handler;
pub mod event_map;
@ -15,13 +15,15 @@ pub mod errors {
pub const DOCUMENT_SYNC_INTERVAL_IN_MILLIS: u64 = 1000;
use crate::errors::FlowyError;
use flowy_collaboration::entities::document_info::{BlockId, BlockInfo, CreateBlockParams, ResetBlockParams};
use flowy_collaboration::entities::text_block_info::{
CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo,
};
use lib_infra::future::FutureResult;
pub trait BlockCloudService: Send + Sync {
fn create_block(&self, token: &str, params: CreateBlockParams) -> FutureResult<(), FlowyError>;
fn create_block(&self, token: &str, params: CreateTextBlockParams) -> FutureResult<(), FlowyError>;
fn read_block(&self, token: &str, params: BlockId) -> FutureResult<Option<BlockInfo>, FlowyError>;
fn read_block(&self, token: &str, params: TextBlockId) -> FutureResult<Option<TextBlockInfo>, FlowyError>;
fn update_block(&self, token: &str, params: ResetBlockParams) -> FutureResult<(), FlowyError>;
fn update_block(&self, token: &str, params: ResetTextBlockParams) -> FutureResult<(), FlowyError>;
}

View File

@ -1,9 +1,9 @@
use crate::{block_editor::ClientBlockEditor, errors::FlowyError, BlockCloudService};
use crate::{editor::ClientTextBlockEditor, errors::FlowyError, BlockCloudService};
use bytes::Bytes;
use dashmap::DashMap;
use flowy_collaboration::entities::{
document_info::{BlockDelta, BlockId},
revision::{md5, RepeatedRevision, Revision},
text_block_info::{TextBlockDelta, TextBlockId},
ws_data::ServerRevisionWSData,
};
use flowy_database::ConnectionPool;
@ -12,43 +12,42 @@ use flowy_sync::{RevisionCloudService, RevisionManager, RevisionPersistence, Rev
use lib_infra::future::FutureResult;
use std::{convert::TryInto, sync::Arc};
pub trait BlockUser: Send + Sync {
pub trait TextBlockUser: Send + Sync {
fn user_dir(&self) -> Result<String, FlowyError>;
fn user_id(&self) -> Result<String, FlowyError>;
fn token(&self) -> Result<String, FlowyError>;
fn db_pool(&self) -> Result<Arc<ConnectionPool>, FlowyError>;
}
pub struct BlockManager {
pub struct TextBlockManager {
cloud_service: Arc<dyn BlockCloudService>,
rev_web_socket: Arc<dyn RevisionWebSocket>,
block_editors: Arc<BlockEditors>,
block_user: Arc<dyn BlockUser>,
editor_map: Arc<TextBlockEditorMap>,
user: Arc<dyn TextBlockUser>,
}
impl BlockManager {
impl TextBlockManager {
pub fn new(
cloud_service: Arc<dyn BlockCloudService>,
block_user: Arc<dyn BlockUser>,
text_block_user: Arc<dyn TextBlockUser>,
rev_web_socket: Arc<dyn RevisionWebSocket>,
) -> Self {
let block_editors = Arc::new(BlockEditors::new());
Self {
cloud_service,
rev_web_socket,
block_editors,
block_user,
editor_map: Arc::new(TextBlockEditorMap::new()),
user: text_block_user,
}
}
pub fn init(&self) -> FlowyResult<()> {
listen_ws_state_changed(self.rev_web_socket.clone(), self.block_editors.clone());
listen_ws_state_changed(self.rev_web_socket.clone(), self.editor_map.clone());
Ok(())
}
#[tracing::instrument(level = "debug", skip(self, block_id), fields(block_id), err)]
pub async fn open_block<T: AsRef<str>>(&self, block_id: T) -> Result<Arc<ClientBlockEditor>, FlowyError> {
pub async fn open_block<T: AsRef<str>>(&self, block_id: T) -> Result<Arc<ClientTextBlockEditor>, FlowyError> {
let block_id = block_id.as_ref();
tracing::Span::current().record("block_id", &block_id);
self.get_block_editor(block_id).await
@ -58,7 +57,7 @@ impl BlockManager {
pub fn close_block<T: AsRef<str>>(&self, block_id: T) -> Result<(), FlowyError> {
let block_id = block_id.as_ref();
tracing::Span::current().record("block_id", &block_id);
self.block_editors.remove(block_id);
self.editor_map.remove(block_id);
Ok(())
}
@ -66,16 +65,16 @@ impl BlockManager {
pub fn delete_block<T: AsRef<str>>(&self, doc_id: T) -> Result<(), FlowyError> {
let doc_id = doc_id.as_ref();
tracing::Span::current().record("doc_id", &doc_id);
self.block_editors.remove(doc_id);
self.editor_map.remove(doc_id);
Ok(())
}
#[tracing::instrument(level = "debug", skip(self, delta), fields(doc_id = %delta.block_id), err)]
pub async fn receive_local_delta(&self, delta: BlockDelta) -> Result<BlockDelta, FlowyError> {
pub async fn receive_local_delta(&self, delta: TextBlockDelta) -> Result<TextBlockDelta, FlowyError> {
let editor = self.get_block_editor(&delta.block_id).await?;
let _ = editor.compose_local_delta(Bytes::from(delta.delta_str)).await?;
let document_json = editor.delta_str().await?;
Ok(BlockDelta {
Ok(TextBlockDelta {
block_id: delta.block_id.clone(),
delta_str: document_json,
})
@ -83,7 +82,7 @@ impl BlockManager {
pub async fn create_block<T: AsRef<str>>(&self, doc_id: T, revisions: RepeatedRevision) -> FlowyResult<()> {
let doc_id = doc_id.as_ref().to_owned();
let db_pool = self.block_user.db_pool()?;
let db_pool = self.user.db_pool()?;
// Maybe we could save the block to disk without creating the RevisionManager
let rev_manager = self.make_block_rev_manager(&doc_id, db_pool)?;
let _ = rev_manager.reset_object(revisions).await?;
@ -93,9 +92,9 @@ impl BlockManager {
pub async fn receive_ws_data(&self, data: Bytes) {
let result: Result<ServerRevisionWSData, protobuf::ProtobufError> = data.try_into();
match result {
Ok(data) => match self.block_editors.get(&data.object_id) {
Ok(data) => match self.editor_map.get(&data.object_id) {
None => tracing::error!("Can't find any source handler for {:?}-{:?}", data.object_id, data.ty),
Some(block_editor) => match block_editor.receive_ws_data(data).await {
Some(editor) => match editor.receive_ws_data(data).await {
Ok(_) => {}
Err(e) => tracing::error!("{}", e),
},
@ -107,11 +106,11 @@ impl BlockManager {
}
}
impl BlockManager {
async fn get_block_editor(&self, block_id: &str) -> FlowyResult<Arc<ClientBlockEditor>> {
match self.block_editors.get(block_id) {
impl TextBlockManager {
async fn get_block_editor(&self, block_id: &str) -> FlowyResult<Arc<ClientTextBlockEditor>> {
match self.editor_map.get(block_id) {
None => {
let db_pool = self.block_user.db_pool()?;
let db_pool = self.user.db_pool()?;
self.make_block_editor(block_id, db_pool).await
}
Some(editor) => Ok(editor),
@ -122,36 +121,36 @@ impl BlockManager {
&self,
block_id: &str,
pool: Arc<ConnectionPool>,
) -> Result<Arc<ClientBlockEditor>, FlowyError> {
let user = self.block_user.clone();
let token = self.block_user.token()?;
) -> Result<Arc<ClientTextBlockEditor>, FlowyError> {
let user = self.user.clone();
let token = self.user.token()?;
let rev_manager = self.make_block_rev_manager(block_id, pool.clone())?;
let cloud_service = Arc::new(BlockRevisionCloudService {
let cloud_service = Arc::new(TextBlockRevisionCloudService {
token,
server: self.cloud_service.clone(),
});
let doc_editor =
ClientBlockEditor::new(block_id, user, rev_manager, self.rev_web_socket.clone(), cloud_service).await?;
self.block_editors.insert(block_id, &doc_editor);
ClientTextBlockEditor::new(block_id, user, rev_manager, self.rev_web_socket.clone(), cloud_service).await?;
self.editor_map.insert(block_id, &doc_editor);
Ok(doc_editor)
}
fn make_block_rev_manager(&self, doc_id: &str, pool: Arc<ConnectionPool>) -> Result<RevisionManager, FlowyError> {
let user_id = self.block_user.user_id()?;
let user_id = self.user.user_id()?;
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, doc_id, pool));
Ok(RevisionManager::new(&user_id, doc_id, rev_persistence))
}
}
struct BlockRevisionCloudService {
struct TextBlockRevisionCloudService {
token: String,
server: Arc<dyn BlockCloudService>,
}
impl RevisionCloudService for BlockRevisionCloudService {
impl RevisionCloudService for TextBlockRevisionCloudService {
#[tracing::instrument(level = "trace", skip(self))]
fn fetch_object(&self, user_id: &str, object_id: &str) -> FutureResult<Vec<Revision>, FlowyError> {
let params: BlockId = object_id.to_string().into();
let params: TextBlockId = object_id.to_string().into();
let server = self.server.clone();
let token = self.token.clone();
let user_id = user_id.to_string();
@ -177,32 +176,24 @@ impl RevisionCloudService for BlockRevisionCloudService {
}
}
pub struct BlockEditors {
inner: DashMap<String, Arc<ClientBlockEditor>>,
pub struct TextBlockEditorMap {
inner: DashMap<String, Arc<ClientTextBlockEditor>>,
}
impl BlockEditors {
impl TextBlockEditorMap {
fn new() -> Self {
Self { inner: DashMap::new() }
}
pub(crate) fn insert(&self, block_id: &str, doc: &Arc<ClientBlockEditor>) {
pub(crate) fn insert(&self, block_id: &str, doc: &Arc<ClientTextBlockEditor>) {
if self.inner.contains_key(block_id) {
log::warn!("Doc:{} already exists in cache", block_id);
}
self.inner.insert(block_id.to_string(), doc.clone());
}
pub(crate) fn contains(&self, block_id: &str) -> bool {
self.inner.get(block_id).is_some()
}
pub(crate) fn get(&self, block_id: &str) -> Option<Arc<ClientBlockEditor>> {
if !self.contains(block_id) {
return None;
}
let opened_doc = self.inner.get(block_id).unwrap();
Some(opened_doc.clone())
pub(crate) fn get(&self, block_id: &str) -> Option<Arc<ClientTextBlockEditor>> {
Some(self.inner.get(block_id)?.clone())
}
pub(crate) fn remove(&self, block_id: &str) {
@ -214,7 +205,7 @@ impl BlockEditors {
}
#[tracing::instrument(level = "trace", skip(web_socket, handlers))]
fn listen_ws_state_changed(web_socket: Arc<dyn RevisionWebSocket>, handlers: Arc<BlockEditors>) {
fn listen_ws_state_changed(web_socket: Arc<dyn RevisionWebSocket>, handlers: Arc<TextBlockEditorMap>) {
tokio::spawn(async move {
let mut notify = web_socket.subscribe_state_changed().await;
while let Ok(state) = notify.recv().await {

View File

@ -1,5 +1,5 @@
use crate::web_socket::EditorCommandReceiver;
use crate::BlockUser;
use crate::TextBlockUser;
use async_stream::stream;
use flowy_collaboration::util::make_delta_from_revisions;
use flowy_collaboration::{
@ -21,14 +21,14 @@ use tokio::sync::{oneshot, RwLock};
// serial.
pub(crate) struct EditBlockQueue {
document: Arc<RwLock<ClientDocument>>,
user: Arc<dyn BlockUser>,
user: Arc<dyn TextBlockUser>,
rev_manager: Arc<RevisionManager>,
receiver: Option<EditorCommandReceiver>,
}
impl EditBlockQueue {
pub(crate) fn new(
user: Arc<dyn BlockUser>,
user: Arc<dyn TextBlockUser>,
rev_manager: Arc<RevisionManager>,
delta: RichTextDelta,
receiver: EditorCommandReceiver,

View File

@ -31,11 +31,11 @@ pub(crate) async fn make_block_ws_manager(
rev_web_socket: Arc<dyn RevisionWebSocket>,
) -> Arc<RevisionWebSocketManager> {
let ws_data_provider = Arc::new(WSDataProvider::new(&doc_id, Arc::new(rev_manager.clone())));
let resolver = Arc::new(BlockConflictResolver { edit_cmd_tx });
let resolver = Arc::new(TextBlockConflictResolver { edit_cmd_tx });
let conflict_controller =
RichTextConflictController::new(&user_id, resolver, Arc::new(ws_data_provider.clone()), rev_manager);
let ws_data_stream = Arc::new(BlockRevisionWSDataStream::new(conflict_controller));
let ws_data_sink = Arc::new(BlockWSDataSink(ws_data_provider));
let ws_data_stream = Arc::new(TextBlockRevisionWSDataStream::new(conflict_controller));
let ws_data_sink = Arc::new(TextBlockWSDataSink(ws_data_provider));
let ping_duration = Duration::from_millis(DOCUMENT_SYNC_INTERVAL_IN_MILLIS);
let ws_manager = Arc::new(RevisionWebSocketManager::new(
"Block",
@ -62,11 +62,11 @@ fn listen_document_ws_state(_user_id: &str, _doc_id: &str, mut subscriber: broad
});
}
pub(crate) struct BlockRevisionWSDataStream {
pub(crate) struct TextBlockRevisionWSDataStream {
conflict_controller: Arc<RichTextConflictController>,
}
impl BlockRevisionWSDataStream {
impl TextBlockRevisionWSDataStream {
pub fn new(conflict_controller: RichTextConflictController) -> Self {
Self {
conflict_controller: Arc::new(conflict_controller),
@ -74,7 +74,7 @@ impl BlockRevisionWSDataStream {
}
}
impl RevisionWSDataStream for BlockRevisionWSDataStream {
impl RevisionWSDataStream for TextBlockRevisionWSDataStream {
fn receive_push_revision(&self, bytes: Bytes) -> BoxResultFuture<(), FlowyError> {
let resolver = self.conflict_controller.clone();
Box::pin(async move { resolver.receive_bytes(bytes).await })
@ -96,19 +96,19 @@ impl RevisionWSDataStream for BlockRevisionWSDataStream {
}
}
pub(crate) struct BlockWSDataSink(pub(crate) Arc<WSDataProvider>);
impl RevisionWebSocketSink for BlockWSDataSink {
pub(crate) struct TextBlockWSDataSink(pub(crate) Arc<WSDataProvider>);
impl RevisionWebSocketSink for TextBlockWSDataSink {
fn next(&self) -> FutureResult<Option<ClientRevisionWSData>, FlowyError> {
let sink_provider = self.0.clone();
FutureResult::new(async move { sink_provider.next().await })
}
}
struct BlockConflictResolver {
struct TextBlockConflictResolver {
edit_cmd_tx: EditorCommandSender,
}
impl ConflictResolver<RichTextAttributes> for BlockConflictResolver {
impl ConflictResolver<RichTextAttributes> for TextBlockConflictResolver {
fn compose_delta(&self, delta: RichTextDelta) -> BoxResultFuture<DeltaMD5, FlowyError> {
let tx = self.edit_cmd_tx.clone();
Box::pin(async move {

View File

@ -1,4 +1,4 @@
use flowy_block::block_editor::ClientBlockEditor;
use flowy_block::editor::ClientTextBlockEditor;
use flowy_block::DOCUMENT_SYNC_INTERVAL_IN_MILLIS;
use flowy_collaboration::entities::revision::RevisionState;
use flowy_test::{helper::ViewTest, FlowySDKTest};
@ -19,7 +19,7 @@ pub enum EditorScript {
pub struct EditorTest {
pub sdk: FlowySDKTest,
pub editor: Arc<ClientBlockEditor>,
pub editor: Arc<ClientTextBlockEditor>,
}
impl EditorTest {
@ -27,7 +27,7 @@ impl EditorTest {
let sdk = FlowySDKTest::default();
let _ = sdk.init_user().await;
let test = ViewTest::new(&sdk).await;
let editor = sdk.block_manager.open_block(&test.view.id).await.unwrap();
let editor = sdk.text_block_manager.open_block(&test.view.id).await.unwrap();
Self { sdk, editor }
}

View File

@ -1,2 +1,3 @@
-- This file should undo anything in `up.sql`
DROP TABLE kv_table;
DROP TABLE kv_table;
DROP TABLE grid_rev_table;

View File

@ -2,4 +2,13 @@
CREATE TABLE kv_table (
key TEXT NOT NULL PRIMARY KEY,
value BLOB NOT NULL DEFAULT (x'')
);
CREATE TABLE grid_rev_table (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
object_id TEXT NOT NULL DEFAULT '',
base_rev_id BIGINT NOT NULL DEFAULT 0,
rev_id BIGINT NOT NULL DEFAULT 0,
data BLOB NOT NULL DEFAULT (x''),
state INTEGER NOT NULL DEFAULT 0
);

View File

@ -14,8 +14,8 @@ use crate::{
};
use bytes::Bytes;
use flowy_collaboration::entities::{
document_info::BlockId,
revision::{RepeatedRevision, Revision},
text_block_info::TextBlockId,
};
use flowy_database::kv::KV;
use flowy_folder_data_model::entities::view::ViewDataType;
@ -147,7 +147,7 @@ impl ViewController {
}
#[tracing::instrument(level = "debug", skip(self,params), fields(doc_id = %params.value), err)]
pub(crate) async fn delete_view(&self, params: BlockId) -> Result<(), FlowyError> {
pub(crate) async fn delete_view(&self, params: TextBlockId) -> Result<(), FlowyError> {
if let Some(view_id) = KV::get_str(LATEST_VIEW_ID) {
if view_id == params.value {
let _ = KV::remove(LATEST_VIEW_ID);

View File

@ -1,4 +1,4 @@
use flowy_collaboration::entities::document_info::BlockInfo;
use flowy_collaboration::entities::text_block_info::TextBlockInfo;
use flowy_folder::event_map::FolderEvent::*;
use flowy_folder_data_model::entities::view::{RepeatedViewId, ViewId};
use flowy_folder_data_model::entities::workspace::WorkspaceId;
@ -161,14 +161,14 @@ pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec<String>) {
.await;
}
pub async fn open_document(sdk: &FlowySDKTest, view_id: &str) -> BlockInfo {
pub async fn open_document(sdk: &FlowySDKTest, view_id: &str) -> TextBlockInfo {
let view_id: ViewId = view_id.into();
FolderEventBuilder::new(sdk.clone())
.event(SetLatestView)
.payload(view_id)
.async_send()
.await
.parse::<BlockInfo>()
.parse::<TextBlockInfo>()
}
pub async fn read_trash(sdk: &FlowySDKTest) -> RepeatedTrash {

View File

@ -1,5 +1,5 @@
use crate::helper::*;
use flowy_collaboration::entities::{document_info::BlockInfo, revision::RevisionState};
use flowy_collaboration::entities::{revision::RevisionState, text_block_info::TextBlockInfo};
use flowy_folder::{errors::ErrorCode, services::folder_editor::ClientFolderEditor};
use flowy_folder_data_model::entities::{
app::{App, RepeatedApp},
@ -58,7 +58,7 @@ pub struct FolderTest {
pub app: App,
pub view: View,
pub trash: Vec<Trash>,
pub document_info: Option<BlockInfo>,
pub document_info: Option<TextBlockInfo>,
// pub folder_editor:
}

View File

@ -44,7 +44,7 @@ impl GridBuilder {
let grid_meta = GridMeta {
grid_id: self.grid_id,
fields: self.fields,
rows: self.rows,
blocks: vec![],
};
// let _ = check_rows(&self.fields, &self.rows)?;

View File

@ -3,7 +3,9 @@ use crate::{
request::{HttpRequestBuilder, ResponseMiddleware},
};
use flowy_block::BlockCloudService;
use flowy_collaboration::entities::document_info::{BlockId, BlockInfo, CreateBlockParams, ResetBlockParams};
use flowy_collaboration::entities::text_block_info::{
CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo,
};
use flowy_error::FlowyError;
use http_flowy::response::FlowyResponse;
use lazy_static::lazy_static;
@ -21,26 +23,26 @@ impl BlockHttpCloudService {
}
impl BlockCloudService for BlockHttpCloudService {
fn create_block(&self, token: &str, params: CreateBlockParams) -> FutureResult<(), FlowyError> {
fn create_block(&self, token: &str, params: CreateTextBlockParams) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.doc_url();
FutureResult::new(async move { create_document_request(&token, params, &url).await })
}
fn read_block(&self, token: &str, params: BlockId) -> FutureResult<Option<BlockInfo>, FlowyError> {
fn read_block(&self, token: &str, params: TextBlockId) -> FutureResult<Option<TextBlockInfo>, FlowyError> {
let token = token.to_owned();
let url = self.config.doc_url();
FutureResult::new(async move { read_document_request(&token, params, &url).await })
}
fn update_block(&self, token: &str, params: ResetBlockParams) -> FutureResult<(), FlowyError> {
fn update_block(&self, token: &str, params: ResetTextBlockParams) -> FutureResult<(), FlowyError> {
let token = token.to_owned();
let url = self.config.doc_url();
FutureResult::new(async move { reset_doc_request(&token, params, &url).await })
}
}
pub async fn create_document_request(token: &str, params: CreateBlockParams, url: &str) -> Result<(), FlowyError> {
pub async fn create_document_request(token: &str, params: CreateTextBlockParams, url: &str) -> Result<(), FlowyError> {
let _ = request_builder()
.post(&url.to_owned())
.header(HEADER_TOKEN, token)
@ -50,7 +52,11 @@ pub async fn create_document_request(token: &str, params: CreateBlockParams, url
Ok(())
}
pub async fn read_document_request(token: &str, params: BlockId, url: &str) -> Result<Option<BlockInfo>, FlowyError> {
pub async fn read_document_request(
token: &str,
params: TextBlockId,
url: &str,
) -> Result<Option<TextBlockInfo>, FlowyError> {
let doc = request_builder()
.get(&url.to_owned())
.header(HEADER_TOKEN, token)
@ -61,7 +67,7 @@ pub async fn read_document_request(token: &str, params: BlockId, url: &str) -> R
Ok(doc)
}
pub async fn reset_doc_request(token: &str, params: ResetBlockParams, url: &str) -> Result<(), FlowyError> {
pub async fn reset_doc_request(token: &str, params: ResetTextBlockParams, url: &str) -> Result<(), FlowyError> {
let _ = request_builder()
.patch(&url.to_owned())
.header(HEADER_TOKEN, token)

View File

@ -1,5 +1,5 @@
use flowy_collaboration::{
entities::{document_info::BlockInfo, folder_info::FolderInfo},
entities::{folder_info::FolderInfo, text_block_info::TextBlockInfo},
errors::CollaborateError,
protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB},
server_document::*,
@ -111,7 +111,7 @@ impl FolderCloudPersistence for LocalDocumentCloudPersistence {
}
impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
fn read_document(&self, doc_id: &str) -> BoxResultFuture<BlockInfo, CollaborateError> {
fn read_document(&self, doc_id: &str) -> BoxResultFuture<TextBlockInfo, CollaborateError> {
let storage = self.storage.clone();
let doc_id = doc_id.to_owned();
Box::pin(async move {
@ -127,7 +127,7 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
&self,
doc_id: &str,
repeated_revision: RepeatedRevisionPB,
) -> BoxResultFuture<Option<BlockInfo>, CollaborateError> {
) -> BoxResultFuture<Option<TextBlockInfo>, CollaborateError> {
let doc_id = doc_id.to_owned();
let storage = self.storage.clone();
Box::pin(async move {

View File

@ -4,7 +4,7 @@ use bytes::Bytes;
use flowy_collaboration::{
client_document::default::initial_quill_delta_string,
entities::{
document_info::{BlockId, BlockInfo, CreateBlockParams, ResetBlockParams},
text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo},
ws_data::{ClientRevisionWSData, ClientRevisionWSDataType},
},
errors::CollaborateError,
@ -413,12 +413,12 @@ impl UserCloudService for LocalServer {
}
impl BlockCloudService for LocalServer {
fn create_block(&self, _token: &str, _params: CreateBlockParams) -> FutureResult<(), FlowyError> {
fn create_block(&self, _token: &str, _params: CreateTextBlockParams) -> FutureResult<(), FlowyError> {
FutureResult::new(async { Ok(()) })
}
fn read_block(&self, _token: &str, params: BlockId) -> FutureResult<Option<BlockInfo>, FlowyError> {
let doc = BlockInfo {
fn read_block(&self, _token: &str, params: TextBlockId) -> FutureResult<Option<TextBlockInfo>, FlowyError> {
let doc = TextBlockInfo {
block_id: params.value,
text: initial_quill_delta_string(),
rev_id: 0,
@ -427,7 +427,7 @@ impl BlockCloudService for LocalServer {
FutureResult::new(async { Ok(Some(doc)) })
}
fn update_block(&self, _token: &str, _params: ResetBlockParams) -> FutureResult<(), FlowyError> {
fn update_block(&self, _token: &str, _params: ResetTextBlockParams) -> FutureResult<(), FlowyError> {
FutureResult::new(async { Ok(()) })
}
}

View File

@ -1,5 +1,5 @@
use bytes::Bytes;
use flowy_block::BlockManager;
use flowy_block::TextBlockManager;
use flowy_collaboration::client_document::default::initial_quill_delta_string;
use flowy_collaboration::entities::revision::RepeatedRevision;
use flowy_collaboration::entities::ws_data::ClientRevisionWSData;
@ -32,7 +32,7 @@ impl FolderDepsResolver {
user_session: Arc<UserSession>,
server_config: &ClientServerConfiguration,
ws_conn: &Arc<FlowyWebSocketConnect>,
block_manager: &Arc<BlockManager>,
text_block_manager: &Arc<TextBlockManager>,
grid_manager: &Arc<GridManager>,
) -> Arc<FolderManager> {
let user: Arc<dyn WorkspaceUser> = Arc::new(WorkspaceUserImpl(user_session.clone()));
@ -43,7 +43,7 @@ impl FolderDepsResolver {
Some(local_server) => local_server,
};
let view_data_processor = make_view_data_processor(block_manager.clone(), grid_manager.clone());
let view_data_processor = make_view_data_processor(text_block_manager.clone(), grid_manager.clone());
let folder_manager =
Arc::new(FolderManager::new(user.clone(), cloud_service, database, view_data_processor, web_socket).await);
@ -60,10 +60,13 @@ impl FolderDepsResolver {
}
}
fn make_view_data_processor(block_manager: Arc<BlockManager>, grid_manager: Arc<GridManager>) -> ViewDataProcessorMap {
fn make_view_data_processor(
text_block_manager: Arc<TextBlockManager>,
grid_manager: Arc<GridManager>,
) -> ViewDataProcessorMap {
let mut map: HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>> = HashMap::new();
let block_data_impl = BlockManagerViewDataImpl(block_manager);
let block_data_impl = BlockManagerViewDataImpl(text_block_manager);
map.insert(block_data_impl.data_type(), Arc::new(block_data_impl));
let grid_data_impl = GridManagerViewDataImpl(grid_manager);
@ -130,45 +133,45 @@ impl WSMessageReceiver for FolderWSMessageReceiverImpl {
}
}
struct BlockManagerViewDataImpl(Arc<BlockManager>);
struct BlockManagerViewDataImpl(Arc<TextBlockManager>);
impl ViewDataProcessor for BlockManagerViewDataImpl {
fn initialize(&self) -> FutureResult<(), FlowyError> {
let block_manager = self.0.clone();
FutureResult::new(async move { block_manager.init() })
let manager = self.0.clone();
FutureResult::new(async move { manager.init() })
}
fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError> {
let block_manager = self.0.clone();
let manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = block_manager.create_block(view_id, repeated_revision).await?;
let _ = manager.create_block(view_id, repeated_revision).await?;
Ok(())
})
}
fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let block_manager = self.0.clone();
let manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = block_manager.delete_block(view_id)?;
let _ = manager.delete_block(view_id)?;
Ok(())
})
}
fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let block_manager = self.0.clone();
let manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = block_manager.close_block(view_id)?;
let _ = manager.close_block(view_id)?;
Ok(())
})
}
fn delta_str(&self, view_id: &str) -> FutureResult<String, FlowyError> {
let view_id = view_id.to_string();
let block_manager = self.0.clone();
let manager = self.0.clone();
FutureResult::new(async move {
let editor = block_manager.open_block(view_id).await?;
let editor = manager.open_block(view_id).await?;
let delta_str = editor.delta_str().await?;
Ok(delta_str)
})

View File

@ -1,10 +1,10 @@
mod block_deps;
mod folder_deps;
mod grid_deps;
mod text_block_deps;
mod user_deps;
mod util;
pub use block_deps::*;
pub use folder_deps::*;
pub use grid_deps::*;
pub use text_block_deps::*;
pub use user_deps::*;

View File

@ -1,7 +1,7 @@
use bytes::Bytes;
use flowy_block::{
errors::{internal_error, FlowyError},
BlockCloudService, BlockManager, BlockUser,
BlockCloudService, TextBlockManager, TextBlockUser,
};
use flowy_collaboration::entities::ws_data::ClientRevisionWSData;
use flowy_database::ConnectionPool;
@ -16,22 +16,22 @@ use lib_infra::future::BoxResultFuture;
use lib_ws::{WSChannel, WSMessageReceiver, WebSocketRawMessage};
use std::{convert::TryInto, path::Path, sync::Arc};
pub struct BlockDepsResolver();
impl BlockDepsResolver {
pub struct TextBlockDepsResolver();
impl TextBlockDepsResolver {
pub fn resolve(
local_server: Option<Arc<LocalServer>>,
ws_conn: Arc<FlowyWebSocketConnect>,
user_session: Arc<UserSession>,
server_config: &ClientServerConfiguration,
) -> Arc<BlockManager> {
) -> Arc<TextBlockManager> {
let user = Arc::new(BlockUserImpl(user_session));
let rev_web_socket = Arc::new(BlockWebSocket(ws_conn.clone()));
let rev_web_socket = Arc::new(TextBlockWebSocket(ws_conn.clone()));
let cloud_service: Arc<dyn BlockCloudService> = match local_server {
None => Arc::new(BlockHttpCloudService::new(server_config.clone())),
Some(local_server) => local_server,
};
let manager = Arc::new(BlockManager::new(cloud_service, user, rev_web_socket));
let manager = Arc::new(TextBlockManager::new(cloud_service, user, rev_web_socket));
let receiver = Arc::new(DocumentWSMessageReceiverImpl(manager.clone()));
ws_conn.add_ws_message_receiver(receiver).unwrap();
@ -40,7 +40,7 @@ impl BlockDepsResolver {
}
struct BlockUserImpl(Arc<UserSession>);
impl BlockUser for BlockUserImpl {
impl TextBlockUser for BlockUserImpl {
fn user_dir(&self) -> Result<String, FlowyError> {
let dir = self.0.user_dir().map_err(|e| FlowyError::unauthorized().context(e))?;
@ -64,8 +64,8 @@ impl BlockUser for BlockUserImpl {
}
}
struct BlockWebSocket(Arc<FlowyWebSocketConnect>);
impl RevisionWebSocket for BlockWebSocket {
struct TextBlockWebSocket(Arc<FlowyWebSocketConnect>);
impl RevisionWebSocket for TextBlockWebSocket {
fn send(&self, data: ClientRevisionWSData) -> BoxResultFuture<(), FlowyError> {
let bytes: Bytes = data.try_into().unwrap();
let msg = WebSocketRawMessage {
@ -90,7 +90,7 @@ impl RevisionWebSocket for BlockWebSocket {
}
}
struct DocumentWSMessageReceiverImpl(Arc<BlockManager>);
struct DocumentWSMessageReceiverImpl(Arc<TextBlockManager>);
impl WSMessageReceiver for DocumentWSMessageReceiverImpl {
fn source(&self) -> WSChannel {
WSChannel::Document

View File

@ -3,7 +3,7 @@ pub mod module;
pub use flowy_net::get_client_server_configuration;
use crate::deps_resolve::*;
use flowy_block::BlockManager;
use flowy_block::TextBlockManager;
use flowy_folder::{errors::FlowyError, manager::FolderManager};
use flowy_grid::manager::GridManager;
use flowy_net::ClientServerConfiguration;
@ -88,7 +88,7 @@ pub struct FlowySDK {
#[allow(dead_code)]
config: FlowySDKConfig,
pub user_session: Arc<UserSession>,
pub block_manager: Arc<BlockManager>,
pub text_block_manager: Arc<TextBlockManager>,
pub folder_manager: Arc<FolderManager>,
pub grid_manager: Arc<GridManager>,
pub dispatcher: Arc<EventDispatcher>,
@ -103,9 +103,9 @@ impl FlowySDK {
tracing::debug!("🔥 {:?}", config);
let runtime = tokio_default_runtime().unwrap();
let (local_server, ws_conn) = mk_local_server(&config.server_config);
let (user_session, block_manager, folder_manager, local_server, grid_manager) = runtime.block_on(async {
let (user_session, text_block_manager, folder_manager, local_server, grid_manager) = runtime.block_on(async {
let user_session = mk_user_session(&config, &local_server, &config.server_config);
let block_manager = BlockDepsResolver::resolve(
let text_block_manager = TextBlockDepsResolver::resolve(
local_server.clone(),
ws_conn.clone(),
user_session.clone(),
@ -119,7 +119,7 @@ impl FlowySDK {
user_session.clone(),
&config.server_config,
&ws_conn,
&block_manager,
&text_block_manager,
&grid_manager,
)
.await;
@ -128,11 +128,23 @@ impl FlowySDK {
local_server.run();
}
ws_conn.init().await;
(user_session, block_manager, folder_manager, local_server, grid_manager)
(
user_session,
text_block_manager,
folder_manager,
local_server,
grid_manager,
)
});
let dispatcher = Arc::new(EventDispatcher::construct(runtime, || {
mk_modules(&ws_conn, &folder_manager, &grid_manager, &user_session, &block_manager)
mk_modules(
&ws_conn,
&folder_manager,
&grid_manager,
&user_session,
&text_block_manager,
)
}));
_start_listening(&dispatcher, &ws_conn, &user_session, &folder_manager);
@ -140,7 +152,7 @@ impl FlowySDK {
Self {
config,
user_session,
block_manager,
text_block_manager,
folder_manager,
grid_manager,
dispatcher,

View File

@ -1,4 +1,4 @@
use flowy_block::BlockManager;
use flowy_block::TextBlockManager;
use flowy_folder::manager::FolderManager;
use flowy_grid::manager::GridManager;
use flowy_net::ws::connection::FlowyWebSocketConnect;
@ -11,14 +11,20 @@ pub fn mk_modules(
folder_manager: &Arc<FolderManager>,
grid_manager: &Arc<GridManager>,
user_session: &Arc<UserSession>,
block_manager: &Arc<BlockManager>,
text_block_manager: &Arc<TextBlockManager>,
) -> Vec<Module> {
let user_module = mk_user_module(user_session.clone());
let folder_module = mk_folder_module(folder_manager.clone());
let network_module = mk_network_module(ws_conn.clone());
let grid_module = mk_grid_module(grid_manager.clone());
let block_module = mk_block_module(block_manager.clone());
vec![user_module, folder_module, network_module, grid_module, block_module]
let text_block_module = mk_text_block_module(text_block_manager.clone());
vec![
user_module,
folder_module,
network_module,
grid_module,
text_block_module,
]
}
fn mk_user_module(user_session: Arc<UserSession>) -> Module {
@ -37,6 +43,6 @@ fn mk_grid_module(grid_manager: Arc<GridManager>) -> Module {
flowy_grid::event_map::create(grid_manager)
}
fn mk_block_module(block_manager: Arc<BlockManager>) -> Module {
flowy_block::event_map::create(block_manager)
fn mk_text_block_module(text_block_manager: Arc<TextBlockManager>) -> Module {
flowy_block::event_map::create(text_block_manager)
}

View File

@ -1,9 +1,14 @@
mod sql_impl;
mod folder_rev_impl;
mod grid_rev_impl;
mod text_block_rev_impl;
pub use folder_rev_impl::*;
pub use grid_rev_impl::*;
pub use text_block_rev_impl::*;
use crate::RevisionRecord;
use diesel::SqliteConnection;
use flowy_collaboration::entities::revision::RevisionRange;
pub use sql_impl::*;
use flowy_error::FlowyResult;
use std::fmt::Debug;

View File

@ -14,12 +14,12 @@ use flowy_database::{
use flowy_error::{internal_error, FlowyError, FlowyResult};
use std::sync::Arc;
pub struct SQLitePersistence {
pub struct SQLiteTextBlockRevisionPersistence {
user_id: String,
pub(crate) pool: Arc<ConnectionPool>,
}
impl RevisionDiskCache for SQLitePersistence {
impl RevisionDiskCache for SQLiteTextBlockRevisionPersistence {
type Error = FlowyError;
fn create_revision_records(
@ -83,7 +83,7 @@ impl RevisionDiskCache for SQLitePersistence {
}
}
impl SQLitePersistence {
impl SQLiteTextBlockRevisionPersistence {
pub(crate) fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self {
Self {
user_id: user_id.to_owned(),

View File

@ -1,325 +1,2 @@
mod disk;
mod memory;
use crate::cache::{
disk::{RevisionChangeset, RevisionDiskCache, RevisionTableState, SQLitePersistence},
memory::{RevisionMemoryCache, RevisionMemoryCacheDelegate},
};
use flowy_collaboration::entities::revision::{Revision, RevisionRange, RevisionState};
use flowy_database::ConnectionPool;
use flowy_error::{internal_error, FlowyError, FlowyResult};
use crate::RevisionCompact;
use std::collections::VecDeque;
use std::{borrow::Cow, sync::Arc};
use tokio::sync::RwLock;
use tokio::task::spawn_blocking;
pub const REVISION_WRITE_INTERVAL_IN_MILLIS: u64 = 600;
pub struct RevisionPersistence {
user_id: String,
object_id: String,
disk_cache: Arc<dyn RevisionDiskCache<Error = FlowyError>>,
memory_cache: Arc<RevisionMemoryCache>,
sync_seq: RwLock<RevisionSyncSequence>,
}
impl RevisionPersistence {
pub fn new(user_id: &str, object_id: &str, pool: Arc<ConnectionPool>) -> RevisionPersistence {
let disk_cache = Arc::new(SQLitePersistence::new(user_id, pool));
let memory_cache = Arc::new(RevisionMemoryCache::new(object_id, Arc::new(disk_cache.clone())));
let object_id = object_id.to_owned();
let user_id = user_id.to_owned();
let sync_seq = RwLock::new(RevisionSyncSequence::new());
Self {
user_id,
object_id,
disk_cache,
memory_cache,
sync_seq,
}
}
/// Save the revision that comes from remote to disk.
#[tracing::instrument(level = "trace", skip(self, revision), fields(rev_id, object_id=%self.object_id), err)]
pub(crate) async fn add_ack_revision(&self, revision: &Revision) -> FlowyResult<()> {
tracing::Span::current().record("rev_id", &revision.rev_id);
self.add(revision.clone(), RevisionState::Ack, true).await
}
/// Append the revision that already existed in the local DB state to sync sequence
#[tracing::instrument(level = "trace", skip(self), fields(rev_id, object_id=%self.object_id), err)]
pub(crate) async fn sync_revision(&self, revision: &Revision) -> FlowyResult<()> {
tracing::Span::current().record("rev_id", &revision.rev_id);
self.add(revision.clone(), RevisionState::Sync, false).await?;
self.sync_seq.write().await.add(revision.rev_id)?;
Ok(())
}
/// Save the revision to disk and append it to the end of the sync sequence.
#[tracing::instrument(level = "trace", skip(self, revision), fields(rev_id, compact_range, object_id=%self.object_id), err)]
pub(crate) async fn add_sync_revision<C>(&self, revision: &Revision) -> FlowyResult<i64>
where
C: RevisionCompact,
{
let result = self.sync_seq.read().await.compact();
match result {
None => {
tracing::Span::current().record("rev_id", &revision.rev_id);
self.add(revision.clone(), RevisionState::Sync, true).await?;
self.sync_seq.write().await.add(revision.rev_id)?;
Ok(revision.rev_id)
}
Some((range, mut compact_seq)) => {
tracing::Span::current().record("compact_range", &format!("{}", range).as_str());
let mut revisions = self.revisions_in_range(&range).await?;
if range.to_rev_ids().len() != revisions.len() {
debug_assert_eq!(range.to_rev_ids().len(), revisions.len());
}
// append the new revision
revisions.push(revision.clone());
// compact multiple revisions into one
let compact_revision = C::compact_revisions(&self.user_id, &self.object_id, revisions)?;
let rev_id = compact_revision.rev_id;
tracing::Span::current().record("rev_id", &rev_id);
// insert new revision
compact_seq.push_back(rev_id);
// replace the revisions in range with compact revision
self.compact(&range, compact_revision).await?;
debug_assert_eq!(self.sync_seq.read().await.len(), compact_seq.len());
self.sync_seq.write().await.reset(compact_seq);
Ok(rev_id)
}
}
}
/// Remove the revision with rev_id from the sync sequence.
pub(crate) async fn ack_revision(&self, rev_id: i64) -> FlowyResult<()> {
if self.sync_seq.write().await.ack(&rev_id).is_ok() {
self.memory_cache.ack(&rev_id).await;
}
Ok(())
}
pub(crate) async fn next_sync_revision(&self) -> FlowyResult<Option<Revision>> {
match self.sync_seq.read().await.next_rev_id() {
None => Ok(None),
Some(rev_id) => Ok(self.get(rev_id).await.map(|record| record.revision)),
}
}
/// The cache gets reset while it conflicts with the remote revisions.
#[tracing::instrument(level = "trace", skip(self, revisions), err)]
pub(crate) async fn reset(&self, revisions: Vec<Revision>) -> FlowyResult<()> {
let records = revisions
.to_vec()
.into_iter()
.map(|revision| RevisionRecord {
revision,
state: RevisionState::Sync,
write_to_disk: false,
})
.collect::<Vec<_>>();
let _ = self
.disk_cache
.delete_and_insert_records(&self.object_id, None, records.clone())?;
let _ = self.memory_cache.reset_with_revisions(records).await;
self.sync_seq.write().await.clear();
Ok(())
}
async fn add(&self, revision: Revision, state: RevisionState, write_to_disk: bool) -> FlowyResult<()> {
if self.memory_cache.contains(&revision.rev_id) {
tracing::warn!("Duplicate revision: {}:{}-{:?}", self.object_id, revision.rev_id, state);
return Ok(());
}
let record = RevisionRecord {
revision,
state,
write_to_disk,
};
self.memory_cache.add(Cow::Owned(record)).await;
Ok(())
}
async fn compact(&self, range: &RevisionRange, new_revision: Revision) -> FlowyResult<()> {
self.memory_cache.remove_with_range(range);
let rev_ids = range.to_rev_ids();
let _ = self
.disk_cache
.delete_revision_records(&self.object_id, Some(rev_ids))?;
self.add(new_revision, RevisionState::Sync, true).await?;
Ok(())
}
pub async fn get(&self, rev_id: i64) -> Option<RevisionRecord> {
match self.memory_cache.get(&rev_id).await {
None => match self
.disk_cache
.read_revision_records(&self.object_id, Some(vec![rev_id]))
{
Ok(mut records) => {
let record = records.pop()?;
assert!(records.is_empty());
Some(record)
}
Err(e) => {
tracing::error!("{}", e);
None
}
},
Some(revision) => Some(revision),
}
}
pub fn batch_get(&self, doc_id: &str) -> FlowyResult<Vec<RevisionRecord>> {
self.disk_cache.read_revision_records(doc_id, None)
}
// Read the revision which rev_id >= range.start && rev_id <= range.end
pub async fn revisions_in_range(&self, range: &RevisionRange) -> FlowyResult<Vec<Revision>> {
let range = range.clone();
let mut records = self.memory_cache.get_with_range(&range).await?;
let range_len = range.len() as usize;
if records.len() != range_len {
let disk_cache = self.disk_cache.clone();
let object_id = self.object_id.clone();
records = spawn_blocking(move || disk_cache.read_revision_records_with_range(&object_id, &range))
.await
.map_err(internal_error)??;
if records.len() != range_len {
// #[cfg(debug_assertions)]
// records.iter().for_each(|record| {
// let delta = PlainDelta::from_bytes(&record.revision.delta_data).unwrap();
// tracing::trace!("{}", delta.to_string());
// });
tracing::error!("Expect revision len {},but receive {}", range_len, records.len());
}
}
Ok(records
.into_iter()
.map(|record| record.revision)
.collect::<Vec<Revision>>())
}
}
pub fn mk_revision_disk_cache(
user_id: &str,
pool: Arc<ConnectionPool>,
) -> Arc<dyn RevisionDiskCache<Error = FlowyError>> {
Arc::new(SQLitePersistence::new(user_id, pool))
}
impl RevisionMemoryCacheDelegate for Arc<SQLitePersistence> {
#[tracing::instrument(level = "trace", skip(self, records), fields(checkpoint_result), err)]
fn checkpoint_tick(&self, mut records: Vec<RevisionRecord>) -> FlowyResult<()> {
let conn = &*self.pool.get().map_err(internal_error)?;
records.retain(|record| record.write_to_disk);
if !records.is_empty() {
tracing::Span::current().record(
"checkpoint_result",
&format!("{} records were saved", records.len()).as_str(),
);
let _ = self.create_revision_records(records, conn)?;
}
Ok(())
}
fn receive_ack(&self, object_id: &str, rev_id: i64) {
let changeset = RevisionChangeset {
object_id: object_id.to_string(),
rev_id: rev_id.into(),
state: RevisionTableState::Ack,
};
match self.update_revision_record(vec![changeset]) {
Ok(_) => {}
Err(e) => tracing::error!("{}", e),
}
}
}
#[derive(Clone, Debug)]
pub struct RevisionRecord {
pub revision: Revision,
pub state: RevisionState,
pub write_to_disk: bool,
}
impl RevisionRecord {
pub fn ack(&mut self) {
self.state = RevisionState::Ack;
}
}
#[derive(Default)]
struct RevisionSyncSequence(VecDeque<i64>);
impl RevisionSyncSequence {
fn new() -> Self {
RevisionSyncSequence::default()
}
fn add(&mut self, new_rev_id: i64) -> FlowyResult<()> {
// The last revision's rev_id must be greater than the new one.
if let Some(rev_id) = self.0.back() {
if *rev_id >= new_rev_id {
return Err(
FlowyError::internal().context(format!("The new revision's id must be greater than {}", rev_id))
);
}
}
self.0.push_back(new_rev_id);
Ok(())
}
fn ack(&mut self, rev_id: &i64) -> FlowyResult<()> {
let cur_rev_id = self.0.front().cloned();
if let Some(pop_rev_id) = cur_rev_id {
if &pop_rev_id != rev_id {
let desc = format!(
"The ack rev_id:{} is not equal to the current rev_id:{}",
rev_id, pop_rev_id
);
return Err(FlowyError::internal().context(desc));
}
let _ = self.0.pop_front();
}
Ok(())
}
fn next_rev_id(&self) -> Option<i64> {
self.0.front().cloned()
}
fn reset(&mut self, new_seq: VecDeque<i64>) {
self.0 = new_seq;
}
fn clear(&mut self) {
self.0.clear();
}
fn len(&self) -> usize {
self.0.len()
}
// Compact the rev_ids into one except the current synchronizing rev_id.
fn compact(&self) -> Option<(RevisionRange, VecDeque<i64>)> {
self.next_rev_id()?;
let mut new_seq = self.0.clone();
let mut drained = new_seq.drain(1..).collect::<VecDeque<_>>();
let start = drained.pop_front()?;
let end = drained.pop_back().unwrap_or(start);
Some((RevisionRange { start, end }, new_seq))
}
}
pub(crate) mod disk;
pub(crate) mod memory;

View File

@ -1,11 +1,13 @@
mod cache;
mod conflict_resolve;
mod rev_manager;
mod rev_persistence;
mod ws_manager;
pub use cache::*;
pub use conflict_resolve::*;
pub use rev_manager::*;
pub use rev_persistence::*;
pub use ws_manager::*;
#[macro_use]

View File

@ -0,0 +1,322 @@
use crate::cache::{
disk::{RevisionChangeset, RevisionDiskCache, RevisionTableState, SQLiteTextBlockRevisionPersistence},
memory::{RevisionMemoryCache, RevisionMemoryCacheDelegate},
};
use flowy_collaboration::entities::revision::{Revision, RevisionRange, RevisionState};
use flowy_database::ConnectionPool;
use flowy_error::{internal_error, FlowyError, FlowyResult};
use crate::RevisionCompact;
use std::collections::VecDeque;
use std::{borrow::Cow, sync::Arc};
use tokio::sync::RwLock;
use tokio::task::spawn_blocking;
pub const REVISION_WRITE_INTERVAL_IN_MILLIS: u64 = 600;
pub struct RevisionPersistence {
user_id: String,
object_id: String,
disk_cache: Arc<dyn RevisionDiskCache<Error = FlowyError>>,
memory_cache: Arc<RevisionMemoryCache>,
sync_seq: RwLock<RevisionSyncSequence>,
}
impl RevisionPersistence {
pub fn new(user_id: &str, object_id: &str, pool: Arc<ConnectionPool>) -> RevisionPersistence {
let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool));
let memory_cache = Arc::new(RevisionMemoryCache::new(object_id, Arc::new(disk_cache.clone())));
let object_id = object_id.to_owned();
let user_id = user_id.to_owned();
let sync_seq = RwLock::new(RevisionSyncSequence::new());
Self {
user_id,
object_id,
disk_cache,
memory_cache,
sync_seq,
}
}
/// Save the revision that comes from remote to disk.
#[tracing::instrument(level = "trace", skip(self, revision), fields(rev_id, object_id=%self.object_id), err)]
pub(crate) async fn add_ack_revision(&self, revision: &Revision) -> FlowyResult<()> {
tracing::Span::current().record("rev_id", &revision.rev_id);
self.add(revision.clone(), RevisionState::Ack, true).await
}
/// Append the revision that already existed in the local DB state to sync sequence
#[tracing::instrument(level = "trace", skip(self), fields(rev_id, object_id=%self.object_id), err)]
pub(crate) async fn sync_revision(&self, revision: &Revision) -> FlowyResult<()> {
tracing::Span::current().record("rev_id", &revision.rev_id);
self.add(revision.clone(), RevisionState::Sync, false).await?;
self.sync_seq.write().await.add(revision.rev_id)?;
Ok(())
}
/// Save the revision to disk and append it to the end of the sync sequence.
#[tracing::instrument(level = "trace", skip(self, revision), fields(rev_id, compact_range, object_id=%self.object_id), err)]
pub(crate) async fn add_sync_revision<C>(&self, revision: &Revision) -> FlowyResult<i64>
where
C: RevisionCompact,
{
let result = self.sync_seq.read().await.compact();
match result {
None => {
tracing::Span::current().record("rev_id", &revision.rev_id);
self.add(revision.clone(), RevisionState::Sync, true).await?;
self.sync_seq.write().await.add(revision.rev_id)?;
Ok(revision.rev_id)
}
Some((range, mut compact_seq)) => {
tracing::Span::current().record("compact_range", &format!("{}", range).as_str());
let mut revisions = self.revisions_in_range(&range).await?;
if range.to_rev_ids().len() != revisions.len() {
debug_assert_eq!(range.to_rev_ids().len(), revisions.len());
}
// append the new revision
revisions.push(revision.clone());
// compact multiple revisions into one
let compact_revision = C::compact_revisions(&self.user_id, &self.object_id, revisions)?;
let rev_id = compact_revision.rev_id;
tracing::Span::current().record("rev_id", &rev_id);
// insert new revision
compact_seq.push_back(rev_id);
// replace the revisions in range with compact revision
self.compact(&range, compact_revision).await?;
debug_assert_eq!(self.sync_seq.read().await.len(), compact_seq.len());
self.sync_seq.write().await.reset(compact_seq);
Ok(rev_id)
}
}
}
/// Remove the revision with rev_id from the sync sequence.
pub(crate) async fn ack_revision(&self, rev_id: i64) -> FlowyResult<()> {
if self.sync_seq.write().await.ack(&rev_id).is_ok() {
self.memory_cache.ack(&rev_id).await;
}
Ok(())
}
pub(crate) async fn next_sync_revision(&self) -> FlowyResult<Option<Revision>> {
match self.sync_seq.read().await.next_rev_id() {
None => Ok(None),
Some(rev_id) => Ok(self.get(rev_id).await.map(|record| record.revision)),
}
}
/// The cache gets reset while it conflicts with the remote revisions.
#[tracing::instrument(level = "trace", skip(self, revisions), err)]
pub(crate) async fn reset(&self, revisions: Vec<Revision>) -> FlowyResult<()> {
let records = revisions
.to_vec()
.into_iter()
.map(|revision| RevisionRecord {
revision,
state: RevisionState::Sync,
write_to_disk: false,
})
.collect::<Vec<_>>();
let _ = self
.disk_cache
.delete_and_insert_records(&self.object_id, None, records.clone())?;
let _ = self.memory_cache.reset_with_revisions(records).await;
self.sync_seq.write().await.clear();
Ok(())
}
async fn add(&self, revision: Revision, state: RevisionState, write_to_disk: bool) -> FlowyResult<()> {
if self.memory_cache.contains(&revision.rev_id) {
tracing::warn!("Duplicate revision: {}:{}-{:?}", self.object_id, revision.rev_id, state);
return Ok(());
}
let record = RevisionRecord {
revision,
state,
write_to_disk,
};
self.memory_cache.add(Cow::Owned(record)).await;
Ok(())
}
async fn compact(&self, range: &RevisionRange, new_revision: Revision) -> FlowyResult<()> {
self.memory_cache.remove_with_range(range);
let rev_ids = range.to_rev_ids();
let _ = self
.disk_cache
.delete_revision_records(&self.object_id, Some(rev_ids))?;
self.add(new_revision, RevisionState::Sync, true).await?;
Ok(())
}
pub async fn get(&self, rev_id: i64) -> Option<RevisionRecord> {
match self.memory_cache.get(&rev_id).await {
None => match self
.disk_cache
.read_revision_records(&self.object_id, Some(vec![rev_id]))
{
Ok(mut records) => {
let record = records.pop()?;
assert!(records.is_empty());
Some(record)
}
Err(e) => {
tracing::error!("{}", e);
None
}
},
Some(revision) => Some(revision),
}
}
pub fn batch_get(&self, doc_id: &str) -> FlowyResult<Vec<RevisionRecord>> {
self.disk_cache.read_revision_records(doc_id, None)
}
// Read the revision which rev_id >= range.start && rev_id <= range.end
pub async fn revisions_in_range(&self, range: &RevisionRange) -> FlowyResult<Vec<Revision>> {
let range = range.clone();
let mut records = self.memory_cache.get_with_range(&range).await?;
let range_len = range.len() as usize;
if records.len() != range_len {
let disk_cache = self.disk_cache.clone();
let object_id = self.object_id.clone();
records = spawn_blocking(move || disk_cache.read_revision_records_with_range(&object_id, &range))
.await
.map_err(internal_error)??;
if records.len() != range_len {
// #[cfg(debug_assertions)]
// records.iter().for_each(|record| {
// let delta = PlainDelta::from_bytes(&record.revision.delta_data).unwrap();
// tracing::trace!("{}", delta.to_string());
// });
tracing::error!("Expect revision len {},but receive {}", range_len, records.len());
}
}
Ok(records
.into_iter()
.map(|record| record.revision)
.collect::<Vec<Revision>>())
}
}
pub fn mk_revision_disk_cache(
user_id: &str,
pool: Arc<ConnectionPool>,
) -> Arc<dyn RevisionDiskCache<Error = FlowyError>> {
Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool))
}
impl RevisionMemoryCacheDelegate for Arc<SQLiteTextBlockRevisionPersistence> {
#[tracing::instrument(level = "trace", skip(self, records), fields(checkpoint_result), err)]
fn checkpoint_tick(&self, mut records: Vec<RevisionRecord>) -> FlowyResult<()> {
let conn = &*self.pool.get().map_err(internal_error)?;
records.retain(|record| record.write_to_disk);
if !records.is_empty() {
tracing::Span::current().record(
"checkpoint_result",
&format!("{} records were saved", records.len()).as_str(),
);
let _ = self.create_revision_records(records, conn)?;
}
Ok(())
}
fn receive_ack(&self, object_id: &str, rev_id: i64) {
let changeset = RevisionChangeset {
object_id: object_id.to_string(),
rev_id: rev_id.into(),
state: RevisionTableState::Ack,
};
match self.update_revision_record(vec![changeset]) {
Ok(_) => {}
Err(e) => tracing::error!("{}", e),
}
}
}
#[derive(Clone, Debug)]
pub struct RevisionRecord {
pub revision: Revision,
pub state: RevisionState,
pub write_to_disk: bool,
}
impl RevisionRecord {
pub fn ack(&mut self) {
self.state = RevisionState::Ack;
}
}
#[derive(Default)]
struct RevisionSyncSequence(VecDeque<i64>);
impl RevisionSyncSequence {
fn new() -> Self {
RevisionSyncSequence::default()
}
fn add(&mut self, new_rev_id: i64) -> FlowyResult<()> {
// The last revision's rev_id must be greater than the new one.
if let Some(rev_id) = self.0.back() {
if *rev_id >= new_rev_id {
return Err(
FlowyError::internal().context(format!("The new revision's id must be greater than {}", rev_id))
);
}
}
self.0.push_back(new_rev_id);
Ok(())
}
fn ack(&mut self, rev_id: &i64) -> FlowyResult<()> {
let cur_rev_id = self.0.front().cloned();
if let Some(pop_rev_id) = cur_rev_id {
if &pop_rev_id != rev_id {
let desc = format!(
"The ack rev_id:{} is not equal to the current rev_id:{}",
rev_id, pop_rev_id
);
return Err(FlowyError::internal().context(desc));
}
let _ = self.0.pop_front();
}
Ok(())
}
fn next_rev_id(&self) -> Option<i64> {
self.0.front().cloned()
}
fn reset(&mut self, new_seq: VecDeque<i64>) {
self.0 = new_seq;
}
fn clear(&mut self) {
self.0.clear();
}
fn len(&self) -> usize {
self.0.len()
}
// Compact the rev_ids into one except the current synchronizing rev_id.
fn compact(&self) -> Option<(RevisionRange, VecDeque<i64>)> {
self.next_rev_id()?;
let mut new_seq = self.0.clone();
let mut drained = new_seq.drain(1..).collect::<VecDeque<_>>();
let start = drained.pop_front()?;
let end = drained.pop_back().unwrap_or(start);
Some((RevisionRange { start, end }, new_seq))
}
}

View File

@ -0,0 +1,115 @@
use crate::entities::revision::{md5, RepeatedRevision, Revision};
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_delta_from_revisions};
use flowy_grid_data_model::entities::{BlockMeta, RowMeta, RowOrder};
use lib_infra::uuid;
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
use std::sync::Arc;
pub type BlockMetaDelta = PlainTextDelta;
pub type BlockDeltaBuilder = PlainTextDeltaBuilder;
pub struct BlockMetaPad {
pub(crate) block_meta: Arc<BlockMeta>,
pub(crate) delta: BlockMetaDelta,
}
impl BlockMetaPad {
pub fn from_delta(delta: BlockMetaDelta) -> CollaborateResult<Self> {
let s = delta.to_str()?;
let block_delta: BlockMeta = serde_json::from_str(&s).map_err(|e| {
CollaborateError::internal().context(format!("Deserialize delta to block meta failed: {}", e))
})?;
Ok(Self {
block_meta: Arc::new(block_delta),
delta,
})
}
pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
let block_delta: BlockMetaDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
Self::from_delta(block_delta)
}
pub fn create_row(&mut self, row: RowMeta) -> CollaborateResult<Option<BlockMetaChange>> {
self.modify(|grid| {
grid.rows.push(row);
Ok(Some(()))
})
}
pub fn delete_rows(&mut self, row_ids: &[String]) -> CollaborateResult<Option<BlockMetaChange>> {
self.modify(|grid| {
grid.rows.retain(|row| !row_ids.contains(&row.id));
Ok(Some(()))
})
}
pub fn md5(&self) -> String {
md5(&self.delta.to_bytes())
}
pub fn delta_str(&self) -> String {
self.delta.to_delta_str()
}
pub fn modify<F>(&mut self, f: F) -> CollaborateResult<Option<BlockMetaChange>>
where
F: FnOnce(&mut BlockMeta) -> CollaborateResult<Option<()>>,
{
let cloned_meta = self.block_meta.clone();
match f(Arc::make_mut(&mut self.block_meta))? {
None => Ok(None),
Some(_) => {
let old = json_from_grid(&cloned_meta)?;
let new = json_from_grid(&self.block_meta)?;
match cal_diff::<PlainTextAttributes>(old, new) {
None => Ok(None),
Some(delta) => {
self.delta = self.delta.compose(&delta)?;
Ok(Some(BlockMetaChange { delta, md5: self.md5() }))
}
}
}
}
}
}
fn json_from_grid(block_meta: &Arc<BlockMeta>) -> CollaborateResult<String> {
let json = serde_json::to_string(block_meta)
.map_err(|err| internal_error(format!("Serialize grid to json str failed. {:?}", err)))?;
Ok(json)
}
pub struct BlockMetaChange {
pub delta: BlockMetaDelta,
/// md5: the md5 of the grid after applying the change.
pub md5: String,
}
pub fn make_block_meta_delta(block_meta: &BlockMeta) -> BlockMetaDelta {
let json = serde_json::to_string(&block_meta).unwrap();
PlainTextDeltaBuilder::new().insert(&json).build()
}
pub fn make_block_meta_revisions(user_id: &str, block_meta: &BlockMeta) -> RepeatedRevision {
let delta = make_block_meta_delta(block_meta);
let bytes = delta.to_bytes();
let revision = Revision::initial_revision(user_id, &block_meta.block_id, bytes);
revision.into()
}
impl std::default::Default for BlockMetaPad {
fn default() -> Self {
let block_meta = BlockMeta {
block_id: uuid(),
rows: vec![],
};
let delta = make_block_meta_delta(&block_meta);
BlockMetaPad {
block_meta: Arc::new(block_meta),
delta,
}
}
}

View File

@ -33,7 +33,7 @@ impl GridMetaPad {
pub fn create_row(&mut self, row: RowMeta) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| {
grid.rows.push(row);
// grid.rows.push(row);
Ok(Some(()))
})
}
@ -47,7 +47,7 @@ impl GridMetaPad {
pub fn delete_rows(&mut self, row_ids: &[String]) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| {
grid.rows.retain(|row| !row_ids.contains(&row.id));
// grid.rows.retain(|row| !row_ids.contains(&row.id));
Ok(Some(()))
})
}
@ -74,17 +74,17 @@ impl GridMetaPad {
.map(FieldOrder::from)
.collect::<Vec<FieldOrder>>();
let row_orders = self
.grid_meta
.rows
.iter()
.map(RowOrder::from)
.collect::<Vec<RowOrder>>();
// let row_orders = self
// .grid_meta
// .rows
// .iter()
// .map(RowOrder::from)
// .collect::<Vec<RowOrder>>();
Grid {
id: "".to_string(),
field_orders,
row_orders,
row_orders: vec![],
}
}
@ -147,7 +147,7 @@ impl std::default::Default for GridMetaPad {
let grid = GridMeta {
grid_id: uuid(),
fields: vec![],
rows: vec![],
blocks: vec![],
};
let delta = make_grid_delta(&grid);
GridMetaPad {

View File

@ -1,3 +1,5 @@
mod block_pad;
mod grid_pad;
pub use block_pad::*;
pub use grid_pad::*;

View File

@ -1,5 +1,5 @@
pub mod document_info;
pub mod folder_info;
pub mod parser;
pub mod revision;
pub mod text_block_info;
pub mod ws_data;

View File

@ -6,7 +6,7 @@ use flowy_derive::ProtoBuf;
use lib_ot::{errors::OTError, rich_text::RichTextDelta};
#[derive(ProtoBuf, Default, Debug, Clone)]
pub struct CreateBlockParams {
pub struct CreateTextBlockParams {
#[pb(index = 1)]
pub id: String,
@ -15,7 +15,7 @@ pub struct CreateBlockParams {
}
#[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)]
pub struct BlockInfo {
pub struct TextBlockInfo {
#[pb(index = 1)]
pub block_id: String,
@ -29,14 +29,14 @@ pub struct BlockInfo {
pub base_rev_id: i64,
}
impl BlockInfo {
impl TextBlockInfo {
pub fn delta(&self) -> Result<RichTextDelta, OTError> {
let delta = RichTextDelta::from_bytes(&self.text)?;
Ok(delta)
}
}
impl std::convert::TryFrom<Revision> for BlockInfo {
impl std::convert::TryFrom<Revision> for TextBlockInfo {
type Error = CollaborateError;
fn try_from(revision: Revision) -> Result<Self, Self::Error> {
@ -48,7 +48,7 @@ impl std::convert::TryFrom<Revision> for BlockInfo {
let delta = RichTextDelta::from_bytes(&revision.delta_data)?;
let doc_json = delta.to_delta_str();
Ok(BlockInfo {
Ok(TextBlockInfo {
block_id: revision.object_id,
text: doc_json,
rev_id: revision.rev_id,
@ -58,7 +58,7 @@ impl std::convert::TryFrom<Revision> for BlockInfo {
}
#[derive(ProtoBuf, Default, Debug, Clone)]
pub struct ResetBlockParams {
pub struct ResetTextBlockParams {
#[pb(index = 1)]
pub block_id: String,
@ -67,7 +67,7 @@ pub struct ResetBlockParams {
}
#[derive(ProtoBuf, Default, Debug, Clone)]
pub struct BlockDelta {
pub struct TextBlockDelta {
#[pb(index = 1)]
pub block_id: String,
@ -88,30 +88,30 @@ pub struct NewDocUser {
}
#[derive(ProtoBuf, Default, Debug, Clone)]
pub struct BlockId {
pub struct TextBlockId {
#[pb(index = 1)]
pub value: String,
}
impl AsRef<str> for BlockId {
impl AsRef<str> for TextBlockId {
fn as_ref(&self) -> &str {
&self.value
}
}
impl std::convert::From<String> for BlockId {
impl std::convert::From<String> for TextBlockId {
fn from(value: String) -> Self {
BlockId { value }
TextBlockId { value }
}
}
impl std::convert::From<BlockId> for String {
fn from(block_id: BlockId) -> Self {
impl std::convert::From<TextBlockId> for String {
fn from(block_id: TextBlockId) -> Self {
block_id.value
}
}
impl std::convert::From<&String> for BlockId {
impl std::convert::From<&String> for TextBlockId {
fn from(s: &String) -> Self {
BlockId { value: s.to_owned() }
TextBlockId { value: s.to_owned() }
}
}

View File

@ -7,8 +7,8 @@ pub use folder_info::*;
mod ws_data;
pub use ws_data::*;
mod text_block_info;
pub use text_block_info::*;
mod revision;
pub use revision::*;
mod document_info;
pub use document_info::*;

View File

@ -17,14 +17,14 @@
#![allow(trivial_casts)]
#![allow(unused_imports)]
#![allow(unused_results)]
//! Generated file from `document_info.proto`
//! Generated file from `text_block_info.proto`
/// Generated files are compatible only with the same version
/// of protobuf runtime.
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2;
#[derive(PartialEq,Clone,Default)]
pub struct CreateBlockParams {
pub struct CreateTextBlockParams {
// message fields
pub id: ::std::string::String,
pub revisions: ::protobuf::SingularPtrField<super::revision::RepeatedRevision>,
@ -33,14 +33,14 @@ pub struct CreateBlockParams {
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a CreateBlockParams {
fn default() -> &'a CreateBlockParams {
<CreateBlockParams as ::protobuf::Message>::default_instance()
impl<'a> ::std::default::Default for &'a CreateTextBlockParams {
fn default() -> &'a CreateTextBlockParams {
<CreateTextBlockParams as ::protobuf::Message>::default_instance()
}
}
impl CreateBlockParams {
pub fn new() -> CreateBlockParams {
impl CreateTextBlockParams {
pub fn new() -> CreateTextBlockParams {
::std::default::Default::default()
}
@ -104,7 +104,7 @@ impl CreateBlockParams {
}
}
impl ::protobuf::Message for CreateBlockParams {
impl ::protobuf::Message for CreateTextBlockParams {
fn is_initialized(&self) -> bool {
for v in &self.revisions {
if !v.is_initialized() {
@ -187,8 +187,8 @@ impl ::protobuf::Message for CreateBlockParams {
Self::descriptor_static()
}
fn new() -> CreateBlockParams {
CreateBlockParams::new()
fn new() -> CreateTextBlockParams {
CreateTextBlockParams::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -197,29 +197,29 @@ impl ::protobuf::Message for CreateBlockParams {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"id",
|m: &CreateBlockParams| { &m.id },
|m: &mut CreateBlockParams| { &mut m.id },
|m: &CreateTextBlockParams| { &m.id },
|m: &mut CreateTextBlockParams| { &mut m.id },
));
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<super::revision::RepeatedRevision>>(
"revisions",
|m: &CreateBlockParams| { &m.revisions },
|m: &mut CreateBlockParams| { &mut m.revisions },
|m: &CreateTextBlockParams| { &m.revisions },
|m: &mut CreateTextBlockParams| { &mut m.revisions },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<CreateBlockParams>(
"CreateBlockParams",
::protobuf::reflect::MessageDescriptor::new_pb_name::<CreateTextBlockParams>(
"CreateTextBlockParams",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static CreateBlockParams {
static instance: ::protobuf::rt::LazyV2<CreateBlockParams> = ::protobuf::rt::LazyV2::INIT;
instance.get(CreateBlockParams::new)
fn default_instance() -> &'static CreateTextBlockParams {
static instance: ::protobuf::rt::LazyV2<CreateTextBlockParams> = ::protobuf::rt::LazyV2::INIT;
instance.get(CreateTextBlockParams::new)
}
}
impl ::protobuf::Clear for CreateBlockParams {
impl ::protobuf::Clear for CreateTextBlockParams {
fn clear(&mut self) {
self.id.clear();
self.revisions.clear();
@ -227,20 +227,20 @@ impl ::protobuf::Clear for CreateBlockParams {
}
}
impl ::std::fmt::Debug for CreateBlockParams {
impl ::std::fmt::Debug for CreateTextBlockParams {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for CreateBlockParams {
impl ::protobuf::reflect::ProtobufValue for CreateTextBlockParams {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
#[derive(PartialEq,Clone,Default)]
pub struct BlockInfo {
pub struct TextBlockInfo {
// message fields
pub block_id: ::std::string::String,
pub text: ::std::string::String,
@ -251,14 +251,14 @@ pub struct BlockInfo {
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a BlockInfo {
fn default() -> &'a BlockInfo {
<BlockInfo as ::protobuf::Message>::default_instance()
impl<'a> ::std::default::Default for &'a TextBlockInfo {
fn default() -> &'a TextBlockInfo {
<TextBlockInfo as ::protobuf::Message>::default_instance()
}
}
impl BlockInfo {
pub fn new() -> BlockInfo {
impl TextBlockInfo {
pub fn new() -> TextBlockInfo {
::std::default::Default::default()
}
@ -345,7 +345,7 @@ impl BlockInfo {
}
}
impl ::protobuf::Message for BlockInfo {
impl ::protobuf::Message for TextBlockInfo {
fn is_initialized(&self) -> bool {
true
}
@ -446,8 +446,8 @@ impl ::protobuf::Message for BlockInfo {
Self::descriptor_static()
}
fn new() -> BlockInfo {
BlockInfo::new()
fn new() -> TextBlockInfo {
TextBlockInfo::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -456,39 +456,39 @@ impl ::protobuf::Message for BlockInfo {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"block_id",
|m: &BlockInfo| { &m.block_id },
|m: &mut BlockInfo| { &mut m.block_id },
|m: &TextBlockInfo| { &m.block_id },
|m: &mut TextBlockInfo| { &mut m.block_id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"text",
|m: &BlockInfo| { &m.text },
|m: &mut BlockInfo| { &mut m.text },
|m: &TextBlockInfo| { &m.text },
|m: &mut TextBlockInfo| { &mut m.text },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>(
"rev_id",
|m: &BlockInfo| { &m.rev_id },
|m: &mut BlockInfo| { &mut m.rev_id },
|m: &TextBlockInfo| { &m.rev_id },
|m: &mut TextBlockInfo| { &mut m.rev_id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>(
"base_rev_id",
|m: &BlockInfo| { &m.base_rev_id },
|m: &mut BlockInfo| { &mut m.base_rev_id },
|m: &TextBlockInfo| { &m.base_rev_id },
|m: &mut TextBlockInfo| { &mut m.base_rev_id },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<BlockInfo>(
"BlockInfo",
::protobuf::reflect::MessageDescriptor::new_pb_name::<TextBlockInfo>(
"TextBlockInfo",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static BlockInfo {
static instance: ::protobuf::rt::LazyV2<BlockInfo> = ::protobuf::rt::LazyV2::INIT;
instance.get(BlockInfo::new)
fn default_instance() -> &'static TextBlockInfo {
static instance: ::protobuf::rt::LazyV2<TextBlockInfo> = ::protobuf::rt::LazyV2::INIT;
instance.get(TextBlockInfo::new)
}
}
impl ::protobuf::Clear for BlockInfo {
impl ::protobuf::Clear for TextBlockInfo {
fn clear(&mut self) {
self.block_id.clear();
self.text.clear();
@ -498,20 +498,20 @@ impl ::protobuf::Clear for BlockInfo {
}
}
impl ::std::fmt::Debug for BlockInfo {
impl ::std::fmt::Debug for TextBlockInfo {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for BlockInfo {
impl ::protobuf::reflect::ProtobufValue for TextBlockInfo {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
#[derive(PartialEq,Clone,Default)]
pub struct ResetBlockParams {
pub struct ResetTextBlockParams {
// message fields
pub block_id: ::std::string::String,
pub revisions: ::protobuf::SingularPtrField<super::revision::RepeatedRevision>,
@ -520,14 +520,14 @@ pub struct ResetBlockParams {
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a ResetBlockParams {
fn default() -> &'a ResetBlockParams {
<ResetBlockParams as ::protobuf::Message>::default_instance()
impl<'a> ::std::default::Default for &'a ResetTextBlockParams {
fn default() -> &'a ResetTextBlockParams {
<ResetTextBlockParams as ::protobuf::Message>::default_instance()
}
}
impl ResetBlockParams {
pub fn new() -> ResetBlockParams {
impl ResetTextBlockParams {
pub fn new() -> ResetTextBlockParams {
::std::default::Default::default()
}
@ -591,7 +591,7 @@ impl ResetBlockParams {
}
}
impl ::protobuf::Message for ResetBlockParams {
impl ::protobuf::Message for ResetTextBlockParams {
fn is_initialized(&self) -> bool {
for v in &self.revisions {
if !v.is_initialized() {
@ -674,8 +674,8 @@ impl ::protobuf::Message for ResetBlockParams {
Self::descriptor_static()
}
fn new() -> ResetBlockParams {
ResetBlockParams::new()
fn new() -> ResetTextBlockParams {
ResetTextBlockParams::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -684,29 +684,29 @@ impl ::protobuf::Message for ResetBlockParams {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"block_id",
|m: &ResetBlockParams| { &m.block_id },
|m: &mut ResetBlockParams| { &mut m.block_id },
|m: &ResetTextBlockParams| { &m.block_id },
|m: &mut ResetTextBlockParams| { &mut m.block_id },
));
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<super::revision::RepeatedRevision>>(
"revisions",
|m: &ResetBlockParams| { &m.revisions },
|m: &mut ResetBlockParams| { &mut m.revisions },
|m: &ResetTextBlockParams| { &m.revisions },
|m: &mut ResetTextBlockParams| { &mut m.revisions },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<ResetBlockParams>(
"ResetBlockParams",
::protobuf::reflect::MessageDescriptor::new_pb_name::<ResetTextBlockParams>(
"ResetTextBlockParams",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static ResetBlockParams {
static instance: ::protobuf::rt::LazyV2<ResetBlockParams> = ::protobuf::rt::LazyV2::INIT;
instance.get(ResetBlockParams::new)
fn default_instance() -> &'static ResetTextBlockParams {
static instance: ::protobuf::rt::LazyV2<ResetTextBlockParams> = ::protobuf::rt::LazyV2::INIT;
instance.get(ResetTextBlockParams::new)
}
}
impl ::protobuf::Clear for ResetBlockParams {
impl ::protobuf::Clear for ResetTextBlockParams {
fn clear(&mut self) {
self.block_id.clear();
self.revisions.clear();
@ -714,20 +714,20 @@ impl ::protobuf::Clear for ResetBlockParams {
}
}
impl ::std::fmt::Debug for ResetBlockParams {
impl ::std::fmt::Debug for ResetTextBlockParams {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for ResetBlockParams {
impl ::protobuf::reflect::ProtobufValue for ResetTextBlockParams {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
#[derive(PartialEq,Clone,Default)]
pub struct BlockDelta {
pub struct TextBlockDelta {
// message fields
pub block_id: ::std::string::String,
pub delta_str: ::std::string::String,
@ -736,14 +736,14 @@ pub struct BlockDelta {
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a BlockDelta {
fn default() -> &'a BlockDelta {
<BlockDelta as ::protobuf::Message>::default_instance()
impl<'a> ::std::default::Default for &'a TextBlockDelta {
fn default() -> &'a TextBlockDelta {
<TextBlockDelta as ::protobuf::Message>::default_instance()
}
}
impl BlockDelta {
pub fn new() -> BlockDelta {
impl TextBlockDelta {
pub fn new() -> TextBlockDelta {
::std::default::Default::default()
}
@ -800,7 +800,7 @@ impl BlockDelta {
}
}
impl ::protobuf::Message for BlockDelta {
impl ::protobuf::Message for TextBlockDelta {
fn is_initialized(&self) -> bool {
true
}
@ -875,8 +875,8 @@ impl ::protobuf::Message for BlockDelta {
Self::descriptor_static()
}
fn new() -> BlockDelta {
BlockDelta::new()
fn new() -> TextBlockDelta {
TextBlockDelta::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -885,29 +885,29 @@ impl ::protobuf::Message for BlockDelta {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"block_id",
|m: &BlockDelta| { &m.block_id },
|m: &mut BlockDelta| { &mut m.block_id },
|m: &TextBlockDelta| { &m.block_id },
|m: &mut TextBlockDelta| { &mut m.block_id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"delta_str",
|m: &BlockDelta| { &m.delta_str },
|m: &mut BlockDelta| { &mut m.delta_str },
|m: &TextBlockDelta| { &m.delta_str },
|m: &mut TextBlockDelta| { &mut m.delta_str },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<BlockDelta>(
"BlockDelta",
::protobuf::reflect::MessageDescriptor::new_pb_name::<TextBlockDelta>(
"TextBlockDelta",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static BlockDelta {
static instance: ::protobuf::rt::LazyV2<BlockDelta> = ::protobuf::rt::LazyV2::INIT;
instance.get(BlockDelta::new)
fn default_instance() -> &'static TextBlockDelta {
static instance: ::protobuf::rt::LazyV2<TextBlockDelta> = ::protobuf::rt::LazyV2::INIT;
instance.get(TextBlockDelta::new)
}
}
impl ::protobuf::Clear for BlockDelta {
impl ::protobuf::Clear for TextBlockDelta {
fn clear(&mut self) {
self.block_id.clear();
self.delta_str.clear();
@ -915,13 +915,13 @@ impl ::protobuf::Clear for BlockDelta {
}
}
impl ::std::fmt::Debug for BlockDelta {
impl ::std::fmt::Debug for TextBlockDelta {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for BlockDelta {
impl ::protobuf::reflect::ProtobufValue for TextBlockDelta {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
@ -1164,7 +1164,7 @@ impl ::protobuf::reflect::ProtobufValue for NewDocUser {
}
#[derive(PartialEq,Clone,Default)]
pub struct BlockId {
pub struct TextBlockId {
// message fields
pub value: ::std::string::String,
// special fields
@ -1172,14 +1172,14 @@ pub struct BlockId {
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a BlockId {
fn default() -> &'a BlockId {
<BlockId as ::protobuf::Message>::default_instance()
impl<'a> ::std::default::Default for &'a TextBlockId {
fn default() -> &'a TextBlockId {
<TextBlockId as ::protobuf::Message>::default_instance()
}
}
impl BlockId {
pub fn new() -> BlockId {
impl TextBlockId {
pub fn new() -> TextBlockId {
::std::default::Default::default()
}
@ -1210,7 +1210,7 @@ impl BlockId {
}
}
impl ::protobuf::Message for BlockId {
impl ::protobuf::Message for TextBlockId {
fn is_initialized(&self) -> bool {
true
}
@ -1276,8 +1276,8 @@ impl ::protobuf::Message for BlockId {
Self::descriptor_static()
}
fn new() -> BlockId {
BlockId::new()
fn new() -> TextBlockId {
TextBlockId::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -1286,57 +1286,57 @@ impl ::protobuf::Message for BlockId {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"value",
|m: &BlockId| { &m.value },
|m: &mut BlockId| { &mut m.value },
|m: &TextBlockId| { &m.value },
|m: &mut TextBlockId| { &mut m.value },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<BlockId>(
"BlockId",
::protobuf::reflect::MessageDescriptor::new_pb_name::<TextBlockId>(
"TextBlockId",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static BlockId {
static instance: ::protobuf::rt::LazyV2<BlockId> = ::protobuf::rt::LazyV2::INIT;
instance.get(BlockId::new)
fn default_instance() -> &'static TextBlockId {
static instance: ::protobuf::rt::LazyV2<TextBlockId> = ::protobuf::rt::LazyV2::INIT;
instance.get(TextBlockId::new)
}
}
impl ::protobuf::Clear for BlockId {
impl ::protobuf::Clear for TextBlockId {
fn clear(&mut self) {
self.value.clear();
self.unknown_fields.clear();
}
}
impl ::std::fmt::Debug for BlockId {
impl ::std::fmt::Debug for TextBlockId {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for BlockId {
impl ::protobuf::reflect::ProtobufValue for TextBlockId {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x13document_info.proto\x1a\x0erevision.proto\"T\n\x11CreateBlockParam\
s\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12/\n\trevisions\x18\x02\
\x20\x01(\x0b2\x11.RepeatedRevisionR\trevisions\"q\n\tBlockInfo\x12\x19\
\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12\x12\n\x04text\x18\x02\
\x20\x01(\tR\x04text\x12\x15\n\x06rev_id\x18\x03\x20\x01(\x03R\x05revId\
\x12\x1e\n\x0bbase_rev_id\x18\x04\x20\x01(\x03R\tbaseRevId\"^\n\x10Reset\
BlockParams\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12/\n\
\trevisions\x18\x02\x20\x01(\x0b2\x11.RepeatedRevisionR\trevisions\"D\n\
\nBlockDelta\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12\
\x1b\n\tdelta_str\x18\x02\x20\x01(\tR\x08deltaStr\"S\n\nNewDocUser\x12\
\x17\n\x07user_id\x18\x01\x20\x01(\tR\x06userId\x12\x15\n\x06rev_id\x18\
\x02\x20\x01(\x03R\x05revId\x12\x15\n\x06doc_id\x18\x03\x20\x01(\tR\x05d\
ocId\"\x1f\n\x07BlockId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05valueb\
\x06proto3\
\n\x15text_block_info.proto\x1a\x0erevision.proto\"X\n\x15CreateTextBloc\
kParams\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12/\n\trevisions\x18\
\x02\x20\x01(\x0b2\x11.RepeatedRevisionR\trevisions\"u\n\rTextBlockInfo\
\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12\x12\n\x04text\
\x18\x02\x20\x01(\tR\x04text\x12\x15\n\x06rev_id\x18\x03\x20\x01(\x03R\
\x05revId\x12\x1e\n\x0bbase_rev_id\x18\x04\x20\x01(\x03R\tbaseRevId\"b\n\
\x14ResetTextBlockParams\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07bl\
ockId\x12/\n\trevisions\x18\x02\x20\x01(\x0b2\x11.RepeatedRevisionR\trev\
isions\"H\n\x0eTextBlockDelta\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\
\x07blockId\x12\x1b\n\tdelta_str\x18\x02\x20\x01(\tR\x08deltaStr\"S\n\nN\
ewDocUser\x12\x17\n\x07user_id\x18\x01\x20\x01(\tR\x06userId\x12\x15\n\
\x06rev_id\x18\x02\x20\x01(\x03R\x05revId\x12\x15\n\x06doc_id\x18\x03\
\x20\x01(\tR\x05docId\"#\n\x0bTextBlockId\x12\x14\n\x05value\x18\x01\x20\
\x01(\tR\x05valueb\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -1,21 +1,21 @@
syntax = "proto3";
import "revision.proto";
message CreateBlockParams {
message CreateTextBlockParams {
string id = 1;
RepeatedRevision revisions = 2;
}
message BlockInfo {
message TextBlockInfo {
string block_id = 1;
string text = 2;
int64 rev_id = 3;
int64 base_rev_id = 4;
}
message ResetBlockParams {
message ResetTextBlockParams {
string block_id = 1;
RepeatedRevision revisions = 2;
}
message BlockDelta {
message TextBlockDelta {
string block_id = 1;
string delta_str = 2;
}
@ -24,6 +24,6 @@ message NewDocUser {
int64 rev_id = 2;
string doc_id = 3;
}
message BlockId {
message TextBlockId {
string value = 1;
}

View File

@ -1,5 +1,5 @@
use crate::{
entities::{document_info::BlockInfo, ws_data::ServerRevisionWSDataBuilder},
entities::{text_block_info::TextBlockInfo, ws_data::ServerRevisionWSDataBuilder},
errors::{internal_error, CollaborateError, CollaborateResult},
protobuf::{ClientRevisionWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB},
server_document::document_pad::ServerDocument,
@ -18,13 +18,13 @@ use tokio::{
};
pub trait DocumentCloudPersistence: Send + Sync + Debug {
fn read_document(&self, doc_id: &str) -> BoxResultFuture<BlockInfo, CollaborateError>;
fn read_document(&self, doc_id: &str) -> BoxResultFuture<TextBlockInfo, CollaborateError>;
fn create_document(
&self,
doc_id: &str,
repeated_revision: RepeatedRevisionPB,
) -> BoxResultFuture<Option<BlockInfo>, CollaborateError>;
) -> BoxResultFuture<Option<TextBlockInfo>, CollaborateError>;
fn read_document_revisions(
&self,
@ -181,7 +181,7 @@ impl ServerDocumentManager {
}
}
async fn create_document_handler(&self, doc: BlockInfo) -> Result<Arc<OpenDocumentHandler>, CollaborateError> {
async fn create_document_handler(&self, doc: TextBlockInfo) -> Result<Arc<OpenDocumentHandler>, CollaborateError> {
let persistence = self.persistence.clone();
let handle = spawn_blocking(|| OpenDocumentHandler::new(doc, persistence))
.await
@ -205,7 +205,7 @@ struct OpenDocumentHandler {
}
impl OpenDocumentHandler {
fn new(doc: BlockInfo, persistence: Arc<dyn DocumentCloudPersistence>) -> Result<Self, CollaborateError> {
fn new(doc: TextBlockInfo, persistence: Arc<dyn DocumentCloudPersistence>) -> Result<Self, CollaborateError> {
let doc_id = doc.block_id.clone();
let (sender, receiver) = mpsc::channel(1000);
let users = DashMap::new();

View File

@ -1,13 +1,13 @@
use crate::{
entities::{
document_info::BlockInfo,
folder_info::{FolderDelta, FolderInfo},
revision::{RepeatedRevision, Revision},
text_block_info::TextBlockInfo,
},
errors::{CollaborateError, CollaborateResult},
protobuf::{
BlockInfo as BlockInfoPB, FolderInfo as FolderInfoPB, RepeatedRevision as RepeatedRevisionPB,
Revision as RevisionPB,
FolderInfo as FolderInfoPB, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB,
TextBlockInfo as TextBlockInfoPB,
},
};
use dissimilar::Chunk;
@ -202,11 +202,11 @@ pub fn make_folder_pb_from_revisions_pb(
pub fn make_document_info_from_revisions_pb(
doc_id: &str,
revisions: RepeatedRevisionPB,
) -> Result<Option<BlockInfo>, CollaborateError> {
) -> Result<Option<TextBlockInfo>, CollaborateError> {
match make_document_info_pb_from_revisions_pb(doc_id, revisions)? {
None => Ok(None),
Some(pb) => {
let document_info: BlockInfo = pb.try_into().map_err(|e| {
let document_info: TextBlockInfo = pb.try_into().map_err(|e| {
CollaborateError::internal().context(format!("Deserialize document info from pb failed: {}", e))
})?;
Ok(Some(document_info))
@ -218,7 +218,7 @@ pub fn make_document_info_from_revisions_pb(
pub fn make_document_info_pb_from_revisions_pb(
doc_id: &str,
mut revisions: RepeatedRevisionPB,
) -> Result<Option<BlockInfoPB>, CollaborateError> {
) -> Result<Option<TextBlockInfoPB>, CollaborateError> {
let revisions = revisions.take_items();
if revisions.is_empty() {
return Ok(None);
@ -240,7 +240,7 @@ pub fn make_document_info_pb_from_revisions_pb(
}
let text = document_delta.to_delta_str();
let mut block_info = BlockInfoPB::new();
let mut block_info = TextBlockInfoPB::new();
block_info.set_block_id(doc_id.to_owned());
block_info.set_text(text);
block_info.set_base_rev_id(base_rev_id);

View File

@ -1,8 +1,6 @@
use crate::entities::{Field, RowMeta};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use serde::{Deserialize, Serialize};
use flowy_derive::ProtoBuf;
use std::collections::HashMap;
use strum_macros::{Display, EnumIter, EnumString};
pub const DEFAULT_ROW_HEIGHT: i32 = 36;
pub const DEFAULT_FIELD_WIDTH: i32 = 150;

View File

@ -1,4 +1,3 @@
use crate::entities::Row;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
@ -16,14 +15,26 @@ pub struct GridMeta {
pub fields: Vec<Field>,
#[pb(index = 3)]
pub rows: Vec<RowMeta>,
pub blocks: Vec<Block>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
pub struct GridBlock {
pub struct Block {
#[pb(index = 1)]
pub id: String,
#[pb(index = 2)]
pub start_row_index: i32,
#[pb(index = 3)]
pub row_count: i32,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
pub struct BlockMeta {
#[pb(index = 1)]
pub block_id: String,
#[pb(index = 2)]
pub rows: Vec<RowMeta>,
}

View File

@ -28,7 +28,7 @@ pub struct GridMeta {
// message fields
pub grid_id: ::std::string::String,
pub fields: ::protobuf::RepeatedField<Field>,
pub rows: ::protobuf::RepeatedField<RowMeta>,
pub blocks: ::protobuf::RepeatedField<Block>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
@ -96,29 +96,29 @@ impl GridMeta {
::std::mem::replace(&mut self.fields, ::protobuf::RepeatedField::new())
}
// repeated .RowMeta rows = 3;
// repeated .Block blocks = 3;
pub fn get_rows(&self) -> &[RowMeta] {
&self.rows
pub fn get_blocks(&self) -> &[Block] {
&self.blocks
}
pub fn clear_rows(&mut self) {
self.rows.clear();
pub fn clear_blocks(&mut self) {
self.blocks.clear();
}
// Param is passed by value, moved
pub fn set_rows(&mut self, v: ::protobuf::RepeatedField<RowMeta>) {
self.rows = v;
pub fn set_blocks(&mut self, v: ::protobuf::RepeatedField<Block>) {
self.blocks = v;
}
// Mutable pointer to the field.
pub fn mut_rows(&mut self) -> &mut ::protobuf::RepeatedField<RowMeta> {
&mut self.rows
pub fn mut_blocks(&mut self) -> &mut ::protobuf::RepeatedField<Block> {
&mut self.blocks
}
// Take field
pub fn take_rows(&mut self) -> ::protobuf::RepeatedField<RowMeta> {
::std::mem::replace(&mut self.rows, ::protobuf::RepeatedField::new())
pub fn take_blocks(&mut self) -> ::protobuf::RepeatedField<Block> {
::std::mem::replace(&mut self.blocks, ::protobuf::RepeatedField::new())
}
}
@ -129,7 +129,7 @@ impl ::protobuf::Message for GridMeta {
return false;
}
};
for v in &self.rows {
for v in &self.blocks {
if !v.is_initialized() {
return false;
}
@ -148,7 +148,7 @@ impl ::protobuf::Message for GridMeta {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.fields)?;
},
3 => {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.rows)?;
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.blocks)?;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -169,7 +169,7 @@ impl ::protobuf::Message for GridMeta {
let len = value.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
};
for value in &self.rows {
for value in &self.blocks {
let len = value.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
};
@ -187,7 +187,7 @@ impl ::protobuf::Message for GridMeta {
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
};
for v in &self.rows {
for v in &self.blocks {
os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
@ -240,10 +240,10 @@ impl ::protobuf::Message for GridMeta {
|m: &GridMeta| { &m.fields },
|m: &mut GridMeta| { &mut m.fields },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowMeta>>(
"rows",
|m: &GridMeta| { &m.rows },
|m: &mut GridMeta| { &mut m.rows },
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<Block>>(
"blocks",
|m: &GridMeta| { &m.blocks },
|m: &mut GridMeta| { &mut m.blocks },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<GridMeta>(
"GridMeta",
@ -263,7 +263,7 @@ impl ::protobuf::Clear for GridMeta {
fn clear(&mut self) {
self.grid_id.clear();
self.fields.clear();
self.rows.clear();
self.blocks.clear();
self.unknown_fields.clear();
}
}
@ -281,23 +281,24 @@ impl ::protobuf::reflect::ProtobufValue for GridMeta {
}
#[derive(PartialEq,Clone,Default)]
pub struct GridBlock {
pub struct Block {
// message fields
pub id: ::std::string::String,
pub rows: ::protobuf::RepeatedField<RowMeta>,
pub start_row_index: i32,
pub row_count: i32,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a GridBlock {
fn default() -> &'a GridBlock {
<GridBlock as ::protobuf::Message>::default_instance()
impl<'a> ::std::default::Default for &'a Block {
fn default() -> &'a Block {
<Block as ::protobuf::Message>::default_instance()
}
}
impl GridBlock {
pub fn new() -> GridBlock {
impl Block {
pub fn new() -> Block {
::std::default::Default::default()
}
@ -327,6 +328,234 @@ impl GridBlock {
::std::mem::replace(&mut self.id, ::std::string::String::new())
}
// int32 start_row_index = 2;
pub fn get_start_row_index(&self) -> i32 {
self.start_row_index
}
pub fn clear_start_row_index(&mut self) {
self.start_row_index = 0;
}
// Param is passed by value, moved
pub fn set_start_row_index(&mut self, v: i32) {
self.start_row_index = v;
}
// int32 row_count = 3;
pub fn get_row_count(&self) -> i32 {
self.row_count
}
pub fn clear_row_count(&mut self) {
self.row_count = 0;
}
// Param is passed by value, moved
pub fn set_row_count(&mut self, v: i32) {
self.row_count = v;
}
}
impl ::protobuf::Message for Block {
fn is_initialized(&self) -> bool {
true
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
while !is.eof()? {
let (field_number, wire_type) = is.read_tag_unpack()?;
match field_number {
1 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
},
2 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
let tmp = is.read_int32()?;
self.start_row_index = tmp;
},
3 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
let tmp = is.read_int32()?;
self.row_count = tmp;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u32 {
let mut my_size = 0;
if !self.id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.id);
}
if self.start_row_index != 0 {
my_size += ::protobuf::rt::value_size(2, self.start_row_index, ::protobuf::wire_format::WireTypeVarint);
}
if self.row_count != 0 {
my_size += ::protobuf::rt::value_size(3, self.row_count, ::protobuf::wire_format::WireTypeVarint);
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
if !self.id.is_empty() {
os.write_string(1, &self.id)?;
}
if self.start_row_index != 0 {
os.write_int32(2, self.start_row_index)?;
}
if self.row_count != 0 {
os.write_int32(3, self.row_count)?;
}
os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
}
fn get_cached_size(&self) -> u32 {
self.cached_size.get()
}
fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
&self.unknown_fields
}
fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
&mut self.unknown_fields
}
fn as_any(&self) -> &dyn (::std::any::Any) {
self as &dyn (::std::any::Any)
}
fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
self as &mut dyn (::std::any::Any)
}
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
self
}
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
Self::descriptor_static()
}
fn new() -> Block {
Block::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"id",
|m: &Block| { &m.id },
|m: &mut Block| { &mut m.id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
"start_row_index",
|m: &Block| { &m.start_row_index },
|m: &mut Block| { &mut m.start_row_index },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
"row_count",
|m: &Block| { &m.row_count },
|m: &mut Block| { &mut m.row_count },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<Block>(
"Block",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static Block {
static instance: ::protobuf::rt::LazyV2<Block> = ::protobuf::rt::LazyV2::INIT;
instance.get(Block::new)
}
}
impl ::protobuf::Clear for Block {
fn clear(&mut self) {
self.id.clear();
self.start_row_index = 0;
self.row_count = 0;
self.unknown_fields.clear();
}
}
impl ::std::fmt::Debug for Block {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for Block {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
#[derive(PartialEq,Clone,Default)]
pub struct BlockMeta {
// message fields
pub block_id: ::std::string::String,
pub rows: ::protobuf::RepeatedField<RowMeta>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a BlockMeta {
fn default() -> &'a BlockMeta {
<BlockMeta as ::protobuf::Message>::default_instance()
}
}
impl BlockMeta {
pub fn new() -> BlockMeta {
::std::default::Default::default()
}
// string block_id = 1;
pub fn get_block_id(&self) -> &str {
&self.block_id
}
pub fn clear_block_id(&mut self) {
self.block_id.clear();
}
// Param is passed by value, moved
pub fn set_block_id(&mut self, v: ::std::string::String) {
self.block_id = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_block_id(&mut self) -> &mut ::std::string::String {
&mut self.block_id
}
// Take field
pub fn take_block_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.block_id, ::std::string::String::new())
}
// repeated .RowMeta rows = 2;
@ -353,7 +582,7 @@ impl GridBlock {
}
}
impl ::protobuf::Message for GridBlock {
impl ::protobuf::Message for BlockMeta {
fn is_initialized(&self) -> bool {
for v in &self.rows {
if !v.is_initialized() {
@ -368,7 +597,7 @@ impl ::protobuf::Message for GridBlock {
let (field_number, wire_type) = is.read_tag_unpack()?;
match field_number {
1 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?;
},
2 => {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.rows)?;
@ -385,8 +614,8 @@ impl ::protobuf::Message for GridBlock {
#[allow(unused_variables)]
fn compute_size(&self) -> u32 {
let mut my_size = 0;
if !self.id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.id);
if !self.block_id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.block_id);
}
for value in &self.rows {
let len = value.compute_size();
@ -398,8 +627,8 @@ impl ::protobuf::Message for GridBlock {
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
if !self.id.is_empty() {
os.write_string(1, &self.id)?;
if !self.block_id.is_empty() {
os.write_string(1, &self.block_id)?;
}
for v in &self.rows {
os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
@ -436,8 +665,8 @@ impl ::protobuf::Message for GridBlock {
Self::descriptor_static()
}
fn new() -> GridBlock {
GridBlock::new()
fn new() -> BlockMeta {
BlockMeta::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -445,44 +674,44 @@ impl ::protobuf::Message for GridBlock {
descriptor.get(|| {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"id",
|m: &GridBlock| { &m.id },
|m: &mut GridBlock| { &mut m.id },
"block_id",
|m: &BlockMeta| { &m.block_id },
|m: &mut BlockMeta| { &mut m.block_id },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowMeta>>(
"rows",
|m: &GridBlock| { &m.rows },
|m: &mut GridBlock| { &mut m.rows },
|m: &BlockMeta| { &m.rows },
|m: &mut BlockMeta| { &mut m.rows },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlock>(
"GridBlock",
::protobuf::reflect::MessageDescriptor::new_pb_name::<BlockMeta>(
"BlockMeta",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static GridBlock {
static instance: ::protobuf::rt::LazyV2<GridBlock> = ::protobuf::rt::LazyV2::INIT;
instance.get(GridBlock::new)
fn default_instance() -> &'static BlockMeta {
static instance: ::protobuf::rt::LazyV2<BlockMeta> = ::protobuf::rt::LazyV2::INIT;
instance.get(BlockMeta::new)
}
}
impl ::protobuf::Clear for GridBlock {
impl ::protobuf::Clear for BlockMeta {
fn clear(&mut self) {
self.id.clear();
self.block_id.clear();
self.rows.clear();
self.unknown_fields.clear();
}
}
impl ::std::fmt::Debug for GridBlock {
impl ::std::fmt::Debug for BlockMeta {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for GridBlock {
impl ::protobuf::reflect::ProtobufValue for BlockMeta {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
@ -1997,34 +2226,36 @@ impl ::protobuf::reflect::ProtobufValue for FieldType {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\nmeta.proto\"a\n\x08GridMeta\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
\n\nmeta.proto\"c\n\x08GridMeta\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
\x06gridId\x12\x1e\n\x06fields\x18\x02\x20\x03(\x0b2\x06.FieldR\x06field\
s\x12\x1c\n\x04rows\x18\x03\x20\x03(\x0b2\x08.RowMetaR\x04rows\"9\n\tGri\
dBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x1c\n\x04rows\x18\
\x02\x20\x03(\x0b2\x08.RowMetaR\x04rows\"\xe5\x01\n\x05Field\x12\x0e\n\
\x02id\x18\x01\x20\x01(\tR\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\
\x04name\x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12)\n\nfield_typ\
e\x18\x04\x20\x01(\x0e2\n.FieldTypeR\tfieldType\x12\x16\n\x06frozen\x18\
\x05\x20\x01(\x08R\x06frozen\x12\x1e\n\nvisibility\x18\x06\x20\x01(\x08R\
\nvisibility\x12\x14\n\x05width\x18\x07\x20\x01(\x05R\x05width\x12+\n\
\x0ctype_options\x18\x08\x20\x01(\x0b2\x08.AnyDataR\x0btypeOptions\"-\n\
\rRepeatedField\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05i\
tems\"8\n\x07AnyData\x12\x17\n\x07type_id\x18\x01\x20\x01(\tR\x06typeId\
\x12\x14\n\x05value\x18\x02\x20\x01(\x0cR\x05value\"\xfd\x01\n\x07RowMet\
a\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x17\n\x07grid_id\x18\x02\
\x20\x01(\tR\x06gridId\x12D\n\x10cell_by_field_id\x18\x03\x20\x03(\x0b2\
\x1b.RowMeta.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\
\x04\x20\x01(\x05R\x06height\x12\x1e\n\nvisibility\x18\x05\x20\x01(\x08R\
\nvisibility\x1aK\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\
\x01(\tR\x03key\x12\x1f\n\x05value\x18\x02\x20\x01(\x0b2\t.CellMetaR\x05\
value:\x028\x01\"\x82\x01\n\x08CellMeta\x12\x0e\n\x02id\x18\x01\x20\x01(\
\tR\x02id\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08\
field_id\x18\x03\x20\x01(\tR\x07fieldId\x12\x1c\n\x04data\x18\x04\x20\
\x01(\x0b2\x08.AnyDataR\x04data\x12\x16\n\x06height\x18\x05\x20\x01(\x05\
R\x06height*d\n\tFieldType\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\
\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\
\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06prot\
o3\
s\x12\x1e\n\x06blocks\x18\x03\x20\x03(\x0b2\x06.BlockR\x06blocks\"\\\n\
\x05Block\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12&\n\x0fstart_row_\
index\x18\x02\x20\x01(\x05R\rstartRowIndex\x12\x1b\n\trow_count\x18\x03\
\x20\x01(\x05R\x08rowCount\"D\n\tBlockMeta\x12\x19\n\x08block_id\x18\x01\
\x20\x01(\tR\x07blockId\x12\x1c\n\x04rows\x18\x02\x20\x03(\x0b2\x08.RowM\
etaR\x04rows\"\xe5\x01\n\x05Field\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\
\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04desc\
\x18\x03\x20\x01(\tR\x04desc\x12)\n\nfield_type\x18\x04\x20\x01(\x0e2\n.\
FieldTypeR\tfieldType\x12\x16\n\x06frozen\x18\x05\x20\x01(\x08R\x06froze\
n\x12\x1e\n\nvisibility\x18\x06\x20\x01(\x08R\nvisibility\x12\x14\n\x05w\
idth\x18\x07\x20\x01(\x05R\x05width\x12+\n\x0ctype_options\x18\x08\x20\
\x01(\x0b2\x08.AnyDataR\x0btypeOptions\"-\n\rRepeatedField\x12\x1c\n\x05\
items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"8\n\x07AnyData\x12\x17\
\n\x07type_id\x18\x01\x20\x01(\tR\x06typeId\x12\x14\n\x05value\x18\x02\
\x20\x01(\x0cR\x05value\"\xfd\x01\n\x07RowMeta\x12\x0e\n\x02id\x18\x01\
\x20\x01(\tR\x02id\x12\x17\n\x07grid_id\x18\x02\x20\x01(\tR\x06gridId\
\x12D\n\x10cell_by_field_id\x18\x03\x20\x03(\x0b2\x1b.RowMeta.CellByFiel\
dIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x04\x20\x01(\x05R\x06he\
ight\x12\x1e\n\nvisibility\x18\x05\x20\x01(\x08R\nvisibility\x1aK\n\x12C\
ellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1f\n\
\x05value\x18\x02\x20\x01(\x0b2\t.CellMetaR\x05value:\x028\x01\"\x82\x01\
\n\x08CellMeta\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x15\n\x06ro\
w_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\
\tR\x07fieldId\x12\x1c\n\x04data\x18\x04\x20\x01(\x0b2\x08.AnyDataR\x04d\
ata\x12\x16\n\x06height\x18\x05\x20\x01(\x05R\x06height*d\n\tFieldType\
\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08Date\
Time\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\
\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -3,10 +3,15 @@ syntax = "proto3";
message GridMeta {
string grid_id = 1;
repeated Field fields = 2;
repeated RowMeta rows = 3;
repeated Block blocks = 3;
}
message GridBlock {
message Block {
string id = 1;
int32 start_row_index = 2;
int32 row_count = 3;
}
message BlockMeta {
string block_id = 1;
repeated RowMeta rows = 2;
}
message Field {

View File

@ -7,14 +7,14 @@ fn grid_serde_test() {
let grid = GridMeta {
grid_id,
fields,
rows: vec![],
blocks: vec![],
};
let grid_1_json = serde_json::to_string(&grid).unwrap();
let _: Grid = serde_json::from_str(&grid_1_json).unwrap();
let _: GridMeta = serde_json::from_str(&grid_1_json).unwrap();
assert_eq!(
grid_1_json,
r#"{"id":"1","fields":[{"id":"1","name":"Text Field","desc":"","field_type":"RichText","frozen":false,"visibility":true,"width":150,"type_options":{"type_id":"","value":[]}}],"rows":[]}"#
r#"{"id":"1","fields":[{"id":"1","name":"Text Field","desc":"","field_type":"RichText","frozen":false,"visibility":true,"width":150,"type_options":{"type_id":"","value":[]}}],"blocks":[]}"#
)
}
@ -24,11 +24,11 @@ fn grid_default_serde_test() {
let grid = GridMeta {
grid_id,
fields: vec![],
rows: vec![],
blocks: vec![],
};
let json = serde_json::to_string(&grid).unwrap();
assert_eq!(json, r#"{"id":"1","fields":[],"row_orders":[]}"#)
assert_eq!(json, r#"{"id":"1","fields":[],"blocks":[]}"#)
}
fn create_field(field_id: &str) -> Field {