Feat/tauri (#1716)

* feat: support tauri desktop

* chore: support call flowy sdk command

* chore: switch to svelte

* chore: gen js protobuf

* chore: import js protobuf

* chore: call flowy sdk handler

* chore: update scipts

* chore: create index.ts

* chore: track files

* chore: gen ts event

* chore: replace application icon

* chore: migrate to react

* chore: fix wanrings

Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
Nathan.fooo
2023-01-17 16:27:17 +08:00
committed by GitHub
parent ba653ff463
commit f64346c955
94 changed files with 6749 additions and 99 deletions

View File

@ -1965,6 +1965,7 @@ dependencies = [
"protobuf",
"serde",
"serde_json",
"serde_repr",
"serde_with",
"thread-id",
"tokio",

View File

@ -26,7 +26,8 @@ pub extern "C" fn init_sdk(path: *mut c_char) -> i64 {
let path: &str = c_str.to_str().unwrap();
let server_config = get_client_server_configuration().unwrap();
let config = FlowySDKConfig::new(path, "appflowy".to_string(), server_config).log_filter("info");
let log_crates = vec!["flowy-ffi".to_string()];
let config = FlowySDKConfig::new(path, "appflowy".to_string(), server_config).log_filter("info", log_crates);
*FLOWY_SDK.write() = Some(FlowySDK::new(config));
0

View File

@ -33,7 +33,6 @@ impl std::convert::From<AFPluginEventResponse> for FFIResponse {
let code = match resp.status_code {
StatusCode::Ok => FFIStatusCode::Ok,
StatusCode::Err => FFIStatusCode::Err,
StatusCode::Internal => FFIStatusCode::Internal,
};
// let msg = match resp.error {

View File

@ -46,4 +46,6 @@ proto_gen = [
"protoc-bin-vendored",
]
dart_event = ["walkdir", "tera", "syn"]
dart = ["proto_gen", "dart_event"]
dart = ["proto_gen", "dart_event"]
ts_event = ["walkdir", "tera", "syn"]
ts = ["proto_gen", "ts_event"]

View File

@ -1,5 +1,5 @@
#![allow(clippy::module_inception)]
mod ast;
pub(crate) mod ast;
mod dart_event;
mod event_template;

View File

@ -4,10 +4,13 @@ pub mod protobuf_file;
#[cfg(feature = "dart_event")]
pub mod dart_event;
#[cfg(any(feature = "proto_gen", feature = "dart_event"))]
#[cfg(feature = "ts_event")]
pub mod ts_event;
#[cfg(any(feature = "proto_gen", feature = "dart_event", feature = "ts_event"))]
mod flowy_toml;
#[cfg(any(feature = "proto_gen", feature = "dart_event"))]
#[cfg(any(feature = "proto_gen", feature = "dart_event", feature = "ts_event"))]
pub mod util;
#[derive(serde::Serialize, serde::Deserialize)]

View File

@ -58,6 +58,15 @@ pub fn gen(crate_name: &str) {
&protoc_bin_path,
);
#[cfg(feature = "ts")]
generate_ts_protobuf_files(
crate_name,
&proto_file_output_path,
&proto_file_paths,
&file_names,
&protoc_bin_path,
);
// 3. generate the protobuf files(Rust)
generate_rust_protobuf_files(
&protoc_bin_path,
@ -83,6 +92,64 @@ fn generate_rust_protobuf_files(
.expect("Running rust protoc failed.");
}
#[cfg(feature = "ts")]
fn generate_ts_protobuf_files(
name: &str,
proto_file_output_path: &str,
paths: &[String],
file_names: &Vec<String>,
protoc_bin_path: &Path,
) {
if std::env::var("TAURI_PROTOBUF_PATH").is_err() {
eprintln!("TAURI_PROTOBUF_PATH was not set, skip generate ts pb");
return;
}
let mut output = PathBuf::new();
output.push(std::env::var("CARGO_MAKE_WORKING_DIRECTORY").unwrap());
output.push(std::env::var("TAURI_PROTOBUF_PATH").unwrap());
output.push("classes");
output.push(name);
if !output.as_path().exists() {
std::fs::create_dir_all(&output).unwrap();
}
let protoc_bin_path = protoc_bin_path.to_str().unwrap().to_owned();
paths.iter().for_each(|path| {
let result = cmd_lib::run_cmd! {
${protoc_bin_path} --ts_out=${output} --proto_path=${proto_file_output_path} ${path}
};
if result.is_err() {
panic!("Generate dart pb file failed with: {}, {:?}", path, result)
};
});
let ts_index = path_string_with_component(&output, vec!["index.ts"]);
match std::fs::OpenOptions::new()
.create(true)
.write(true)
.append(false)
.truncate(true)
.open(&ts_index)
{
Ok(ref mut file) => {
let mut export = String::new();
export.push_str("// Auto-generated, do not edit \n");
for file_name in file_names {
let c = format!("export * from \"./{}\";\n", file_name);
export.push_str(c.as_ref());
}
file.write_all(export.as_bytes()).unwrap();
File::flush(file).unwrap();
}
Err(err) => {
panic!("Failed to open file: {}", err);
}
}
}
#[cfg(feature = "dart")]
fn generate_dart_protobuf_files(
name: &str,

View File

@ -0,0 +1,65 @@
use crate::util::get_tera;
use tera::Context;
pub struct EventTemplate {
tera_context: Context,
}
pub struct EventRenderContext {
pub input_deserializer: Option<String>,
pub output_deserializer: Option<String>,
pub error_deserializer: String,
pub event: String,
pub event_ty: String,
pub prefix: String,
}
#[allow(dead_code)]
impl EventTemplate {
pub fn new() -> Self {
EventTemplate {
tera_context: Context::new(),
}
}
pub fn render(&mut self, ctx: EventRenderContext, index: usize) -> Option<String> {
self.tera_context.insert("index", &index);
let event_func_name = format!("{}{}", ctx.event_ty, ctx.event);
self.tera_context.insert("event_func_name", &event_func_name);
self.tera_context
.insert("event_name", &format!("{}.{}", ctx.prefix, ctx.event_ty));
self.tera_context.insert("event", &ctx.event);
self.tera_context.insert("has_input", &ctx.input_deserializer.is_some());
match ctx.input_deserializer {
None => {}
Some(ref input) => self
.tera_context
.insert("input_deserializer", &format!("{}.{}", ctx.prefix, input)),
}
let has_output = ctx.output_deserializer.is_some();
self.tera_context.insert("has_output", &has_output);
match ctx.output_deserializer {
None => self.tera_context.insert("output_deserializer", "void"),
Some(ref output) => self
.tera_context
.insert("output_deserializer", &format!("{}.{}", ctx.prefix, output)),
}
self.tera_context.insert(
"error_deserializer",
&format!("{}.{}", ctx.prefix, ctx.error_deserializer),
);
let tera = get_tera("ts_event");
match tera.render("event_template.tera", &self.tera_context) {
Ok(r) => Some(r),
Err(e) => {
log::error!("{:?}", e);
None
}
}
}
}

View File

@ -0,0 +1,37 @@
{%- if has_input %}
export async function {{ event_func_name }}(payload: {{ input_deserializer }}): Promise<Result<{{ output_deserializer }}, {{ error_deserializer }}>> {
{%- else %}
export async function {{ event_func_name }}(): Promise<Result<{{ output_deserializer }}, {{ error_deserializer }}>> {
{%- endif %}
{%- if has_input %}
let args = {
request: {
ty: {{ event_name }}[{{ event_name }}.{{ event }}],
payload: Array.from(payload.serializeBinary()),
},
};
{%- else %}
let args = {
request: {
ty: {{ event_name }}[{{ event_name }}.{{ event }}],
payload: Array.from([]),
},
};
{%- endif %}
let result: { code: number; payload: Uint8Array } = await invoke("invoke_request", args);
if (result.code == 0) {
{%- if has_output %}
let object = {{ output_deserializer }}.deserializeBinary(result.payload);
console.log("Success:" + JSON.stringify(object.toObject()))
return Ok(object);
{%- else %}
return Ok.EMPTY;
{%- endif %}
} else {
let error = {{ error_deserializer }}.deserializeBinary(result.payload);
console.log("Error:" + JSON.stringify(error.toObject()))
return Err(error);
}
}

View File

@ -0,0 +1,202 @@
mod event_template;
use crate::dart_event::ast::EventASTContext;
use crate::flowy_toml::{parse_crate_config_from, CrateConfig};
use crate::ts_event::event_template::{EventRenderContext, EventTemplate};
use crate::util::{is_crate_dir, is_hidden, path_string_with_component, read_file};
use flowy_ast::ASTResult;
use std::collections::HashSet;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use syn::Item;
use walkdir::WalkDir;
pub fn gen(crate_name: &str) {
if std::env::var("TAURI_PROTOBUF_PATH").is_err() {
log::warn!("TAURI_PROTOBUF_PATH was not set, skip generate ts event");
return;
}
let crate_path = std::fs::canonicalize(".").unwrap().as_path().display().to_string();
let event_crates = parse_ts_event_files(vec![crate_path]);
let event_ast = event_crates.iter().flat_map(parse_event_crate).collect::<Vec<_>>();
let event_render_ctx = ast_to_event_render_ctx(event_ast.as_ref());
let mut render_result = TS_HEADER.to_string();
for (index, render_ctx) in event_render_ctx.into_iter().enumerate() {
let mut event_template = EventTemplate::new();
if let Some(content) = event_template.render(render_ctx, index) {
render_result.push_str(content.as_ref())
}
}
render_result.push_str(TS_FOOTER);
let ts_event_folder: PathBuf = [
&std::env::var("CARGO_MAKE_WORKING_DIRECTORY").unwrap(),
&std::env::var("TAURI_PROTOBUF_PATH").unwrap(),
"events",
crate_name,
]
.iter()
.collect();
if !ts_event_folder.as_path().exists() {
std::fs::create_dir_all(ts_event_folder.as_path()).unwrap();
}
let event_file = "event";
let event_file_ext = "ts";
let ts_event_file_path =
path_string_with_component(&ts_event_folder, vec![&format!("{}.{}", event_file, event_file_ext)]);
println!("cargo:rerun-if-changed={}", ts_event_file_path);
match std::fs::OpenOptions::new()
.create(true)
.write(true)
.append(false)
.truncate(true)
.open(&ts_event_file_path)
{
Ok(ref mut file) => {
file.write_all(render_result.as_bytes()).unwrap();
File::flush(file).unwrap();
}
Err(err) => {
panic!("Failed to open file: {}, {:?}", ts_event_file_path, err);
}
}
let ts_index = path_string_with_component(&ts_event_folder, vec!["index.ts"]);
match std::fs::OpenOptions::new()
.create(true)
.write(true)
.append(false)
.truncate(true)
.open(&ts_index)
{
Ok(ref mut file) => {
let mut export = String::new();
export.push_str("// Auto-generated, do not edit \n");
export.push_str(&format!("export * from '../../classes/{}';\n", crate_name));
export.push_str(&format!("export * from './{}';\n", event_file));
file.write_all(export.as_bytes()).unwrap();
File::flush(file).unwrap();
}
Err(err) => {
panic!("Failed to open file: {}", err);
}
}
}
#[derive(Debug)]
pub struct TsEventCrate {
crate_path: PathBuf,
event_files: Vec<String>,
}
impl TsEventCrate {
pub fn from_config(config: &CrateConfig) -> Self {
TsEventCrate {
crate_path: config.crate_path.clone(),
event_files: config.flowy_config.event_files.clone(),
}
}
}
pub fn parse_ts_event_files(crate_paths: Vec<String>) -> Vec<TsEventCrate> {
let mut ts_event_crates: Vec<TsEventCrate> = vec![];
crate_paths.iter().for_each(|path| {
let crates = WalkDir::new(path)
.into_iter()
.filter_entry(|e| !is_hidden(e))
.filter_map(|e| e.ok())
.filter(is_crate_dir)
.flat_map(|e| parse_crate_config_from(&e))
.map(|crate_config| TsEventCrate::from_config(&crate_config))
.collect::<Vec<TsEventCrate>>();
ts_event_crates.extend(crates);
});
ts_event_crates
}
pub fn parse_event_crate(event_crate: &TsEventCrate) -> Vec<EventASTContext> {
event_crate
.event_files
.iter()
.flat_map(|event_file| {
let file_path = path_string_with_component(&event_crate.crate_path, vec![event_file.as_str()]);
let file_content = read_file(file_path.as_ref()).unwrap();
let ast = syn::parse_file(file_content.as_ref()).expect("Unable to parse file");
ast.items
.iter()
.flat_map(|item| match item {
Item::Enum(item_enum) => {
let ast_result = ASTResult::new();
let attrs = flowy_ast::enum_from_ast(
&ast_result,
&item_enum.ident,
&item_enum.variants,
&item_enum.attrs,
);
ast_result.check().unwrap();
attrs
.iter()
.filter(|attr| !attr.attrs.event_attrs.ignore)
.enumerate()
.map(|(_index, variant)| EventASTContext::from(&variant.attrs))
.collect::<Vec<_>>()
}
_ => vec![],
})
.collect::<Vec<_>>()
})
.collect::<Vec<EventASTContext>>()
}
pub fn ast_to_event_render_ctx(ast: &[EventASTContext]) -> Vec<EventRenderContext> {
let mut import_objects = HashSet::new();
ast.iter().for_each(|event_ast| {
if let Some(input) = event_ast.event_input.as_ref() {
import_objects.insert(input.get_ident().unwrap().to_string());
}
if let Some(output) = event_ast.event_output.as_ref() {
import_objects.insert(output.get_ident().unwrap().to_string());
}
});
ast.iter()
.map(|event_ast| {
let input_deserializer = event_ast
.event_input
.as_ref()
.map(|event_input| event_input.get_ident().unwrap().to_string());
let output_deserializer = event_ast
.event_output
.as_ref()
.map(|event_output| event_output.get_ident().unwrap().to_string());
EventRenderContext {
input_deserializer,
output_deserializer,
error_deserializer: event_ast.event_error.to_string(),
event: event_ast.event.to_string(),
event_ty: event_ast.event_ty.to_string(),
prefix: "pb".to_string(),
}
})
.collect::<Vec<EventRenderContext>>()
}
const TS_HEADER: &str = r#"
/// Auto generate. Do not edit
import { Ok, Err, Result } from "ts-results";
import { invoke } from "@tauri-apps/api/tauri";
import * as pb from "../../classes";
"#;
const TS_FOOTER: &str = r#"
"#;

View File

@ -18,7 +18,7 @@ flowy-document = { path = "../flowy-document", default-features = false }
flowy-revision = { path = "../flowy-revision" }
flowy-task = { path = "../flowy-task" }
tracing = { version = "0.1" }
tracing = { version = "0.1", features = ["log"] }
futures-core = { version = "0.3", default-features = false }
bytes = "1.0"
tokio = { version = "1", features = ["rt"] }
@ -39,6 +39,13 @@ dart = [
"flowy-grid/dart",
"flowy-document/dart",
]
ts = [
"flowy-user/ts",
"flowy-net/ts",
"flowy-folder/ts",
"flowy-grid/ts",
"flowy-document/ts",
]
rev-sqlite = [
"flowy-database",
"flowy-user/rev-sqlite",

View File

@ -59,7 +59,7 @@ impl FlowySDKConfig {
FlowySDKConfig {
name,
root: root.to_owned(),
log_filter: crate_log_filter("info".to_owned()),
log_filter: create_log_filter("info".to_owned(), vec![]),
server_config,
document: DocumentConfig::default(),
}
@ -70,15 +70,18 @@ impl FlowySDKConfig {
self
}
pub fn log_filter(mut self, level: &str) -> Self {
self.log_filter = crate_log_filter(level.to_owned());
pub fn log_filter(mut self, level: &str, with_crates: Vec<String>) -> Self {
self.log_filter = create_log_filter(level.to_owned(), with_crates);
self
}
}
fn crate_log_filter(level: String) -> String {
fn create_log_filter(level: String, with_crates: Vec<String>) -> String {
let level = std::env::var("RUST_LOG").unwrap_or(level);
let mut filters = vec![];
let mut filters = with_crates
.into_iter()
.map(|crate_name| format!("{}={}", crate_name, level))
.collect::<Vec<String>>();
filters.push(format!("flowy_core={}", level));
filters.push(format!("flowy_folder={}", level));
filters.push(format!("flowy_user={}", level));
@ -330,7 +333,7 @@ fn init_log(config: &FlowySDKConfig) {
if !INIT_LOG.load(Ordering::SeqCst) {
INIT_LOG.store(true, Ordering::SeqCst);
let _ = lib_log::Builder::new("flowy-client", &config.root)
let _ = lib_log::Builder::new("AppFlowy-Client", &config.root)
.env_filter(&config.log_filter)
.build();
}

View File

@ -61,4 +61,5 @@ sync = []
cloud_sync = ["sync"]
rev-sqlite = ["flowy-database"]
flowy_unit_test = ["lib-ot/flowy_unit_test", "flowy-revision/flowy_unit_test"]
dart = ["flowy-codegen/dart", "dart-notify/dart"]
dart = ["flowy-codegen/dart", "dart-notify/dart"]
ts = ["flowy-codegen/ts"]

View File

@ -4,4 +4,7 @@ fn main() {
#[cfg(feature = "dart")]
flowy_codegen::dart_event::gen(crate_name);
#[cfg(feature = "ts")]
flowy_codegen::ts_event::gen(crate_name);
}

View File

@ -28,6 +28,7 @@ serde = ["serde_json"]
http_server = ["http-flowy"]
db = ["flowy-database", "r2d2"]
dart = ["flowy-codegen/dart"]
ts = ["flowy-codegen/ts"]
[build-dependencies]
flowy-codegen = { path = "../flowy-codegen", features = ["proto_gen"]}

View File

@ -52,4 +52,5 @@ sync = []
cloud_sync = ["sync"]
rev-sqlite = ["flowy-database", "flowy-folder/rev-sqlite"]
flowy_unit_test = ["lib-ot/flowy_unit_test", "flowy-revision/flowy_unit_test"]
dart = ["flowy-codegen/dart", "dart-notify/dart"]
dart = ["flowy-codegen/dart", "dart-notify/dart"]
ts = ["flowy-codegen/ts"]

View File

@ -4,4 +4,7 @@ fn main() {
#[cfg(feature = "dart")]
flowy_codegen::dart_event::gen(crate_name);
#[cfg(feature = "ts")]
flowy_codegen::ts_event::gen(crate_name);
}

View File

@ -59,4 +59,5 @@ flowy-codegen = { path = "../flowy-codegen"}
default = []
rev-sqlite = ["flowy-database"]
dart = ["flowy-codegen/dart", "dart-notify/dart"]
ts = ["flowy-codegen/ts"]
flowy_unit_test = ["flowy-revision/flowy_unit_test"]

View File

@ -4,4 +4,7 @@ fn main() {
#[cfg(feature = "dart")]
flowy_codegen::dart_event::gen(crate_name);
#[cfg(feature = "ts")]
flowy_codegen::ts_event::gen(crate_name);
}

View File

@ -101,7 +101,7 @@ pub(crate) async fn delete_all_sorts_handler(
) -> Result<(), FlowyError> {
let grid_id: GridIdPB = data.into_inner();
let editor = manager.open_grid(grid_id.as_ref()).await?;
let _ = editor.delete_all_sorts(grid_id.as_ref()).await?;
editor.delete_all_sorts(grid_id.as_ref()).await?;
Ok(())
}

View File

@ -16,8 +16,8 @@ impl DateFilterPB {
_ => {}
}
let cell_time = NaiveDateTime::from_timestamp(timestamp, 0);
let cell_date = cell_time.date();
let cell_time = NaiveDateTime::from_timestamp_opt(timestamp, 0);
let cell_date = cell_time.map(|time| time.date());
match self.timestamp {
None => {
if self.start.is_none() {
@ -28,17 +28,17 @@ impl DateFilterPB {
return true;
}
let start_time = NaiveDateTime::from_timestamp(*self.start.as_ref().unwrap(), 0);
let start_date = start_time.date();
let start_time = NaiveDateTime::from_timestamp_opt(*self.start.as_ref().unwrap(), 0);
let start_date = start_time.map(|time| time.date());
let end_time = NaiveDateTime::from_timestamp(*self.end.as_ref().unwrap(), 0);
let end_date = end_time.date();
let end_time = NaiveDateTime::from_timestamp_opt(*self.end.as_ref().unwrap(), 0);
let end_date = end_time.map(|time| time.date());
cell_date >= start_date && cell_date <= end_date
}
Some(timestamp) => {
let expected_timestamp = NaiveDateTime::from_timestamp(timestamp, 0);
let expected_date = expected_timestamp.date();
let expected_timestamp = NaiveDateTime::from_timestamp_opt(timestamp, 0);
let expected_date = expected_timestamp.map(|time| time.date());
// We assume that the cell_timestamp doesn't contain hours, just day.
match self.condition {

View File

@ -54,7 +54,11 @@ impl DateTypeOptionPB {
fn today_desc_from_timestamp<T: Into<i64>>(&self, timestamp: T) -> DateCellDataPB {
let timestamp = timestamp.into();
let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0);
let native = chrono::NaiveDateTime::from_timestamp_opt(timestamp, 0);
if native.is_none() {
return DateCellDataPB::default();
}
let native = native.unwrap();
if native.timestamp() == 0 {
return DateCellDataPB::default();
}
@ -163,10 +167,13 @@ impl CellDataChangeset for DateTypeOptionPB {
Some(date_timestamp) => match (self.include_time, changeset.time) {
(true, Some(time)) => {
let time = Some(time.trim().to_uppercase());
let native = NaiveDateTime::from_timestamp(date_timestamp, 0);
let utc = self.utc_date_time_from_native(native);
self.timestamp_from_utc_with_time(&utc, &time)?
let native = NaiveDateTime::from_timestamp_opt(date_timestamp, 0);
if let Some(native) = native {
let utc = self.utc_date_time_from_native(native);
self.timestamp_from_utc_with_time(&utc, &time)?
} else {
date_timestamp
}
}
_ => date_timestamp,
},

View File

@ -107,7 +107,7 @@ impl NumberTypeOptionPB {
}
} else {
let draw_numer_string = NUM_REGEX.replace_all(s, "");
let strnum = match draw_numer_string.matches(".").count() {
let strnum = match draw_numer_string.matches('.').count() {
0 | 1 => draw_numer_string.to_string(),
_ => match EXTRACT_NUM_REGEX.captures(&draw_numer_string) {
Ok(captures) => match captures {

View File

@ -376,8 +376,7 @@ impl GridViewRevisionEditor {
pub async fn get_view_setting(&self) -> GridSettingPB {
let field_revs = self.delegate.get_field_revs(None).await;
let grid_setting = make_grid_setting(&*self.pad.read().await, &field_revs);
grid_setting
make_grid_setting(&*self.pad.read().await, &field_revs)
}
pub async fn get_all_view_sorts(&self) -> Vec<Arc<SortRevision>> {
@ -448,12 +447,11 @@ impl GridViewRevisionEditor {
pub async fn delete_all_view_sorts(&self) -> FlowyResult<()> {
let all_sorts = self.get_all_view_sorts().await;
self.sort_controller.write().await.delete_all_sorts().await;
let _ = self
.modify(|pad| {
let changeset = pad.delete_all_sorts()?;
Ok(changeset)
})
.await?;
self.modify(|pad| {
let changeset = pad.delete_all_sorts()?;
Ok(changeset)
})
.await?;
let mut notification = SortChangesetNotificationPB::new(self.view_id.clone());
notification.delete_sorts = all_sorts.into_iter().map(|sort| SortPB::from(sort.as_ref())).collect();

View File

@ -47,5 +47,11 @@ dart = [
"flowy-error/dart",
]
ts = [
"flowy-codegen/ts",
"flowy-user/ts",
"flowy-error/ts",
]
[build-dependencies]
flowy-codegen = { path = "../flowy-codegen"}

View File

@ -4,4 +4,7 @@ fn main() {
#[cfg(feature = "dart")]
flowy_codegen::dart_event::gen(crate_name);
#[cfg(feature = "ts")]
flowy_codegen::ts_event::gen(crate_name);
}

View File

@ -75,11 +75,11 @@ where
break;
}
}
return if new_operations.is_empty() {
if new_operations.is_empty() {
None
} else {
Some(new_operations)
};
}
}
pub fn pair_rev_id_from_revision_pbs(revisions: &[Revision]) -> (i64, i64) {

View File

@ -38,7 +38,7 @@ impl FlowySDKTest {
let server_config = get_client_server_configuration().unwrap();
let config = FlowySDKConfig::new(&root_dir(), nanoid!(6), server_config)
.with_document_version(document_version)
.log_filter("info");
.log_filter("info", vec![]);
let sdk = std::thread::spawn(|| FlowySDK::new(config)).join().unwrap();
std::mem::forget(sdk.dispatcher());
Self { inner: sdk }

View File

@ -47,6 +47,7 @@ rand = "0.8.5"
[features]
rev-sqlite = ["flowy-database"]
dart = ["flowy-codegen/dart", "dart-notify/dart"]
ts = ["flowy-codegen/ts"]
[build-dependencies]
flowy-codegen = { path = "../flowy-codegen"}

View File

@ -4,4 +4,7 @@ fn main() {
#[cfg(feature = "dart")]
flowy_codegen::dart_event::gen(crate_name);
#[cfg(feature = "ts")]
flowy_codegen::ts_event::gen(crate_name);
}

View File

@ -24,6 +24,7 @@ dyn-clone = "1.0"
derivative = "2.2.0"
serde_json = {version = "1.0", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
serde_repr = { version = "0.1", optional = true }
dashmap = "5"
#optional crate
@ -37,5 +38,5 @@ futures-util = "0.3.15"
[features]
default = ["use_protobuf"]
use_serde = ["bincode", "serde_json", "serde"]
use_serde = ["bincode", "serde_json", "serde", "serde_repr"]
use_protobuf= ["protobuf"]

View File

@ -24,18 +24,18 @@ where
}
}
#[cfg(feature = "use_serde")]
impl<T> ToBytes for T
where
T: serde::Serialize,
{
fn into_bytes(self) -> Result<Bytes, DispatchError> {
match serde_json::to_string(&self.0) {
Ok(s) => Ok(Bytes::from(s)),
Err(e) => Err(InternalError::SerializeToBytes(format!("{:?}", e)).into()),
}
}
}
// #[cfg(feature = "use_serde")]
// impl<T> ToBytes for T
// where
// T: serde::Serialize,
// {
// fn into_bytes(self) -> Result<Bytes, DispatchError> {
// match serde_json::to_string(&self.0) {
// Ok(s) => Ok(Bytes::from(s)),
// Err(e) => Err(InternalError::SerializeToBytes(format!("{:?}", e)).into()),
// }
// }
// }
// From bytes
@ -65,18 +65,18 @@ where
}
}
}
#[cfg(feature = "use_serde")]
impl<T> AFPluginFromBytes for T
where
T: serde::de::DeserializeOwned + 'static,
{
fn parse_from_bytes(bytes: Bytes) -> Result<Self, String> {
let s = String::from_utf8_lossy(&bytes);
match serde_json::from_str::<T>(s.as_ref()) {
Ok(data) => Ok(data),
Err(e) => Err(format!("{:?}", e)),
}
}
}
//
// #[cfg(feature = "use_serde")]
// impl<T> AFPluginFromBytes for T
// where
// T: serde::de::DeserializeOwned + 'static,
// {
// fn parse_from_bytes(bytes: Bytes) -> Result<Self, String> {
// let s = String::from_utf8_lossy(&bytes);
//
// match serde_json::from_str::<T>(s.as_ref()) {
// Ok(data) => Ok(data),
// Err(e) => Err(format!("{:?}", e)),
// }
// }
// }

View File

@ -122,8 +122,7 @@ impl fmt::Display for InternalError {
impl Error for InternalError {
fn as_response(&self) -> AFPluginEventResponse {
let error = format!("{}", self).into_bytes();
ResponseBuilder::Internal().data(error).build()
ResponseBuilder::Err().data(self.to_string()).build()
}
}

View File

@ -37,7 +37,7 @@ pub(crate) fn as_plugin_map(plugins: Vec<AFPlugin>) -> AFPluginMap {
}
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub struct AFPluginEvent(String);
pub struct AFPluginEvent(pub String);
impl<T: Display + Eq + Hash + Debug + Clone> std::convert::From<T> for AFPluginEvent {
fn from(t: T) -> Self {

View File

@ -11,6 +11,15 @@ pub enum Payload {
Bytes(Bytes),
}
impl Payload {
pub fn to_vec(self) -> Vec<u8> {
match self {
Payload::None => vec![],
Payload::Bytes(bytes) => bytes.to_vec(),
}
}
}
impl std::fmt::Debug for Payload {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
format_payload_print(self, f)

View File

@ -39,5 +39,4 @@ impl ResponseBuilder {
static_response!(Ok, StatusCode::Ok);
static_response!(Err, StatusCode::Err);
static_response!(Internal, StatusCode::Internal);
}

View File

@ -9,11 +9,11 @@ use derivative::*;
use std::{convert::TryFrom, fmt, fmt::Formatter};
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "use_serde", derive(serde::Serialize))]
#[cfg_attr(feature = "use_serde", derive(serde_repr::Serialize_repr))]
#[repr(u8)]
pub enum StatusCode {
Ok = 0,
Err = 1,
Internal = 2,
}
// serde user guide: https://serde.rs/field-attrs.html
@ -43,7 +43,7 @@ impl AFPluginEventResponse {
let data = <AFPluginData<T>>::try_from(self.payload)?;
Ok(Ok(data.into_inner()))
}
StatusCode::Err | StatusCode::Internal => {
StatusCode::Err => {
let err = <AFPluginData<E>>::try_from(self.payload)?;
Ok(Err(err.into_inner()))
}