Browse Source

[rust]: add export interface

appflowy 3 years ago
parent
commit
f9ed746f9a
22 changed files with 846 additions and 59 deletions
  1. 17 0
      app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart
  2. 123 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/export.pb.dart
  3. 26 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/export.pbenum.dart
  4. 42 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/export.pbjson.dart
  5. 9 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/export.pbserver.dart
  6. 1 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/protobuf.dart
  7. 2 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbenum.dart
  8. 2 1
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbjson.dart
  9. 3 0
      rust-lib/flowy-derive/src/derive_cache/derive_cache.rs
  10. 2 4
      rust-lib/flowy-document/src/services/doc/doc_controller.rs
  11. 2 1
      rust-lib/flowy-workspace-infra/src/entities/mod.rs
  12. 57 0
      rust-lib/flowy-workspace-infra/src/entities/share/export.rs
  13. 3 0
      rust-lib/flowy-workspace-infra/src/entities/share/mod.rs
  14. 459 0
      rust-lib/flowy-workspace-infra/src/protobuf/model/export.rs
  15. 3 0
      rust-lib/flowy-workspace-infra/src/protobuf/model/mod.rs
  16. 13 0
      rust-lib/flowy-workspace-infra/src/protobuf/proto/export.proto
  17. 3 0
      rust-lib/flowy-workspace/src/event.rs
  18. 11 0
      rust-lib/flowy-workspace/src/handlers/view_handler.rs
  19. 2 0
      rust-lib/flowy-workspace/src/module.rs
  20. 59 53
      rust-lib/flowy-workspace/src/protobuf/model/event.rs
  21. 1 0
      rust-lib/flowy-workspace/src/protobuf/proto/event.proto
  22. 6 0
      rust-lib/flowy-workspace/src/services/view_controller.rs

+ 17 - 0
app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart

@@ -395,6 +395,23 @@ class WorkspaceEventApplyDocDelta {
     }
 }
 
+class WorkspaceEventExportDocument {
+     ExportRequest request;
+     WorkspaceEventExportDocument(this.request);
+
+    Future<Either<ExportData, WorkspaceError>> send() {
+    final request = FFIRequest.create()
+          ..event = WorkspaceEvent.ExportDocument.toString()
+          ..payload = requestToBytes(this.request);
+
+    return Dispatch.asyncRequest(request)
+        .then((bytesResult) => bytesResult.fold(
+           (okBytes) => left(ExportData.fromBuffer(okBytes)),
+           (errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
+        ));
+    }
+}
+
 class UserEventInitUser {
     UserEventInitUser();
 

+ 123 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/export.pb.dart

@@ -0,0 +1,123 @@
+///
+//  Generated code. Do not modify.
+//  source: export.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:protobuf/protobuf.dart' as $pb;
+
+import 'export.pbenum.dart';
+
+export 'export.pbenum.dart';
+
+class ExportRequest extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ExportRequest', createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
+    ..e<ExportType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'exportType', $pb.PbFieldType.OE, defaultOrMaker: ExportType.Text, valueOf: ExportType.valueOf, enumValues: ExportType.values)
+    ..hasRequiredFields = false
+  ;
+
+  ExportRequest._() : super();
+  factory ExportRequest({
+    $core.String? docId,
+    ExportType? exportType,
+  }) {
+    final _result = create();
+    if (docId != null) {
+      _result.docId = docId;
+    }
+    if (exportType != null) {
+      _result.exportType = exportType;
+    }
+    return _result;
+  }
+  factory ExportRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ExportRequest.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')
+  ExportRequest clone() => ExportRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ExportRequest copyWith(void Function(ExportRequest) updates) => super.copyWith((message) => updates(message as ExportRequest)) as ExportRequest; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static ExportRequest create() => ExportRequest._();
+  ExportRequest createEmptyInstance() => create();
+  static $pb.PbList<ExportRequest> createRepeated() => $pb.PbList<ExportRequest>();
+  @$core.pragma('dart2js:noInline')
+  static ExportRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ExportRequest>(create);
+  static ExportRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get docId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set docId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasDocId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearDocId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  ExportType get exportType => $_getN(1);
+  @$pb.TagNumber(2)
+  set exportType(ExportType v) { setField(2, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasExportType() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearExportType() => clearField(2);
+}
+
+class ExportData extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ExportData', createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
+    ..hasRequiredFields = false
+  ;
+
+  ExportData._() : super();
+  factory ExportData({
+    $core.String? data,
+  }) {
+    final _result = create();
+    if (data != null) {
+      _result.data = data;
+    }
+    return _result;
+  }
+  factory ExportData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ExportData.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')
+  ExportData clone() => ExportData()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ExportData copyWith(void Function(ExportData) updates) => super.copyWith((message) => updates(message as ExportData)) as ExportData; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static ExportData create() => ExportData._();
+  ExportData createEmptyInstance() => create();
+  static $pb.PbList<ExportData> createRepeated() => $pb.PbList<ExportData>();
+  @$core.pragma('dart2js:noInline')
+  static ExportData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ExportData>(create);
+  static ExportData? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get data => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set data($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasData() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearData() => clearField(1);
+}
+

+ 26 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/export.pbenum.dart

@@ -0,0 +1,26 @@
+///
+//  Generated code. Do not modify.
+//  source: export.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
+
+// ignore_for_file: UNDEFINED_SHOWN_NAME
+import 'dart:core' as $core;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class ExportType extends $pb.ProtobufEnum {
+  static const ExportType Text = ExportType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Text');
+  static const ExportType RichText = ExportType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RichText');
+
+  static const $core.List<ExportType> values = <ExportType> [
+    Text,
+    RichText,
+  ];
+
+  static final $core.Map<$core.int, ExportType> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static ExportType? valueOf($core.int value) => _byValue[value];
+
+  const ExportType._($core.int v, $core.String n) : super(v, n);
+}
+

+ 42 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/export.pbjson.dart

@@ -0,0 +1,42 @@
+///
+//  Generated code. Do not modify.
+//  source: export.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 exportTypeDescriptor instead')
+const ExportType$json = const {
+  '1': 'ExportType',
+  '2': const [
+    const {'1': 'Text', '2': 0},
+    const {'1': 'RichText', '2': 1},
+  ],
+};
+
+/// Descriptor for `ExportType`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List exportTypeDescriptor = $convert.base64Decode('CgpFeHBvcnRUeXBlEggKBFRleHQQABIMCghSaWNoVGV4dBAB');
+@$core.Deprecated('Use exportRequestDescriptor instead')
+const ExportRequest$json = const {
+  '1': 'ExportRequest',
+  '2': const [
+    const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
+    const {'1': 'export_type', '3': 2, '4': 1, '5': 14, '6': '.ExportType', '10': 'exportType'},
+  ],
+};
+
+/// Descriptor for `ExportRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List exportRequestDescriptor = $convert.base64Decode('Cg1FeHBvcnRSZXF1ZXN0EhUKBmRvY19pZBgBIAEoCVIFZG9jSWQSLAoLZXhwb3J0X3R5cGUYAiABKA4yCy5FeHBvcnRUeXBlUgpleHBvcnRUeXBl');
+@$core.Deprecated('Use exportDataDescriptor instead')
+const ExportData$json = const {
+  '1': 'ExportData',
+  '2': const [
+    const {'1': 'data', '3': 1, '4': 1, '5': 9, '10': 'data'},
+  ],
+};
+
+/// Descriptor for `ExportData`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List exportDataDescriptor = $convert.base64Decode('CgpFeHBvcnREYXRhEhIKBGRhdGEYASABKAlSBGRhdGE=');

+ 9 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/export.pbserver.dart

@@ -0,0 +1,9 @@
+///
+//  Generated code. Do not modify.
+//  source: export.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 'export.pb.dart';
+

+ 1 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace-infra/protobuf.dart

@@ -12,3 +12,4 @@ export './workspace_create.pb.dart';
 export './app_update.pb.dart';
 export './view_query.pb.dart';
 export './trash_create.pb.dart';
+export './export.pb.dart';

+ 2 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbenum.dart

@@ -34,6 +34,7 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
   static const WorkspaceEvent RestoreAll = WorkspaceEvent._(303, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RestoreAll');
   static const WorkspaceEvent DeleteAll = WorkspaceEvent._(304, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteAll');
   static const WorkspaceEvent ApplyDocDelta = WorkspaceEvent._(400, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ApplyDocDelta');
+  static const WorkspaceEvent ExportDocument = WorkspaceEvent._(500, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ExportDocument');
 
   static const $core.List<WorkspaceEvent> values = <WorkspaceEvent> [
     CreateWorkspace,
@@ -60,6 +61,7 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
     RestoreAll,
     DeleteAll,
     ApplyDocDelta,
+    ExportDocument,
   ];
 
   static final $core.Map<$core.int, WorkspaceEvent> _byValue = $pb.ProtobufEnum.initByValue(values);

+ 2 - 1
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/event.pbjson.dart

@@ -36,8 +36,9 @@ const WorkspaceEvent$json = const {
     const {'1': 'RestoreAll', '2': 303},
     const {'1': 'DeleteAll', '2': 304},
     const {'1': 'ApplyDocDelta', '2': 400},
+    const {'1': 'ExportDocument', '2': 500},
   ],
 };
 
 /// Descriptor for `WorkspaceEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRINCglDcmVhdGVBcHAQZRINCglEZWxldGVBcHAQZhILCgdSZWFkQXBwEGcSDQoJVXBkYXRlQXBwEGgSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsBEg8KCkRlbGV0ZVZpZXcQzAESEgoNRHVwbGljYXRlVmlldxDNARINCghDb3B5TGluaxDOARINCghPcGVuVmlldxDPARIOCglDbG9zZVZpZXcQ0AESDgoJUmVhZFRyYXNoEKwCEhEKDFB1dGJhY2tUcmFzaBCtAhIQCgtEZWxldGVUcmFzaBCuAhIPCgpSZXN0b3JlQWxsEK8CEg4KCURlbGV0ZUFsbBCwAhISCg1BcHBseURvY0RlbHRhEJAD');
+final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRINCglDcmVhdGVBcHAQZRINCglEZWxldGVBcHAQZhILCgdSZWFkQXBwEGcSDQoJVXBkYXRlQXBwEGgSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsBEg8KCkRlbGV0ZVZpZXcQzAESEgoNRHVwbGljYXRlVmlldxDNARINCghDb3B5TGluaxDOARINCghPcGVuVmlldxDPARIOCglDbG9zZVZpZXcQ0AESDgoJUmVhZFRyYXNoEKwCEhEKDFB1dGJhY2tUcmFzaBCtAhIQCgtEZWxldGVUcmFzaBCuAhIPCgpSZXN0b3JlQWxsEK8CEg4KCURlbGV0ZUFsbBCwAhISCg1BcHBseURvY0RlbHRhEJADEhMKDkV4cG9ydERvY3VtZW50EPQD');

+ 3 - 0
rust-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -48,6 +48,8 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "CreateViewParams"
         | "View"
         | "RepeatedView"
+        | "ExportRequest"
+        | "ExportData"
         | "KeyValue"
         | "WorkspaceError"
         | "WsError"
@@ -80,6 +82,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         => TypeCategory::Protobuf,
         "TrashType"
         | "ViewType"
+        | "ExportType"
         | "ErrorCode"
         | "WorkspaceEvent"
         | "WsModule"

+ 2 - 4
rust-lib/flowy-document/src/services/doc/doc_controller.rs

@@ -1,7 +1,3 @@
-use std::sync::Arc;
-
-use bytes::Bytes;
-
 use crate::{
     entities::doc::{Doc, DocDelta, DocIdentifier},
     errors::{DocError, DocResult},
@@ -16,8 +12,10 @@ use crate::{
         ws::WsDocumentManager,
     },
 };
+use bytes::Bytes;
 use flowy_database::ConnectionPool;
 use flowy_infra::future::{wrap_future, FnFuture, ResultFuture};
+use std::sync::Arc;
 
 use tokio::time::{interval, Duration};
 

+ 2 - 1
rust-lib/flowy-workspace-infra/src/entities/mod.rs

@@ -1,8 +1,9 @@
 pub mod app;
+pub mod share;
 pub mod trash;
 pub mod view;
 pub mod workspace;
 
 pub mod prelude {
-    pub use crate::entities::{app::*, trash::*, view::*, workspace::*};
+    pub use crate::entities::{app::*, share::*, trash::*, view::*, workspace::*};
 }

+ 57 - 0
rust-lib/flowy-workspace-infra/src/entities/share/export.rs

@@ -0,0 +1,57 @@
+use crate::errors::ErrorCode;
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+use std::convert::TryInto;
+
+#[derive(PartialEq, Debug, ProtoBuf_Enum, Clone)]
+pub enum ExportType {
+    Text     = 0,
+    RichText = 1,
+}
+
+impl std::default::Default for ExportType {
+    fn default() -> Self { ExportType::Text }
+}
+
+impl std::convert::From<i32> for ExportType {
+    fn from(val: i32) -> Self {
+        match val {
+            0 => ExportType::Text,
+            1 => ExportType::RichText,
+            _ => {
+                log::error!("Invalid export type: {}", val);
+                ViewType::Text
+            },
+        }
+    }
+}
+
+#[derive(Default, ProtoBuf)]
+pub struct ExportRequest {
+    #[pb(index = 1)]
+    pub doc_id: String,
+
+    #[pb(index = 2)]
+    pub export_type: ExportType,
+}
+
+#[derive(Default)]
+pub struct ExportParams {
+    pub doc_id: String,
+    pub export_type: ExportType,
+}
+
+impl TryInto<ExportParams> for ExportRequest {
+    type Error = ErrorCode;
+    fn try_into(self) -> Result<ExportParams, Self::Error> {
+        Ok(ExportParams {
+            doc_id: self.doc_id,
+            export_type: self.export_type,
+        })
+    }
+}
+
+#[derive(Default, ProtoBuf)]
+pub struct ExportData {
+    #[pb(index = 1)]
+    pub data: String,
+}

+ 3 - 0
rust-lib/flowy-workspace-infra/src/entities/share/mod.rs

@@ -0,0 +1,3 @@
+mod export;
+
+pub use export::*;

+ 459 - 0
rust-lib/flowy-workspace-infra/src/protobuf/model/export.rs

@@ -0,0 +1,459 @@
+// This file is generated by rust-protobuf 2.22.1. Do not edit
+// @generated
+
+// https://github.com/rust-lang/rust-clippy/issues/702
+#![allow(unknown_lints)]
+#![allow(clippy::all)]
+
+#![allow(unused_attributes)]
+#![cfg_attr(rustfmt, rustfmt::skip)]
+
+#![allow(box_pointers)]
+#![allow(dead_code)]
+#![allow(missing_docs)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(non_upper_case_globals)]
+#![allow(trivial_casts)]
+#![allow(unused_imports)]
+#![allow(unused_results)]
+//! Generated file from `export.proto`
+
+/// Generated files are compatible only with the same version
+/// of protobuf runtime.
+// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
+
+#[derive(PartialEq,Clone,Default)]
+pub struct ExportRequest {
+    // message fields
+    pub doc_id: ::std::string::String,
+    pub export_type: ExportType,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a ExportRequest {
+    fn default() -> &'a ExportRequest {
+        <ExportRequest as ::protobuf::Message>::default_instance()
+    }
+}
+
+impl ExportRequest {
+    pub fn new() -> ExportRequest {
+        ::std::default::Default::default()
+    }
+
+    // string doc_id = 1;
+
+
+    pub fn get_doc_id(&self) -> &str {
+        &self.doc_id
+    }
+    pub fn clear_doc_id(&mut self) {
+        self.doc_id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_doc_id(&mut self, v: ::std::string::String) {
+        self.doc_id = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_doc_id(&mut self) -> &mut ::std::string::String {
+        &mut self.doc_id
+    }
+
+    // Take field
+    pub fn take_doc_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
+    }
+
+    // .ExportType export_type = 2;
+
+
+    pub fn get_export_type(&self) -> ExportType {
+        self.export_type
+    }
+    pub fn clear_export_type(&mut self) {
+        self.export_type = ExportType::Text;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_export_type(&mut self, v: ExportType) {
+        self.export_type = v;
+    }
+}
+
+impl ::protobuf::Message for ExportRequest {
+    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.doc_id)?;
+                },
+                2 => {
+                    ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.export_type, 2, &mut self.unknown_fields)?
+                },
+                _ => {
+                    ::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.doc_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.doc_id);
+        }
+        if self.export_type != ExportType::Text {
+            my_size += ::protobuf::rt::enum_size(2, self.export_type);
+        }
+        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.doc_id.is_empty() {
+            os.write_string(1, &self.doc_id)?;
+        }
+        if self.export_type != ExportType::Text {
+            os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.export_type))?;
+        }
+        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() -> ExportRequest {
+        ExportRequest::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>(
+                "doc_id",
+                |m: &ExportRequest| { &m.doc_id },
+                |m: &mut ExportRequest| { &mut m.doc_id },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ExportType>>(
+                "export_type",
+                |m: &ExportRequest| { &m.export_type },
+                |m: &mut ExportRequest| { &mut m.export_type },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<ExportRequest>(
+                "ExportRequest",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static ExportRequest {
+        static instance: ::protobuf::rt::LazyV2<ExportRequest> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(ExportRequest::new)
+    }
+}
+
+impl ::protobuf::Clear for ExportRequest {
+    fn clear(&mut self) {
+        self.doc_id.clear();
+        self.export_type = ExportType::Text;
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for ExportRequest {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for ExportRequest {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
+#[derive(PartialEq,Clone,Default)]
+pub struct ExportData {
+    // message fields
+    pub data: ::std::string::String,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a ExportData {
+    fn default() -> &'a ExportData {
+        <ExportData as ::protobuf::Message>::default_instance()
+    }
+}
+
+impl ExportData {
+    pub fn new() -> ExportData {
+        ::std::default::Default::default()
+    }
+
+    // string data = 1;
+
+
+    pub fn get_data(&self) -> &str {
+        &self.data
+    }
+    pub fn clear_data(&mut self) {
+        self.data.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_data(&mut self, v: ::std::string::String) {
+        self.data = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_data(&mut self) -> &mut ::std::string::String {
+        &mut self.data
+    }
+
+    // Take field
+    pub fn take_data(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.data, ::std::string::String::new())
+    }
+}
+
+impl ::protobuf::Message for ExportData {
+    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.data)?;
+                },
+                _ => {
+                    ::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.data.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.data);
+        }
+        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.data.is_empty() {
+            os.write_string(1, &self.data)?;
+        }
+        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() -> ExportData {
+        ExportData::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>(
+                "data",
+                |m: &ExportData| { &m.data },
+                |m: &mut ExportData| { &mut m.data },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<ExportData>(
+                "ExportData",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static ExportData {
+        static instance: ::protobuf::rt::LazyV2<ExportData> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(ExportData::new)
+    }
+}
+
+impl ::protobuf::Clear for ExportData {
+    fn clear(&mut self) {
+        self.data.clear();
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for ExportData {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for ExportData {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
+#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+pub enum ExportType {
+    Text = 0,
+    RichText = 1,
+}
+
+impl ::protobuf::ProtobufEnum for ExportType {
+    fn value(&self) -> i32 {
+        *self as i32
+    }
+
+    fn from_i32(value: i32) -> ::std::option::Option<ExportType> {
+        match value {
+            0 => ::std::option::Option::Some(ExportType::Text),
+            1 => ::std::option::Option::Some(ExportType::RichText),
+            _ => ::std::option::Option::None
+        }
+    }
+
+    fn values() -> &'static [Self] {
+        static values: &'static [ExportType] = &[
+            ExportType::Text,
+            ExportType::RichText,
+        ];
+        values
+    }
+
+    fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
+        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
+        descriptor.get(|| {
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<ExportType>("ExportType", file_descriptor_proto())
+        })
+    }
+}
+
+impl ::std::marker::Copy for ExportType {
+}
+
+impl ::std::default::Default for ExportType {
+    fn default() -> Self {
+        ExportType::Text
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for ExportType {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
+    }
+}
+
+static file_descriptor_proto_data: &'static [u8] = b"\
+    \n\x0cexport.proto\"T\n\rExportRequest\x12\x15\n\x06doc_id\x18\x01\x20\
+    \x01(\tR\x05docId\x12,\n\x0bexport_type\x18\x02\x20\x01(\x0e2\x0b.Export\
+    TypeR\nexportType\"\x20\n\nExportData\x12\x12\n\x04data\x18\x01\x20\x01(\
+    \tR\x04data*$\n\nExportType\x12\x08\n\x04Text\x10\0\x12\x0c\n\x08RichTex\
+    t\x10\x01J\xd1\x02\n\x06\x12\x04\0\0\x0c\x01\n\x08\n\x01\x0c\x12\x03\0\0\
+    \x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\
+    \x02\x08\x15\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x16\n\x0c\n\x05\x04\
+    \0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\
+    \x0b\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x14\x15\n\x0b\n\x04\x04\
+    \0\x02\x01\x12\x03\x04\x04\x1f\n\x0c\n\x05\x04\0\x02\x01\x06\x12\x03\x04\
+    \x04\x0e\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0f\x1a\n\x0c\n\x05\
+    \x04\0\x02\x01\x03\x12\x03\x04\x1d\x1e\n\n\n\x02\x04\x01\x12\x04\x06\0\
+    \x08\x01\n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\x12\n\x0b\n\x04\x04\x01\
+    \x02\0\x12\x03\x07\x04\x14\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\
+    \n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x07\x0b\x0f\n\x0c\n\x05\x04\x01\
+    \x02\0\x03\x12\x03\x07\x12\x13\n\n\n\x02\x05\0\x12\x04\t\0\x0c\x01\n\n\n\
+    \x03\x05\0\x01\x12\x03\t\x05\x0f\n\x0b\n\x04\x05\0\x02\0\x12\x03\n\x04\r\
+    \n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\n\x04\x08\n\x0c\n\x05\x05\0\x02\0\
+    \x02\x12\x03\n\x0b\x0c\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x0b\x04\x11\n\
+    \x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x0b\x04\x0c\n\x0c\n\x05\x05\0\x02\
+    \x01\x02\x12\x03\x0b\x0f\x10b\x06proto3\
+";
+
+static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
+
+fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto {
+    ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
+}
+
+pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
+    file_descriptor_proto_lazy.get(|| {
+        parse_descriptor_proto()
+    })
+}

+ 3 - 0
rust-lib/flowy-workspace-infra/src/protobuf/model/mod.rs

@@ -38,3 +38,6 @@ pub use view_query::*;
 
 mod trash_create; 
 pub use trash_create::*; 
+
+mod export; 
+pub use export::*; 

+ 13 - 0
rust-lib/flowy-workspace-infra/src/protobuf/proto/export.proto

@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+message ExportRequest {
+    string doc_id = 1;
+    ExportType export_type = 2;
+}
+message ExportData {
+    string data = 1;
+}
+enum ExportType {
+    Text = 0;
+    RichText = 1;
+}

+ 3 - 0
rust-lib/flowy-workspace/src/event.rs

@@ -75,4 +75,7 @@ pub enum WorkspaceEvent {
 
     #[event(input = "DocDelta", output = "DocDelta")]
     ApplyDocDelta     = 400,
+
+    #[event(input = "ExportRequest", output = "ExportData")]
+    ExportDocument    = 500,
 }

+ 11 - 0
rust-lib/flowy-workspace/src/handlers/view_handler.rs

@@ -17,6 +17,7 @@ use crate::{
 };
 use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
 use flowy_document::entities::doc::DocDelta;
+use flowy_workspace_infra::entities::share::{ExportParams, ExportRequest};
 use std::{convert::TryInto, sync::Arc};
 
 pub(crate) async fn create_view_handler(
@@ -106,3 +107,13 @@ pub(crate) async fn duplicate_view_handler(
     let _ = controller.duplicate_view(params.into()).await?;
     Ok(())
 }
+
+#[tracing::instrument(skip(data, controller), err)]
+pub(crate) async fn export_handler(
+    data: Data<QueryViewRequest>,
+    controller: Unit<Arc<ViewController>>,
+) -> Result<(), WorkspaceError> {
+    let params: ExportParams = data.into_inner().try_into()?;
+    let _ = controller.export_doc(params.into()).await?;
+    Ok(())
+}

+ 2 - 0
rust-lib/flowy-workspace/src/module.rs

@@ -102,5 +102,7 @@ pub fn create(workspace: Arc<WorkspaceController>) -> Module {
         .event(WorkspaceEvent::RestoreAll, restore_all_handler)
         .event(WorkspaceEvent::DeleteAll, delete_all_handler);
 
+    module = module.event(WorkspaceEvent::ExportDocument, export_handler);
+
     module
 }

+ 59 - 53
rust-lib/flowy-workspace/src/protobuf/model/event.rs

@@ -49,6 +49,7 @@ pub enum WorkspaceEvent {
     RestoreAll = 303,
     DeleteAll = 304,
     ApplyDocDelta = 400,
+    ExportDocument = 500,
 }
 
 impl ::protobuf::ProtobufEnum for WorkspaceEvent {
@@ -82,6 +83,7 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
             303 => ::std::option::Option::Some(WorkspaceEvent::RestoreAll),
             304 => ::std::option::Option::Some(WorkspaceEvent::DeleteAll),
             400 => ::std::option::Option::Some(WorkspaceEvent::ApplyDocDelta),
+            500 => ::std::option::Option::Some(WorkspaceEvent::ExportDocument),
             _ => ::std::option::Option::None
         }
     }
@@ -112,6 +114,7 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
             WorkspaceEvent::RestoreAll,
             WorkspaceEvent::DeleteAll,
             WorkspaceEvent::ApplyDocDelta,
+            WorkspaceEvent::ExportDocument,
         ];
         values
     }
@@ -140,7 +143,7 @@ impl ::protobuf::reflect::ProtobufValue for WorkspaceEvent {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0bevent.proto*\xb6\x03\n\x0eWorkspaceEvent\x12\x13\n\x0fCreateWorksp\
+    \n\x0bevent.proto*\xcb\x03\n\x0eWorkspaceEvent\x12\x13\n\x0fCreateWorksp\
     ace\x10\0\x12\x14\n\x10ReadCurWorkspace\x10\x01\x12\x12\n\x0eReadWorkspa\
     ces\x10\x02\x12\x13\n\x0fDeleteWorkspace\x10\x03\x12\x11\n\rOpenWorkspac\
     e\x10\x04\x12\x15\n\x11ReadWorkspaceApps\x10\x05\x12\r\n\tCreateApp\x10e\
@@ -151,58 +154,61 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x08OpenView\x10\xcf\x01\x12\x0e\n\tCloseView\x10\xd0\x01\x12\x0e\n\tR\
     eadTrash\x10\xac\x02\x12\x11\n\x0cPutbackTrash\x10\xad\x02\x12\x10\n\x0b\
     DeleteTrash\x10\xae\x02\x12\x0f\n\nRestoreAll\x10\xaf\x02\x12\x0e\n\tDel\
-    eteAll\x10\xb0\x02\x12\x12\n\rApplyDocDelta\x10\x90\x03J\x82\x08\n\x06\
-    \x12\x04\0\0\x1b\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\
-    \x04\x02\0\x1b\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x13\n\x0b\n\x04\
-    \x05\0\x02\0\x12\x03\x03\x04\x18\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\
-    \x04\x13\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x16\x17\n\x0b\n\x04\x05\
-    \0\x02\x01\x12\x03\x04\x04\x19\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\
-    \x04\x14\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\x17\x18\n\x0b\n\x04\
-    \x05\0\x02\x02\x12\x03\x05\x04\x17\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\
-    \x05\x04\x12\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\x15\x16\n\x0b\n\
-    \x04\x05\0\x02\x03\x12\x03\x06\x04\x18\n\x0c\n\x05\x05\0\x02\x03\x01\x12\
-    \x03\x06\x04\x13\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\x06\x16\x17\n\x0b\
-    \n\x04\x05\0\x02\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\x05\0\x02\x04\x01\
-    \x12\x03\x07\x04\x11\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x07\x14\x15\n\
-    \x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x1a\n\x0c\n\x05\x05\0\x02\x05\
-    \x01\x12\x03\x08\x04\x15\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x08\x18\
-    \x19\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x14\n\x0c\n\x05\x05\0\x02\
-    \x06\x01\x12\x03\t\x04\r\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\t\x10\x13\
-    \n\x0b\n\x04\x05\0\x02\x07\x12\x03\n\x04\x14\n\x0c\n\x05\x05\0\x02\x07\
-    \x01\x12\x03\n\x04\r\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\n\x10\x13\n\
-    \x0b\n\x04\x05\0\x02\x08\x12\x03\x0b\x04\x12\n\x0c\n\x05\x05\0\x02\x08\
-    \x01\x12\x03\x0b\x04\x0b\n\x0c\n\x05\x05\0\x02\x08\x02\x12\x03\x0b\x0e\
-    \x11\n\x0b\n\x04\x05\0\x02\t\x12\x03\x0c\x04\x14\n\x0c\n\x05\x05\0\x02\t\
-    \x01\x12\x03\x0c\x04\r\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\x0c\x10\x13\n\
-    \x0b\n\x04\x05\0\x02\n\x12\x03\r\x04\x15\n\x0c\n\x05\x05\0\x02\n\x01\x12\
-    \x03\r\x04\x0e\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\r\x11\x14\n\x0b\n\x04\
-    \x05\0\x02\x0b\x12\x03\x0e\x04\x13\n\x0c\n\x05\x05\0\x02\x0b\x01\x12\x03\
-    \x0e\x04\x0c\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\x0e\x0f\x12\n\x0b\n\
-    \x04\x05\0\x02\x0c\x12\x03\x0f\x04\x15\n\x0c\n\x05\x05\0\x02\x0c\x01\x12\
-    \x03\x0f\x04\x0e\n\x0c\n\x05\x05\0\x02\x0c\x02\x12\x03\x0f\x11\x14\n\x0b\
-    \n\x04\x05\0\x02\r\x12\x03\x10\x04\x15\n\x0c\n\x05\x05\0\x02\r\x01\x12\
-    \x03\x10\x04\x0e\n\x0c\n\x05\x05\0\x02\r\x02\x12\x03\x10\x11\x14\n\x0b\n\
-    \x04\x05\0\x02\x0e\x12\x03\x11\x04\x18\n\x0c\n\x05\x05\0\x02\x0e\x01\x12\
-    \x03\x11\x04\x11\n\x0c\n\x05\x05\0\x02\x0e\x02\x12\x03\x11\x14\x17\n\x0b\
-    \n\x04\x05\0\x02\x0f\x12\x03\x12\x04\x13\n\x0c\n\x05\x05\0\x02\x0f\x01\
-    \x12\x03\x12\x04\x0c\n\x0c\n\x05\x05\0\x02\x0f\x02\x12\x03\x12\x0f\x12\n\
-    \x0b\n\x04\x05\0\x02\x10\x12\x03\x13\x04\x13\n\x0c\n\x05\x05\0\x02\x10\
-    \x01\x12\x03\x13\x04\x0c\n\x0c\n\x05\x05\0\x02\x10\x02\x12\x03\x13\x0f\
-    \x12\n\x0b\n\x04\x05\0\x02\x11\x12\x03\x14\x04\x14\n\x0c\n\x05\x05\0\x02\
-    \x11\x01\x12\x03\x14\x04\r\n\x0c\n\x05\x05\0\x02\x11\x02\x12\x03\x14\x10\
-    \x13\n\x0b\n\x04\x05\0\x02\x12\x12\x03\x15\x04\x14\n\x0c\n\x05\x05\0\x02\
-    \x12\x01\x12\x03\x15\x04\r\n\x0c\n\x05\x05\0\x02\x12\x02\x12\x03\x15\x10\
-    \x13\n\x0b\n\x04\x05\0\x02\x13\x12\x03\x16\x04\x17\n\x0c\n\x05\x05\0\x02\
-    \x13\x01\x12\x03\x16\x04\x10\n\x0c\n\x05\x05\0\x02\x13\x02\x12\x03\x16\
-    \x13\x16\n\x0b\n\x04\x05\0\x02\x14\x12\x03\x17\x04\x16\n\x0c\n\x05\x05\0\
-    \x02\x14\x01\x12\x03\x17\x04\x0f\n\x0c\n\x05\x05\0\x02\x14\x02\x12\x03\
-    \x17\x12\x15\n\x0b\n\x04\x05\0\x02\x15\x12\x03\x18\x04\x15\n\x0c\n\x05\
-    \x05\0\x02\x15\x01\x12\x03\x18\x04\x0e\n\x0c\n\x05\x05\0\x02\x15\x02\x12\
-    \x03\x18\x11\x14\n\x0b\n\x04\x05\0\x02\x16\x12\x03\x19\x04\x14\n\x0c\n\
-    \x05\x05\0\x02\x16\x01\x12\x03\x19\x04\r\n\x0c\n\x05\x05\0\x02\x16\x02\
-    \x12\x03\x19\x10\x13\n\x0b\n\x04\x05\0\x02\x17\x12\x03\x1a\x04\x18\n\x0c\
-    \n\x05\x05\0\x02\x17\x01\x12\x03\x1a\x04\x11\n\x0c\n\x05\x05\0\x02\x17\
-    \x02\x12\x03\x1a\x14\x17b\x06proto3\
+    eteAll\x10\xb0\x02\x12\x12\n\rApplyDocDelta\x10\x90\x03\x12\x13\n\x0eExp\
+    ortDocument\x10\xf4\x03J\xab\x08\n\x06\x12\x04\0\0\x1c\x01\n\x08\n\x01\
+    \x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\x1c\x01\n\n\n\x03\x05\
+    \0\x01\x12\x03\x02\x05\x13\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x18\n\
+    \x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\x04\x13\n\x0c\n\x05\x05\0\x02\0\
+    \x02\x12\x03\x03\x16\x17\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x19\n\
+    \x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x05\0\x02\
+    \x01\x02\x12\x03\x04\x17\x18\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\
+    \x17\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x05\x04\x12\n\x0c\n\x05\x05\0\
+    \x02\x02\x02\x12\x03\x05\x15\x16\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\
+    \x04\x18\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x13\n\x0c\n\x05\
+    \x05\0\x02\x03\x02\x12\x03\x06\x16\x17\n\x0b\n\x04\x05\0\x02\x04\x12\x03\
+    \x07\x04\x16\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x11\n\x0c\n\
+    \x05\x05\0\x02\x04\x02\x12\x03\x07\x14\x15\n\x0b\n\x04\x05\0\x02\x05\x12\
+    \x03\x08\x04\x1a\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\x08\x04\x15\n\x0c\
+    \n\x05\x05\0\x02\x05\x02\x12\x03\x08\x18\x19\n\x0b\n\x04\x05\0\x02\x06\
+    \x12\x03\t\x04\x14\n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\t\x04\r\n\x0c\n\
+    \x05\x05\0\x02\x06\x02\x12\x03\t\x10\x13\n\x0b\n\x04\x05\0\x02\x07\x12\
+    \x03\n\x04\x14\n\x0c\n\x05\x05\0\x02\x07\x01\x12\x03\n\x04\r\n\x0c\n\x05\
+    \x05\0\x02\x07\x02\x12\x03\n\x10\x13\n\x0b\n\x04\x05\0\x02\x08\x12\x03\
+    \x0b\x04\x12\n\x0c\n\x05\x05\0\x02\x08\x01\x12\x03\x0b\x04\x0b\n\x0c\n\
+    \x05\x05\0\x02\x08\x02\x12\x03\x0b\x0e\x11\n\x0b\n\x04\x05\0\x02\t\x12\
+    \x03\x0c\x04\x14\n\x0c\n\x05\x05\0\x02\t\x01\x12\x03\x0c\x04\r\n\x0c\n\
+    \x05\x05\0\x02\t\x02\x12\x03\x0c\x10\x13\n\x0b\n\x04\x05\0\x02\n\x12\x03\
+    \r\x04\x15\n\x0c\n\x05\x05\0\x02\n\x01\x12\x03\r\x04\x0e\n\x0c\n\x05\x05\
+    \0\x02\n\x02\x12\x03\r\x11\x14\n\x0b\n\x04\x05\0\x02\x0b\x12\x03\x0e\x04\
+    \x13\n\x0c\n\x05\x05\0\x02\x0b\x01\x12\x03\x0e\x04\x0c\n\x0c\n\x05\x05\0\
+    \x02\x0b\x02\x12\x03\x0e\x0f\x12\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x0f\
+    \x04\x15\n\x0c\n\x05\x05\0\x02\x0c\x01\x12\x03\x0f\x04\x0e\n\x0c\n\x05\
+    \x05\0\x02\x0c\x02\x12\x03\x0f\x11\x14\n\x0b\n\x04\x05\0\x02\r\x12\x03\
+    \x10\x04\x15\n\x0c\n\x05\x05\0\x02\r\x01\x12\x03\x10\x04\x0e\n\x0c\n\x05\
+    \x05\0\x02\r\x02\x12\x03\x10\x11\x14\n\x0b\n\x04\x05\0\x02\x0e\x12\x03\
+    \x11\x04\x18\n\x0c\n\x05\x05\0\x02\x0e\x01\x12\x03\x11\x04\x11\n\x0c\n\
+    \x05\x05\0\x02\x0e\x02\x12\x03\x11\x14\x17\n\x0b\n\x04\x05\0\x02\x0f\x12\
+    \x03\x12\x04\x13\n\x0c\n\x05\x05\0\x02\x0f\x01\x12\x03\x12\x04\x0c\n\x0c\
+    \n\x05\x05\0\x02\x0f\x02\x12\x03\x12\x0f\x12\n\x0b\n\x04\x05\0\x02\x10\
+    \x12\x03\x13\x04\x13\n\x0c\n\x05\x05\0\x02\x10\x01\x12\x03\x13\x04\x0c\n\
+    \x0c\n\x05\x05\0\x02\x10\x02\x12\x03\x13\x0f\x12\n\x0b\n\x04\x05\0\x02\
+    \x11\x12\x03\x14\x04\x14\n\x0c\n\x05\x05\0\x02\x11\x01\x12\x03\x14\x04\r\
+    \n\x0c\n\x05\x05\0\x02\x11\x02\x12\x03\x14\x10\x13\n\x0b\n\x04\x05\0\x02\
+    \x12\x12\x03\x15\x04\x14\n\x0c\n\x05\x05\0\x02\x12\x01\x12\x03\x15\x04\r\
+    \n\x0c\n\x05\x05\0\x02\x12\x02\x12\x03\x15\x10\x13\n\x0b\n\x04\x05\0\x02\
+    \x13\x12\x03\x16\x04\x17\n\x0c\n\x05\x05\0\x02\x13\x01\x12\x03\x16\x04\
+    \x10\n\x0c\n\x05\x05\0\x02\x13\x02\x12\x03\x16\x13\x16\n\x0b\n\x04\x05\0\
+    \x02\x14\x12\x03\x17\x04\x16\n\x0c\n\x05\x05\0\x02\x14\x01\x12\x03\x17\
+    \x04\x0f\n\x0c\n\x05\x05\0\x02\x14\x02\x12\x03\x17\x12\x15\n\x0b\n\x04\
+    \x05\0\x02\x15\x12\x03\x18\x04\x15\n\x0c\n\x05\x05\0\x02\x15\x01\x12\x03\
+    \x18\x04\x0e\n\x0c\n\x05\x05\0\x02\x15\x02\x12\x03\x18\x11\x14\n\x0b\n\
+    \x04\x05\0\x02\x16\x12\x03\x19\x04\x14\n\x0c\n\x05\x05\0\x02\x16\x01\x12\
+    \x03\x19\x04\r\n\x0c\n\x05\x05\0\x02\x16\x02\x12\x03\x19\x10\x13\n\x0b\n\
+    \x04\x05\0\x02\x17\x12\x03\x1a\x04\x18\n\x0c\n\x05\x05\0\x02\x17\x01\x12\
+    \x03\x1a\x04\x11\n\x0c\n\x05\x05\0\x02\x17\x02\x12\x03\x1a\x14\x17\n\x0b\
+    \n\x04\x05\0\x02\x18\x12\x03\x1b\x04\x19\n\x0c\n\x05\x05\0\x02\x18\x01\
+    \x12\x03\x1b\x04\x12\n\x0c\n\x05\x05\0\x02\x18\x02\x12\x03\x1b\x15\x18b\
+    \x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 1 - 0
rust-lib/flowy-workspace/src/protobuf/proto/event.proto

@@ -25,4 +25,5 @@ enum WorkspaceEvent {
     RestoreAll = 303;
     DeleteAll = 304;
     ApplyDocDelta = 400;
+    ExportDocument = 500;
 }

+ 6 - 0
rust-lib/flowy-workspace/src/services/view_controller.rs

@@ -19,6 +19,7 @@ use crate::{
     services::{server::Server, TrashCan, TrashEvent},
     sql_tables::view::{ViewTable, ViewTableChangeset, ViewTableSql},
 };
+use flowy_workspace_infra::entities::share::{ExportData, ExportParams, ExportRequest};
 
 pub(crate) struct ViewController {
     user: Arc<dyn WorkspaceUser>,
@@ -138,6 +139,11 @@ impl ViewController {
         Ok(())
     }
 
+    #[tracing::instrument(level = "debug", skip(self, params), err)]
+    pub(crate) async fn export_doc(&self, params: ExportParams) -> Result<ExportData, WorkspaceError> {
+        unimplemented!()
+    }
+
     // belong_to_id will be the app_id or view_id.
     #[tracing::instrument(level = "debug", skip(self), err)]
     pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, WorkspaceError> {