mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 01:08:28 +02:00
NodeJS Plugin Runtime (#53)
This commit is contained in:
@@ -32,10 +32,12 @@ use tokio::sync::Mutex;
|
||||
|
||||
use ::grpc::manager::{DynamicMessage, GrpcHandle};
|
||||
use ::grpc::{deserialize_message, serialize_message, Code, ServiceDefinition};
|
||||
use plugin_runtime::manager::PluginManager;
|
||||
|
||||
use crate::analytics::{AnalyticsAction, AnalyticsResource};
|
||||
use crate::grpc::metadata_to_map;
|
||||
use crate::http_request::send_http_request;
|
||||
use crate::models::ImportResult;
|
||||
use crate::models::{
|
||||
cancel_pending_grpc_connections, cancel_pending_responses, create_http_response,
|
||||
delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar, delete_environment,
|
||||
@@ -53,22 +55,15 @@ use crate::models::{
|
||||
WorkspaceExportResources,
|
||||
};
|
||||
use crate::notifications::YaakNotifier;
|
||||
use crate::plugin::{
|
||||
find_plugins, get_plugin, run_plugin_export_curl, run_plugin_filter, run_plugin_import,
|
||||
ImportResult, PluginCapability,
|
||||
};
|
||||
use crate::render::{render_request, variables_from_environment};
|
||||
use crate::updates::{UpdateMode, YaakUpdater};
|
||||
use crate::window_menu::app_menu;
|
||||
|
||||
mod analytics;
|
||||
mod deno;
|
||||
mod deno_ops;
|
||||
mod grpc;
|
||||
mod http_request;
|
||||
mod models;
|
||||
mod notifications;
|
||||
mod plugin;
|
||||
mod render;
|
||||
#[cfg(target_os = "macos")]
|
||||
mod tauri_plugin_mac_window;
|
||||
@@ -284,8 +279,8 @@ async fn cmd_grpc_go(
|
||||
..conn.clone()
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
return Ok(conn_id);
|
||||
}
|
||||
};
|
||||
@@ -740,22 +735,15 @@ async fn cmd_filter_response(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Have plugins register their own content type (regex?)
|
||||
let plugin_name = if content_type.contains("json") {
|
||||
"filter-jsonpath"
|
||||
} else {
|
||||
"filter-xpath"
|
||||
};
|
||||
|
||||
let body = read_to_string(response.body_path.unwrap()).unwrap();
|
||||
let plugin = match get_plugin(&w.app_handle(), plugin_name).map_err(|e| e.to_string())? {
|
||||
None => return Err("Failed to get plugin".into()),
|
||||
Some(p) => p,
|
||||
};
|
||||
let filter_result = run_plugin_filter(&plugin, filter, &body)
|
||||
|
||||
// TODO: Have plugins register their own content type (regex?)
|
||||
let manager: State<PluginManager> = w.app_handle().state();
|
||||
manager
|
||||
.inner()
|
||||
.run_response_filter(filter, &body, &content_type)
|
||||
.await
|
||||
.expect("Failed to run filter");
|
||||
Ok(filter_result.filtered)
|
||||
.map(|r| r.data)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -764,140 +752,129 @@ async fn cmd_import_data(
|
||||
file_path: &str,
|
||||
_workspace_id: &str,
|
||||
) -> Result<WorkspaceExportResources, String> {
|
||||
let mut result: Option<ImportResult> = None;
|
||||
let file =
|
||||
read_to_string(file_path).unwrap_or_else(|_| panic!("Unable to read file {}", file_path));
|
||||
let file_contents = file.as_str();
|
||||
let plugins = find_plugins(w.app_handle(), &PluginCapability::Import)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
for plugin in plugins {
|
||||
let v = run_plugin_import(&plugin, file_contents)
|
||||
let manager: State<PluginManager> = w.app_handle().state();
|
||||
let import_response = manager.inner().run_import(file_contents).await?;
|
||||
let import_result: ImportResult =
|
||||
serde_json::from_str(import_response.data.as_str()).map_err(|e| e.to_string())?;
|
||||
|
||||
// TODO: Track the plugin that ran, maybe return the run info in the plugin response?
|
||||
let plugin_name = import_response.info.unwrap_or_default().plugin;
|
||||
info!("Imported data using {}", plugin_name);
|
||||
analytics::track_event(
|
||||
&w.app_handle(),
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::Import,
|
||||
Some(json!({ "plugin": plugin_name })),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut imported_resources = WorkspaceExportResources::default();
|
||||
let mut id_map: HashMap<String, String> = HashMap::new();
|
||||
|
||||
fn maybe_gen_id(id: &str, model: ModelType, ids: &mut HashMap<String, String>) -> String {
|
||||
if !id.starts_with("GENERATE_ID::") {
|
||||
return id.to_string();
|
||||
}
|
||||
|
||||
let unique_key = id.replace("GENERATE_ID", "");
|
||||
if let Some(existing) = ids.get(unique_key.as_str()) {
|
||||
existing.to_string()
|
||||
} else {
|
||||
let new_id = generate_model_id(model);
|
||||
ids.insert(unique_key, new_id.clone());
|
||||
new_id
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_gen_id_opt(
|
||||
id: Option<String>,
|
||||
model: ModelType,
|
||||
ids: &mut HashMap<String, String>,
|
||||
) -> Option<String> {
|
||||
match id {
|
||||
Some(id) => Some(maybe_gen_id(id.as_str(), model, ids)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
for mut v in import_result.resources.workspaces {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeWorkspace, &mut id_map);
|
||||
let x = upsert_workspace(&w, v).await.map_err(|e| e.to_string())?;
|
||||
imported_resources.workspaces.push(x.clone());
|
||||
}
|
||||
info!(
|
||||
"Imported {} workspaces",
|
||||
imported_resources.workspaces.len()
|
||||
);
|
||||
|
||||
for mut v in import_result.resources.environments {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeEnvironment, &mut id_map);
|
||||
v.workspace_id = maybe_gen_id(
|
||||
v.workspace_id.as_str(),
|
||||
ModelType::TypeWorkspace,
|
||||
&mut id_map,
|
||||
);
|
||||
let x = upsert_environment(&w, v).await.map_err(|e| e.to_string())?;
|
||||
imported_resources.environments.push(x.clone());
|
||||
}
|
||||
info!(
|
||||
"Imported {} environments",
|
||||
imported_resources.environments.len()
|
||||
);
|
||||
|
||||
for mut v in import_result.resources.folders {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeFolder, &mut id_map);
|
||||
v.workspace_id = maybe_gen_id(
|
||||
v.workspace_id.as_str(),
|
||||
ModelType::TypeWorkspace,
|
||||
&mut id_map,
|
||||
);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
let x = upsert_folder(&w, v).await.map_err(|e| e.to_string())?;
|
||||
imported_resources.folders.push(x.clone());
|
||||
}
|
||||
info!("Imported {} folders", imported_resources.folders.len());
|
||||
|
||||
for mut v in import_result.resources.http_requests {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeHttpRequest, &mut id_map);
|
||||
v.workspace_id = maybe_gen_id(
|
||||
v.workspace_id.as_str(),
|
||||
ModelType::TypeWorkspace,
|
||||
&mut id_map,
|
||||
);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
let x = upsert_http_request(&w, v)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
if let Some(r) = v {
|
||||
info!("Imported data using {}", plugin.name);
|
||||
analytics::track_event(
|
||||
&w.app_handle(),
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::Import,
|
||||
Some(json!({ "plugin": plugin.name })),
|
||||
)
|
||||
.await;
|
||||
result = Some(r);
|
||||
break;
|
||||
}
|
||||
imported_resources.http_requests.push(x.clone());
|
||||
}
|
||||
info!(
|
||||
"Imported {} http_requests",
|
||||
imported_resources.http_requests.len()
|
||||
);
|
||||
|
||||
match result {
|
||||
None => Err("No import handlers found".to_string()),
|
||||
Some(r) => {
|
||||
let mut imported_resources = WorkspaceExportResources::default();
|
||||
let mut id_map: HashMap<String, String> = HashMap::new();
|
||||
|
||||
let maybe_gen_id =
|
||||
|id: &str, model: ModelType, ids: &mut HashMap<String, String>| -> String {
|
||||
if !id.starts_with("GENERATE_ID::") {
|
||||
return id.to_string();
|
||||
}
|
||||
|
||||
let unique_key = id.replace("GENERATE_ID", "");
|
||||
if let Some(existing) = ids.get(unique_key.as_str()) {
|
||||
existing.to_string()
|
||||
} else {
|
||||
let new_id = generate_model_id(model);
|
||||
ids.insert(unique_key, new_id.clone());
|
||||
new_id
|
||||
}
|
||||
};
|
||||
|
||||
let maybe_gen_id_opt = |id: Option<String>,
|
||||
model: ModelType,
|
||||
ids: &mut HashMap<String, String>|
|
||||
-> Option<String> {
|
||||
match id {
|
||||
Some(id) => Some(maybe_gen_id(id.as_str(), model, ids)),
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
|
||||
for mut v in r.resources.workspaces {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeWorkspace, &mut id_map);
|
||||
let x = upsert_workspace(&w, v).await.map_err(|e| e.to_string())?;
|
||||
imported_resources.workspaces.push(x.clone());
|
||||
}
|
||||
info!(
|
||||
"Imported {} workspaces",
|
||||
imported_resources.workspaces.len()
|
||||
);
|
||||
|
||||
for mut v in r.resources.environments {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeEnvironment, &mut id_map);
|
||||
v.workspace_id = maybe_gen_id(
|
||||
v.workspace_id.as_str(),
|
||||
ModelType::TypeWorkspace,
|
||||
&mut id_map,
|
||||
);
|
||||
let x = upsert_environment(&w, v).await.map_err(|e| e.to_string())?;
|
||||
imported_resources.environments.push(x.clone());
|
||||
}
|
||||
info!(
|
||||
"Imported {} environments",
|
||||
imported_resources.environments.len()
|
||||
);
|
||||
|
||||
for mut v in r.resources.folders {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeFolder, &mut id_map);
|
||||
v.workspace_id = maybe_gen_id(
|
||||
v.workspace_id.as_str(),
|
||||
ModelType::TypeWorkspace,
|
||||
&mut id_map,
|
||||
);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
let x = upsert_folder(&w, v).await.map_err(|e| e.to_string())?;
|
||||
imported_resources.folders.push(x.clone());
|
||||
}
|
||||
info!("Imported {} folders", imported_resources.folders.len());
|
||||
|
||||
for mut v in r.resources.http_requests {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeHttpRequest, &mut id_map);
|
||||
v.workspace_id = maybe_gen_id(
|
||||
v.workspace_id.as_str(),
|
||||
ModelType::TypeWorkspace,
|
||||
&mut id_map,
|
||||
);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
let x = upsert_http_request(&w, v)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
imported_resources.http_requests.push(x.clone());
|
||||
}
|
||||
info!(
|
||||
"Imported {} http_requests",
|
||||
imported_resources.http_requests.len()
|
||||
);
|
||||
|
||||
for mut v in r.resources.grpc_requests {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeGrpcRequest, &mut id_map);
|
||||
v.workspace_id = maybe_gen_id(
|
||||
v.workspace_id.as_str(),
|
||||
ModelType::TypeWorkspace,
|
||||
&mut id_map,
|
||||
);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
let x = upsert_grpc_request(&w, &v)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
imported_resources.grpc_requests.push(x.clone());
|
||||
}
|
||||
info!(
|
||||
"Imported {} grpc_requests",
|
||||
imported_resources.grpc_requests.len()
|
||||
);
|
||||
|
||||
Ok(imported_resources)
|
||||
}
|
||||
for mut v in import_result.resources.grpc_requests {
|
||||
v.id = maybe_gen_id(v.id.as_str(), ModelType::TypeGrpcRequest, &mut id_map);
|
||||
v.workspace_id = maybe_gen_id(
|
||||
v.workspace_id.as_str(),
|
||||
ModelType::TypeWorkspace,
|
||||
&mut id_map,
|
||||
);
|
||||
v.folder_id = maybe_gen_id_opt(v.folder_id, ModelType::TypeFolder, &mut id_map);
|
||||
let x = upsert_grpc_request(&w, &v)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
imported_resources.grpc_requests.push(x.clone());
|
||||
}
|
||||
info!(
|
||||
"Imported {} grpc_requests",
|
||||
imported_resources.grpc_requests.len()
|
||||
);
|
||||
|
||||
Ok(imported_resources)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -917,7 +894,11 @@ async fn cmd_request_to_curl(
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let rendered = render_request(&request, &workspace, environment.as_ref());
|
||||
Ok(run_plugin_export_curl(&app, &rendered)?)
|
||||
let request_json = serde_json::to_string(&rendered).map_err(|e| e.to_string())?;
|
||||
|
||||
let manager: State<PluginManager> = app.state();
|
||||
let import_response = manager.inner().run_export_curl(request_json.as_str()).await?;
|
||||
Ok(import_response.data)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -926,27 +907,21 @@ async fn cmd_curl_to_request(
|
||||
command: &str,
|
||||
workspace_id: &str,
|
||||
) -> Result<HttpRequest, String> {
|
||||
let plugin = match get_plugin(&app_handle, "importer-curl").map_err(|e| e.to_string())? {
|
||||
None => return Err("Failed to find plugin".into()),
|
||||
Some(p) => p,
|
||||
};
|
||||
|
||||
let v = run_plugin_import(&plugin, command).await;
|
||||
match v {
|
||||
Ok(Some(r)) => r
|
||||
.resources
|
||||
.http_requests
|
||||
.get(0)
|
||||
.ok_or("No curl command found".to_string())
|
||||
.map(|r| {
|
||||
let mut request = r.clone();
|
||||
request.workspace_id = workspace_id.into();
|
||||
request.id = "".to_string();
|
||||
request
|
||||
}),
|
||||
Ok(None) => Err("Did not find curl request".to_string()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
let manager: State<PluginManager> = app_handle.state();
|
||||
let import_response = manager.inner().run_import(command).await?;
|
||||
let import_result: ImportResult =
|
||||
serde_json::from_str(import_response.data.as_str()).map_err(|e| e.to_string())?;
|
||||
import_result
|
||||
.resources
|
||||
.http_requests
|
||||
.get(0)
|
||||
.ok_or("No curl command found".to_string())
|
||||
.map(|r| {
|
||||
let mut request = r.clone();
|
||||
request.workspace_id = workspace_id.into();
|
||||
request.id = "".to_string();
|
||||
request
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -1595,25 +1570,6 @@ async fn cmd_check_for_updates(
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
let mut builder = tauri::Builder::default()
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
.plugin(tauri_plugin_window_state::Builder::default().build())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_os::init())
|
||||
.plugin(tauri_plugin_fs::init());
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
builder = builder.plugin(tauri_plugin_mac_window::init());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
builder = builder; // Don't complain about not being mut
|
||||
}
|
||||
|
||||
builder
|
||||
.plugin(
|
||||
tauri_plugin_log::Builder::default()
|
||||
.targets([
|
||||
@@ -1621,6 +1577,7 @@ pub fn run() {
|
||||
Target::new(TargetKind::LogDir { file_name: None }),
|
||||
Target::new(TargetKind::Webview),
|
||||
])
|
||||
.level_for("plugin_runtime", log::LevelFilter::Info)
|
||||
.level_for("cookie_store", log::LevelFilter::Info)
|
||||
.level_for("h2", log::LevelFilter::Info)
|
||||
.level_for("hyper", log::LevelFilter::Info)
|
||||
@@ -1642,6 +1599,26 @@ pub fn run() {
|
||||
})
|
||||
.build(),
|
||||
)
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
.plugin(tauri_plugin_window_state::Builder::default().build())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_os::init())
|
||||
.plugin(plugin_runtime::init())
|
||||
.plugin(tauri_plugin_fs::init());
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
builder = builder.plugin(tauri_plugin_mac_window::init());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
builder = builder; // Don't complain about not being mut
|
||||
}
|
||||
|
||||
builder
|
||||
.setup(|app| {
|
||||
let app_data_dir = app.path().app_data_dir().unwrap();
|
||||
let app_config_dir = app.path().app_config_dir().unwrap();
|
||||
@@ -1650,13 +1627,13 @@ pub fn run() {
|
||||
app_config_dir.as_path().to_string_lossy(),
|
||||
);
|
||||
info!("App Data Dir: {}", app_data_dir.as_path().to_string_lossy());
|
||||
let dir = match is_dev() {
|
||||
let app_data_dir = match is_dev() {
|
||||
true => current_dir().unwrap(),
|
||||
false => app_data_dir,
|
||||
};
|
||||
|
||||
create_dir_all(dir.clone()).expect("Problem creating App directory!");
|
||||
let p = dir.join("db.sqlite");
|
||||
create_dir_all(app_data_dir.clone()).expect("Problem creating App directory!");
|
||||
let p = app_data_dir.join("db.sqlite");
|
||||
File::options()
|
||||
.write(true)
|
||||
.create(true)
|
||||
@@ -1679,6 +1656,10 @@ pub fn run() {
|
||||
let grpc_handle = GrpcHandle::new(&app.app_handle());
|
||||
app.manage(Mutex::new(grpc_handle));
|
||||
|
||||
// Add plugin manager
|
||||
let grpc_handle = GrpcHandle::new(&app.app_handle());
|
||||
app.manage(Mutex::new(grpc_handle));
|
||||
|
||||
// Add DB handle
|
||||
tauri::async_runtime::block_on(async move {
|
||||
let opts = SqliteConnectOptions::from_str(p.to_str().unwrap()).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user