mirror of
https://github.com/project-gauntlet/gauntlet.git
synced 2025-12-23 10:35:53 +00:00
Plugins can now be enabled or disabled via management ui
This commit is contained in:
parent
b6c879c3fe
commit
13d9b554cb
14 changed files with 507 additions and 166 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
|
@ -426,6 +426,28 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.69",
|
||||
"quote 1.0.33",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.4.1"
|
||||
|
|
@ -5672,6 +5694,7 @@ name = "placeholdername"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
"clap",
|
||||
"deno_core",
|
||||
"deno_runtime",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ clap = { version = "4.3.22", features = ["derive"] }
|
|||
gix = { version = "0.52.0", features = ["blocking-network-client"] }
|
||||
tempfile = "3"
|
||||
futures-concurrency = "7.4.2"
|
||||
async-stream = "0.3.5"
|
||||
anyhow = "1.0.75"
|
||||
thiserror = "1.0.48"
|
||||
iced = { version = "0.10", features = ["tokio", "lazy", "advanced"] }
|
||||
|
|
|
|||
|
|
@ -16,29 +16,40 @@ declare interface InternalApi {
|
|||
op_react_call_event_listener(instance: InstanceSync, eventName: string): void;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
// noinspection InfiniteLoopJS
|
||||
const run_loop = async () => {
|
||||
while (true) {
|
||||
console.log("before op_react_get_next_pending_ui_event")
|
||||
const uiEvent = await denoCore.opAsync("op_react_get_next_pending_ui_event");
|
||||
switch (uiEvent.type) {
|
||||
console.log("before op_plugin_get_pending_event")
|
||||
const pluginEvent = await denoCore.opAsync("op_plugin_get_pending_event");
|
||||
switch (pluginEvent.type) {
|
||||
case "ViewEvent": {
|
||||
console.log("ViewEvent")
|
||||
InternalApi.op_react_call_event_listener(uiEvent.widget, uiEvent.eventName)
|
||||
InternalApi.op_react_call_event_listener(pluginEvent.widget, pluginEvent.eventName)
|
||||
break;
|
||||
}
|
||||
case "ViewCreated": {
|
||||
console.log("ViewCreated")
|
||||
const view = (await import(`plugin:view?${uiEvent.viewName}`)).default;
|
||||
const view = (await import(`plugin:view?${pluginEvent.viewName}`)).default;
|
||||
const { render } = await import("plugin:renderer");
|
||||
|
||||
render(uiEvent.reconcilerMode, view)
|
||||
render(pluginEvent.reconcilerMode, view)
|
||||
break;
|
||||
}
|
||||
case "ViewDestroyed": {
|
||||
console.log("ViewDestroyed")
|
||||
break;
|
||||
}
|
||||
case "PluginCommand": {
|
||||
switch (pluginEvent.commandType) {
|
||||
case "stop": {
|
||||
console.log("PluginCommand stop")
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
await run_loop()
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ pub enum NativeUiResponseData {
|
|||
CloneInstance {
|
||||
widget: NativeUiWidget
|
||||
},
|
||||
Unit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ pub struct DBusSearchResult {
|
|||
pub struct DBusPlugin {
|
||||
pub plugin_id: String,
|
||||
pub plugin_name: String,
|
||||
pub enabled: bool,
|
||||
pub entrypoints: Vec<DBusEntrypoint>,
|
||||
}
|
||||
|
||||
|
|
@ -23,6 +24,7 @@ pub struct DBusPlugin {
|
|||
pub struct DBusEntrypoint {
|
||||
pub entrypoint_id: String,
|
||||
pub entrypoint_name: String,
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Type)]
|
||||
|
|
|
|||
|
|
@ -7,5 +7,7 @@ use crate::common::dbus::DBusPlugin;
|
|||
)]
|
||||
trait DbusManagementServerProxy {
|
||||
async fn plugins(&self) -> zbus::Result<Vec<DBusPlugin>>;
|
||||
async fn set_plugin_state(&self, plugin_id: &str, enabled: bool) -> zbus::Result<()>;
|
||||
async fn set_entrypoint_state(&self, plugin_id: &str, entrypoint_id: &str, enabled: bool) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||
|
||||
use deno_core::error::AnyError;
|
||||
use iced::{Application, Command, Element, executor, font, futures, Length, Padding, Renderer, Settings, theme, window};
|
||||
use iced::widget::{button, column, container, horizontal_space, row, scrollable, text};
|
||||
use iced::widget::{button, checkbox, column, container, horizontal_space, row, scrollable, text};
|
||||
use iced_aw::graphics::icons;
|
||||
use iced_table::table;
|
||||
use zbus::Connection;
|
||||
|
|
@ -37,11 +37,12 @@ struct ManagementAppModel {
|
|||
enum ManagementAppMsg {
|
||||
TableSyncHeader(scrollable::AbsoluteOffset),
|
||||
FontLoaded(Result<(), font::Error>),
|
||||
PluginsLoaded(HashMap<PluginId, Plugin>),
|
||||
PluginsReloaded(HashMap<PluginId, Plugin>),
|
||||
ToggleShowEntrypoints {
|
||||
plugin_id: PluginId,
|
||||
},
|
||||
SelectItem(SelectedItem)
|
||||
SelectItem(SelectedItem),
|
||||
EnabledToggleItem(EnabledItem),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -56,12 +57,26 @@ enum SelectedItem {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum EnabledItem {
|
||||
Plugin {
|
||||
enabled: bool,
|
||||
plugin_id: PluginId
|
||||
},
|
||||
Entrypoint {
|
||||
enabled: bool,
|
||||
plugin_id: PluginId,
|
||||
entrypoint_id: EntrypointId
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Plugin {
|
||||
plugin_id: PluginId,
|
||||
plugin_name: String,
|
||||
show_entrypoints: bool,
|
||||
enabled: bool,
|
||||
entrypoints: HashMap<EntrypointId, Entrypoint>,
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +84,7 @@ struct Plugin {
|
|||
struct Entrypoint {
|
||||
entrypoint_id: EntrypointId,
|
||||
entrypoint_name: String,
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl Application for ManagementAppModel {
|
||||
|
|
@ -95,8 +111,9 @@ impl Application for ManagementAppModel {
|
|||
dbus_connection,
|
||||
dbus_server,
|
||||
columns: vec![
|
||||
Column::new(ColumnKind::EntrypointToggle),
|
||||
Column::new(ColumnKind::ShowEntrypointsToggle),
|
||||
Column::new(ColumnKind::Name),
|
||||
Column::new(ColumnKind::EnableToggle),
|
||||
],
|
||||
plugins: HashMap::new(),
|
||||
selected_item: SelectedItem::None,
|
||||
|
|
@ -106,36 +123,8 @@ impl Application for ManagementAppModel {
|
|||
Command::batch([
|
||||
font::load(icons::ICON_FONT_BYTES).map(ManagementAppMsg::FontLoaded),
|
||||
Command::perform(async move {
|
||||
let plugins = dbus_server_clone.plugins().await.unwrap();
|
||||
|
||||
let plugins: HashMap<_, _> = plugins.into_iter()
|
||||
.map(|plugin| {
|
||||
let entrypoints: HashMap<_, _> = plugin.entrypoints
|
||||
.into_iter()
|
||||
.map(|entrypoint| {
|
||||
let id = EntrypointId::new(entrypoint.entrypoint_id);
|
||||
let entrypoint = Entrypoint {
|
||||
entrypoint_id: id.clone(),
|
||||
entrypoint_name: entrypoint.entrypoint_name.clone(),
|
||||
};
|
||||
(id, entrypoint)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let id = PluginId::new(plugin.plugin_id);
|
||||
let plugin = Plugin {
|
||||
plugin_id: id.clone(),
|
||||
plugin_name: plugin.plugin_name,
|
||||
show_entrypoints: true,
|
||||
entrypoints,
|
||||
};
|
||||
|
||||
(id, plugin)
|
||||
})
|
||||
.collect();
|
||||
|
||||
plugins
|
||||
}, ManagementAppMsg::PluginsLoaded)
|
||||
reload_plugins(dbus_server_clone).await
|
||||
}, ManagementAppMsg::PluginsReloaded)
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
|
@ -158,7 +147,7 @@ impl Application for ManagementAppModel {
|
|||
plugin.show_entrypoints = !plugin.show_entrypoints;
|
||||
Command::none()
|
||||
}
|
||||
ManagementAppMsg::PluginsLoaded(plugins) => {
|
||||
ManagementAppMsg::PluginsReloaded(plugins) => {
|
||||
self.plugins = plugins;
|
||||
Command::none()
|
||||
}
|
||||
|
|
@ -166,6 +155,29 @@ impl Application for ManagementAppModel {
|
|||
self.selected_item = selected_item;
|
||||
Command::none()
|
||||
}
|
||||
ManagementAppMsg::EnabledToggleItem(item) => {
|
||||
match item {
|
||||
EnabledItem::Plugin { enabled, plugin_id } => {
|
||||
let dbus_server = self.dbus_server.clone();
|
||||
|
||||
Command::perform(async move {
|
||||
dbus_server.set_plugin_state(&plugin_id.to_string(), enabled).await.unwrap();
|
||||
|
||||
reload_plugins(dbus_server).await
|
||||
|
||||
}, ManagementAppMsg::PluginsReloaded)
|
||||
}
|
||||
EnabledItem::Entrypoint { enabled, plugin_id, entrypoint_id } => {
|
||||
let dbus_server = self.dbus_server.clone();
|
||||
|
||||
Command::perform(async move {
|
||||
dbus_server.set_entrypoint_state(&plugin_id.to_string(), &entrypoint_id.to_string(), enabled).await.unwrap();
|
||||
|
||||
reload_plugins(dbus_server).await
|
||||
}, ManagementAppMsg::PluginsReloaded)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -268,8 +280,9 @@ enum Row<'a> {
|
|||
}
|
||||
|
||||
enum ColumnKind {
|
||||
EntrypointToggle,
|
||||
ShowEntrypointsToggle,
|
||||
Name,
|
||||
EnableToggle,
|
||||
}
|
||||
|
||||
struct Column {
|
||||
|
|
@ -289,7 +302,7 @@ impl<'a, 'b> table::Column<'a, 'b, ManagementAppMsg, Renderer> for Column {
|
|||
|
||||
fn header(&'b self, _col_index: usize) -> Element<'a, ManagementAppMsg> {
|
||||
match self.kind {
|
||||
ColumnKind::EntrypointToggle => {
|
||||
ColumnKind::ShowEntrypointsToggle => {
|
||||
horizontal_space(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
|
|
@ -298,6 +311,11 @@ impl<'a, 'b> table::Column<'a, 'b, ManagementAppMsg, Renderer> for Column {
|
|||
.center_y()
|
||||
.into()
|
||||
}
|
||||
ColumnKind::EnableToggle => {
|
||||
container(text("Enabled"))
|
||||
.center_y()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -308,7 +326,7 @@ impl<'a, 'b> table::Column<'a, 'b, ManagementAppMsg, Renderer> for Column {
|
|||
row_entry: &'b Self::Row,
|
||||
) -> Element<'a, ManagementAppMsg> {
|
||||
match self.kind {
|
||||
ColumnKind::EntrypointToggle => {
|
||||
ColumnKind::ShowEntrypointsToggle => {
|
||||
match row_entry {
|
||||
Row::Plugin { plugin } => {
|
||||
let icon = if plugin.show_entrypoints { icons::Icon::CaretDown } else { icons::Icon::CaretRight };
|
||||
|
|
@ -351,7 +369,9 @@ impl<'a, 'b> table::Column<'a, 'b, ManagementAppMsg, Renderer> for Column {
|
|||
};
|
||||
|
||||
let msg = match &row_entry {
|
||||
Row::Plugin { plugin } => SelectedItem::Plugin { plugin_id: plugin.plugin_id.clone() },
|
||||
Row::Plugin { plugin } => SelectedItem::Plugin {
|
||||
plugin_id: plugin.plugin_id.clone()
|
||||
},
|
||||
Row::Entrypoint { entrypoint, plugin } => SelectedItem::Entrypoint {
|
||||
plugin_id: plugin.plugin_id.clone(),
|
||||
entrypoint_id: entrypoint.entrypoint_id.clone()
|
||||
|
|
@ -364,13 +384,54 @@ impl<'a, 'b> table::Column<'a, 'b, ManagementAppMsg, Renderer> for Column {
|
|||
.width(Length::Fill)
|
||||
.into()
|
||||
}
|
||||
ColumnKind::EnableToggle => {
|
||||
let (enabled, plugin_id, entrypoint_id) = match &row_entry {
|
||||
Row::Plugin { plugin } => {
|
||||
(
|
||||
plugin.enabled,
|
||||
plugin.plugin_id.clone(),
|
||||
None
|
||||
)
|
||||
},
|
||||
Row::Entrypoint { entrypoint, plugin } => {
|
||||
(
|
||||
entrypoint.enabled,
|
||||
plugin.plugin_id.clone(),
|
||||
Some(entrypoint.entrypoint_id.clone())
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// TODO disable if plugin is disabled but preserve current state https://github.com/iced-rs/iced/pull/2109
|
||||
let checkbox: Element<_> = checkbox("", enabled, move |enabled| {
|
||||
let enabled_item = match &entrypoint_id {
|
||||
None => EnabledItem::Plugin {
|
||||
enabled,
|
||||
plugin_id: plugin_id.clone(),
|
||||
},
|
||||
Some(entrypoint_id) => EnabledItem::Entrypoint {
|
||||
enabled,
|
||||
plugin_id: plugin_id.clone(),
|
||||
entrypoint_id: entrypoint_id.clone()
|
||||
}
|
||||
};
|
||||
ManagementAppMsg::EnabledToggleItem(enabled_item)
|
||||
}).into();
|
||||
|
||||
container(checkbox)
|
||||
.width(Length::Fill)
|
||||
.center_x()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn width(&self) -> f32 {
|
||||
match self.kind {
|
||||
ColumnKind::EntrypointToggle => 35.0,
|
||||
ColumnKind::ShowEntrypointsToggle => 35.0,
|
||||
ColumnKind::Name => 550.0,
|
||||
ColumnKind::EnableToggle => 75.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -378,3 +439,36 @@ impl<'a, 'b> table::Column<'a, 'b, ManagementAppMsg, Renderer> for Column {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn reload_plugins(dbus_server: DbusManagementServerProxyProxy<'static>) -> HashMap<PluginId, Plugin> {
|
||||
let plugins = dbus_server.plugins().await.unwrap();
|
||||
|
||||
plugins.into_iter()
|
||||
.map(|plugin| {
|
||||
let entrypoints: HashMap<_, _> = plugin.entrypoints
|
||||
.into_iter()
|
||||
.map(|entrypoint| {
|
||||
let id = EntrypointId::new(entrypoint.entrypoint_id);
|
||||
let entrypoint = Entrypoint {
|
||||
enabled: entrypoint.enabled,
|
||||
entrypoint_id: id.clone(),
|
||||
entrypoint_name: entrypoint.entrypoint_name.clone(),
|
||||
};
|
||||
(id, entrypoint)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let id = PluginId::new(plugin.plugin_id);
|
||||
let plugin = Plugin {
|
||||
plugin_id: id.clone(),
|
||||
plugin_name: plugin.plugin_name,
|
||||
show_entrypoints: true,
|
||||
enabled: plugin.enabled,
|
||||
entrypoints,
|
||||
};
|
||||
|
||||
(id, plugin)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
use crate::common::dbus::{DBusEntrypoint, DbusEventViewCreated, DbusEventViewEvent, DBusPlugin, DBusSearchResult, DBusUiPropertyContainer, DBusUiWidget};
|
||||
use crate::common::dbus::{DbusEventViewCreated, DbusEventViewEvent, DBusPlugin, DBusSearchResult, DBusUiPropertyContainer, DBusUiWidget};
|
||||
use crate::common::model::{EntrypointId, PluginId};
|
||||
use crate::server::plugins::PluginManager;
|
||||
use crate::server::search::SearchIndex;
|
||||
|
||||
|
|
@ -36,19 +37,16 @@ pub struct DbusManagementServer {
|
|||
impl DbusManagementServer {
|
||||
fn plugins(&mut self) -> Vec<DBusPlugin> {
|
||||
self.plugin_manager.plugins()
|
||||
.iter()
|
||||
.map(|plugin| DBusPlugin {
|
||||
plugin_id: plugin.id().to_owned(),
|
||||
plugin_name: plugin.name().to_owned(),
|
||||
entrypoints: plugin.entrypoints()
|
||||
.into_iter()
|
||||
.map(|entrypoint| DBusEntrypoint {
|
||||
entrypoint_id: entrypoint.id().to_owned(),
|
||||
entrypoint_name: entrypoint.name().to_owned()
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn set_plugin_state(&mut self, plugin_id: &str, enabled: bool) {
|
||||
println!("set_plugin_state {:?} {:?}", plugin_id, enabled);
|
||||
self.plugin_manager.set_plugin_state(PluginId::new(plugin_id), enabled)
|
||||
}
|
||||
|
||||
fn set_entrypoint_state(&mut self, plugin_id: &str, entrypoint_id: &str, enabled: bool) {
|
||||
println!("set_entrypoint_state {:?} {:?}", plugin_id, enabled);
|
||||
self.plugin_manager.set_entrypoint_state(PluginId::new(plugin_id), EntrypointId::new(entrypoint_id), enabled)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::server::dbus::{DbusManagementServer, DbusServer};
|
||||
use crate::server::plugins::PluginManager;
|
||||
use crate::server::search::{SearchIndex, SearchItem};
|
||||
use crate::server::search::SearchIndex;
|
||||
|
||||
pub mod dbus;
|
||||
pub(in crate::server) mod search;
|
||||
|
|
@ -19,28 +19,10 @@ pub fn start_server() {
|
|||
}
|
||||
|
||||
async fn run_server() -> anyhow::Result<()> {
|
||||
let mut plugin_manager = PluginManager::create();
|
||||
let mut search_index = SearchIndex::create_index().unwrap();
|
||||
let search_index = SearchIndex::create_index().unwrap();
|
||||
let mut plugin_manager = PluginManager::create(search_index.clone());
|
||||
|
||||
let search_items: Vec<_> = plugin_manager.plugins()
|
||||
.iter()
|
||||
.flat_map(|plugin| {
|
||||
plugin.entrypoints()
|
||||
.iter()
|
||||
.map(|entrypoint| {
|
||||
SearchItem {
|
||||
entrypoint_name: entrypoint.name().to_owned(),
|
||||
entrypoint_id: entrypoint.id().to_owned(),
|
||||
plugin_name: plugin.name().to_owned(),
|
||||
plugin_id: plugin.id().to_owned(),
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
search_index.add_entries(search_items).unwrap();
|
||||
|
||||
plugin_manager.start_all_contexts();
|
||||
plugin_manager.reload_all_plugins();
|
||||
|
||||
let interface = DbusServer { search_index };
|
||||
let management_interface = DbusManagementServer { plugin_manager };
|
||||
|
|
|
|||
|
|
@ -79,6 +79,10 @@ pub enum JsUiEvent {
|
|||
#[serde(rename = "eventName")]
|
||||
event_name: UiEventName,
|
||||
},
|
||||
PluginCommand {
|
||||
#[serde(rename = "commandType")]
|
||||
command_type: String,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::pin::{Pin};
|
||||
use std::rc::Rc;
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
|
@ -14,17 +14,35 @@ use deno_runtime::worker::WorkerOptions;
|
|||
use futures_concurrency::stream::Merge;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use crate::common::model::PluginId;
|
||||
|
||||
use crate::server::dbus::{DbusClientProxyProxy, ViewCreatedSignal, ViewEventSignal};
|
||||
use crate::server::model::{JsUiEvent, JsUiEventName, JsUiPropertyValue, JsUiWidget, JsUiWidgetId, JsUiRequestData, JsUiResponseData};
|
||||
use crate::server::plugins::Plugin;
|
||||
use crate::server::plugins::{PluginCode};
|
||||
use crate::utils::channel::{channel, RequestSender};
|
||||
|
||||
pub async fn start_js_runtime(plugin: Plugin) -> anyhow::Result<()> {
|
||||
pub struct PluginContextData {
|
||||
pub id: PluginId,
|
||||
pub code: PluginCode,
|
||||
pub command_receiver: tokio::sync::broadcast::Receiver<PluginCommand>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PluginCommand {
|
||||
pub id: PluginId,
|
||||
pub data: PluginCommandData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PluginCommandData {
|
||||
Stop
|
||||
}
|
||||
|
||||
pub async fn start_js_runtime(data: PluginContextData) -> anyhow::Result<()> {
|
||||
let conn = zbus::Connection::session().await?;
|
||||
let client_proxy = DbusClientProxyProxy::new(&conn).await?;
|
||||
|
||||
let plugin_id = plugin.id().to_owned();
|
||||
let plugin_id = data.id.clone();
|
||||
let view_created_signal = client_proxy.receive_view_created_signal()
|
||||
.await?
|
||||
.filter_map(move |signal: ViewCreatedSignal| {
|
||||
|
|
@ -33,7 +51,7 @@ pub async fn start_js_runtime(plugin: Plugin) -> anyhow::Result<()> {
|
|||
let signal = signal.args().unwrap();
|
||||
|
||||
// TODO add logging here that we received signal
|
||||
if signal.plugin_id != plugin_id {
|
||||
if PluginId::new(signal.plugin_id) != plugin_id {
|
||||
None
|
||||
} else {
|
||||
Some(JsUiEvent::ViewCreated {
|
||||
|
|
@ -44,7 +62,7 @@ pub async fn start_js_runtime(plugin: Plugin) -> anyhow::Result<()> {
|
|||
}
|
||||
});
|
||||
|
||||
let plugin_id = plugin.id().to_owned();
|
||||
let plugin_id = data.id.clone();
|
||||
let view_event_signal = client_proxy.receive_view_event_signal()
|
||||
.await?
|
||||
.filter_map(move |signal: ViewEventSignal| {
|
||||
|
|
@ -53,7 +71,7 @@ pub async fn start_js_runtime(plugin: Plugin) -> anyhow::Result<()> {
|
|||
let signal = signal.args().unwrap();
|
||||
|
||||
// TODO add logging here that we received signal
|
||||
if signal.plugin_id != plugin_id {
|
||||
if PluginId::new(signal.plugin_id) != plugin_id {
|
||||
None
|
||||
} else {
|
||||
Some(JsUiEvent::ViewEvent {
|
||||
|
|
@ -64,12 +82,42 @@ pub async fn start_js_runtime(plugin: Plugin) -> anyhow::Result<()> {
|
|||
}
|
||||
});
|
||||
|
||||
let event_stream = (view_event_signal, view_created_signal).merge();
|
||||
let mut command_receiver = data.command_receiver;
|
||||
let command_stream = async_stream::stream! {
|
||||
loop {
|
||||
yield command_receiver.recv().await.unwrap();
|
||||
}
|
||||
};
|
||||
|
||||
let plugin_id = data.id.clone();
|
||||
let command_stream = command_stream
|
||||
.filter_map(move |command: PluginCommand| {
|
||||
let plugin_id = plugin_id.clone();
|
||||
async move {
|
||||
let id = command.id;
|
||||
|
||||
// TODO add logging here that we received signal
|
||||
if id != plugin_id {
|
||||
None
|
||||
} else {
|
||||
match command.data {
|
||||
PluginCommandData::Stop => {
|
||||
Some(JsUiEvent::PluginCommand {
|
||||
command_type: "stop".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let event_stream = (view_event_signal, view_created_signal, command_stream).merge();
|
||||
|
||||
let (tx, mut rx) = channel::<JsUiRequestData, JsUiResponseData>();
|
||||
|
||||
let plugin_id: String = plugin.id().to_owned();
|
||||
let plugin_id = data.id.clone();
|
||||
tokio::spawn(tokio::task::unconstrained(async move {
|
||||
let plugin_id = plugin_id.to_string();
|
||||
println!("starting request handler loop");
|
||||
|
||||
while let Ok((request_data, responder)) = rx.recv().await {
|
||||
|
|
@ -154,7 +202,7 @@ pub async fn start_js_runtime(plugin: Plugin) -> anyhow::Result<()> {
|
|||
"plugin:unused".parse().unwrap(),
|
||||
PermissionsContainer::allow_all(),
|
||||
WorkerOptions {
|
||||
module_loader: Rc::new(CustomModuleLoader::new(plugin)),
|
||||
module_loader: Rc::new(CustomModuleLoader::new(data.code)),
|
||||
extensions: vec![react_ext::init_ops_and_esm(
|
||||
EventHandlers::new(),
|
||||
EventReceiver::new(Box::pin(event_stream)),
|
||||
|
|
@ -177,17 +225,17 @@ pub async fn start_js_runtime(plugin: Plugin) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
pub struct CustomModuleLoader {
|
||||
plugin: Plugin,
|
||||
code: PluginCode,
|
||||
static_loader: StaticModuleLoader,
|
||||
}
|
||||
|
||||
impl CustomModuleLoader {
|
||||
fn new(plugin: Plugin) -> Self {
|
||||
fn new(code: PluginCode) -> Self {
|
||||
let module_map: HashMap<_, _> = MODULES.iter()
|
||||
.map(|(key, value)| (key.parse().unwrap(), FastString::from_static(value)))
|
||||
.collect();
|
||||
Self {
|
||||
plugin,
|
||||
code,
|
||||
static_loader: StaticModuleLoader::new(module_map),
|
||||
}
|
||||
}
|
||||
|
|
@ -246,10 +294,10 @@ impl ModuleLoader for CustomModuleLoader {
|
|||
if &specifier == &"plugin:view".parse().unwrap() || &specifier == &"plugin:module".parse().unwrap() {
|
||||
let view_name = module_specifier.query().unwrap();
|
||||
|
||||
let js = self.plugin.code().js();
|
||||
let js = self.code.js();
|
||||
let js = js.get(view_name).unwrap();
|
||||
|
||||
let module = ModuleSource::new(ModuleType::JavaScript, js.to_owned().into(), module_specifier);
|
||||
let module = ModuleSource::new(ModuleType::JavaScript, js.to_string().into(), module_specifier);
|
||||
|
||||
return futures::future::ready(Ok(module)).boxed_local();
|
||||
}
|
||||
|
|
@ -270,7 +318,7 @@ deno_core::extension!(
|
|||
op_react_remove_child,
|
||||
op_react_set_properties,
|
||||
op_react_set_text,
|
||||
op_react_get_next_pending_ui_event,
|
||||
op_plugin_get_pending_event,
|
||||
op_react_call_event_listener,
|
||||
op_react_clone_instance,
|
||||
op_react_replace_container_children,
|
||||
|
|
@ -452,7 +500,7 @@ fn op_react_set_properties<'a>(
|
|||
}
|
||||
|
||||
#[op]
|
||||
async fn op_react_get_next_pending_ui_event<'a>(
|
||||
async fn op_plugin_get_pending_event<'a>(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
) -> anyhow::Result<JsUiEvent> {
|
||||
let event_stream = {
|
||||
|
|
@ -462,7 +510,7 @@ async fn op_react_get_next_pending_ui_event<'a>(
|
|||
.clone()
|
||||
};
|
||||
|
||||
println!("op_react_get_next_pending_ui_event");
|
||||
println!("op_plugin_get_pending_event");
|
||||
|
||||
let mut event_stream = event_stream.borrow_mut();
|
||||
let event = event_stream.next()
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@ use std::sync::{Arc, RwLock};
|
|||
use anyhow::Context;
|
||||
use deno_core::serde_json;
|
||||
use serde::Deserialize;
|
||||
use crate::common::dbus::{DBusEntrypoint, DBusPlugin};
|
||||
|
||||
use crate::server::plugins::js::start_js_runtime;
|
||||
use crate::common::model::{EntrypointId, PluginId};
|
||||
use crate::server::plugins::js::{PluginCommand, PluginCommandData, PluginContextData, start_js_runtime};
|
||||
use crate::server::search::{SearchIndex, SearchItem};
|
||||
|
||||
pub mod js;
|
||||
|
||||
|
|
@ -18,31 +21,175 @@ pub struct PluginManager {
|
|||
}
|
||||
|
||||
pub struct PluginManagerInner {
|
||||
plugins: Vec<Plugin>,
|
||||
plugins: HashMap<PluginId, Plugin>,
|
||||
search_index: SearchIndex,
|
||||
command_broadcaster: tokio::sync::broadcast::Sender<PluginCommand>,
|
||||
}
|
||||
|
||||
impl PluginManager {
|
||||
pub fn create() -> Self {
|
||||
let plugins = PluginLoader.load_plugins();
|
||||
pub fn create(search_index: SearchIndex) -> Self {
|
||||
let plugins = PluginLoader.load_plugins()
|
||||
.into_iter()
|
||||
.map(|plugin| (plugin.id.clone(), plugin))
|
||||
.collect();
|
||||
|
||||
let (tx, _) = tokio::sync::broadcast::channel::<PluginCommand>(100);
|
||||
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(PluginManagerInner {
|
||||
plugins,
|
||||
}))
|
||||
search_index,
|
||||
command_broadcaster: tx
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plugins(&self) -> Vec<Plugin> {
|
||||
self.inner.read().unwrap().plugins.clone()
|
||||
pub fn plugins(&self) -> Vec<DBusPlugin> {
|
||||
let plugins = &self.inner.read().unwrap().plugins;
|
||||
|
||||
plugins.iter()
|
||||
.map(|(_, plugin)| DBusPlugin {
|
||||
plugin_id: plugin.id().to_string(),
|
||||
plugin_name: plugin.name().to_owned(),
|
||||
enabled: plugin.enabled(),
|
||||
entrypoints: plugin.entrypoints()
|
||||
.into_iter()
|
||||
.map(|entrypoint| DBusEntrypoint {
|
||||
enabled: entrypoint.enabled(),
|
||||
entrypoint_id: entrypoint.id().to_string(),
|
||||
entrypoint_name: entrypoint.name().to_owned()
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn start_all_contexts(&mut self) {
|
||||
self.plugins()
|
||||
pub fn set_plugin_state(&mut self, plugin_id: PluginId, enabled: bool) {
|
||||
let mut inner = self.inner.write().unwrap();
|
||||
inner.set_plugin_state(plugin_id, enabled);
|
||||
}
|
||||
|
||||
pub fn set_entrypoint_state(&mut self, plugin_id: PluginId, entrypoint_id: EntrypointId, enabled: bool) {
|
||||
let mut inner = self.inner.write().unwrap();
|
||||
inner.set_entrypoint_state(plugin_id, entrypoint_id, enabled);
|
||||
}
|
||||
|
||||
pub fn reload_all_plugins(&mut self) {
|
||||
let mut inner = self.inner.write().unwrap();
|
||||
inner.reload_all_plugins();
|
||||
}
|
||||
}
|
||||
|
||||
impl PluginManagerInner {
|
||||
fn set_plugin_state(&mut self, plugin_id: PluginId, enabled: bool) {
|
||||
let x = self.is_plugin_enabled(&plugin_id);
|
||||
println!("set_plugin_state {:?} {:?}", x, enabled );
|
||||
match (x, enabled) {
|
||||
(false, true) => {
|
||||
self.start_plugin(plugin_id);
|
||||
},
|
||||
(true, false) => {
|
||||
self.stop_plugin(plugin_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_entrypoint_state(&mut self, plugin_id: PluginId, entrypoint_id: EntrypointId, enabled: bool) {
|
||||
let entrypoint = self.plugins.get_mut(&plugin_id)
|
||||
.unwrap()
|
||||
.entrypoints_mut()
|
||||
.iter_mut()
|
||||
.find(|entrypoint| entrypoint.id() == entrypoint_id)
|
||||
.unwrap();
|
||||
|
||||
entrypoint.enabled = enabled;
|
||||
|
||||
self.reload_search_index();
|
||||
}
|
||||
|
||||
fn reload_all_plugins(&mut self) {
|
||||
self.reload_search_index();
|
||||
|
||||
self.plugins
|
||||
.iter()
|
||||
.for_each(|plugin| self.start_context_for_plugin(plugin.clone()));
|
||||
.filter(|(_, plugin)| plugin.enabled)
|
||||
.for_each(|(_, plugin)| {
|
||||
let receiver = self.command_broadcaster.subscribe();
|
||||
|
||||
let data = PluginContextData {
|
||||
id: plugin.id(),
|
||||
code: plugin.code().clone(),
|
||||
command_receiver: receiver,
|
||||
};
|
||||
|
||||
self.start_plugin_context(data)
|
||||
});
|
||||
}
|
||||
|
||||
fn start_context_for_plugin(&self, plugin: Plugin) {
|
||||
fn is_plugin_enabled(&self, plugin_id: &PluginId) -> bool {
|
||||
let plugin = self.plugins.get(plugin_id).unwrap();
|
||||
|
||||
plugin.enabled
|
||||
}
|
||||
|
||||
fn start_plugin(&mut self, plugin_id: PluginId) {
|
||||
println!("plugin_id {:?}", plugin_id);
|
||||
let plugin = self.plugins.get_mut(&plugin_id).unwrap();
|
||||
|
||||
plugin.enabled = true;
|
||||
|
||||
let receiver = self.command_broadcaster.subscribe();
|
||||
let data = PluginContextData {
|
||||
id: plugin_id.clone(),
|
||||
code: plugin.code().clone(),
|
||||
command_receiver: receiver,
|
||||
};
|
||||
|
||||
self.reload_search_index();
|
||||
self.start_plugin_context(data)
|
||||
}
|
||||
|
||||
fn stop_plugin(&mut self, plugin_id: PluginId) {
|
||||
println!("stop_plugin {:?}", plugin_id);
|
||||
let plugin = self.plugins.get_mut(&plugin_id).unwrap();
|
||||
|
||||
plugin.enabled = false;
|
||||
|
||||
let data = PluginCommand {
|
||||
id: plugin.id(),
|
||||
data: PluginCommandData::Stop,
|
||||
};
|
||||
|
||||
self.reload_search_index();
|
||||
self.send_command(data)
|
||||
}
|
||||
|
||||
fn reload_search_index(&mut self) {
|
||||
println!("reload_search_index");
|
||||
|
||||
let search_items: Vec<_> = self.plugins
|
||||
.iter()
|
||||
.filter(|(_, plugin)| plugin.enabled)
|
||||
.flat_map(|(_, plugin)| {
|
||||
plugin.entrypoints()
|
||||
.iter()
|
||||
.filter(|entrypoint| entrypoint.enabled)
|
||||
.map(|entrypoint| {
|
||||
SearchItem {
|
||||
entrypoint_name: entrypoint.name().to_owned(),
|
||||
entrypoint_id: entrypoint.id().to_string(),
|
||||
plugin_name: plugin.name().to_owned(),
|
||||
plugin_id: plugin.id().to_string(),
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.search_index.reload(search_items).unwrap();
|
||||
}
|
||||
|
||||
fn start_plugin_context(&self, data: PluginContextData) {
|
||||
let handle = move || {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
|
|
@ -51,20 +198,24 @@ impl PluginManager {
|
|||
|
||||
let local_set = tokio::task::LocalSet::new();
|
||||
local_set.block_on(&runtime, tokio::task::unconstrained(async move {
|
||||
start_js_runtime(plugin).await
|
||||
start_js_runtime(data).await
|
||||
}))
|
||||
};
|
||||
|
||||
std::thread::Builder::new()
|
||||
.name("react-thread".into())
|
||||
.name("plugin-js-thread".into())
|
||||
.spawn(handle)
|
||||
.expect("failed to spawn react thread");
|
||||
.expect("failed to spawn plugin js thread");
|
||||
}
|
||||
|
||||
fn send_command(&self, command: PluginCommand) {
|
||||
self.command_broadcaster.send(command).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Config {
|
||||
readonly_ui: Option<bool>,
|
||||
readonly_ui: Option<bool>, // TODO 3 modes: no changes, changes saved to config, changes saved to data
|
||||
plugins: Option<Vec<PluginConfig>>,
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +286,7 @@ impl PluginLoader {
|
|||
let js_content = std::fs::read_to_string(&dist_path).unwrap();
|
||||
let id = dist_path.file_stem().unwrap().to_str().unwrap().to_owned();
|
||||
|
||||
(id, js_content)
|
||||
(id, JsCode::new(js_content))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -146,78 +297,93 @@ impl PluginLoader {
|
|||
let entrypoints: Vec<_> = package_json.plugin
|
||||
.entrypoints
|
||||
.into_iter()
|
||||
.map(|entrypoint| PluginEntrypoint::new(entrypoint.id, entrypoint.name, entrypoint.path))
|
||||
.map(|entrypoint| PluginEntrypoint::new(EntrypointId::new(entrypoint.id), entrypoint.name, entrypoint.path))
|
||||
.collect();
|
||||
|
||||
Plugin::new(&plugin.id, &package_json.plugin.metadata.name, PluginCode::new(js), entrypoints)
|
||||
Plugin::new(
|
||||
PluginId::new(plugin.id),
|
||||
&package_json.plugin.metadata.name,
|
||||
true,
|
||||
PluginCode::new(js),
|
||||
entrypoints
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Plugin {
|
||||
inner: Arc<PluginInner>,
|
||||
}
|
||||
|
||||
pub struct PluginInner {
|
||||
id: String,
|
||||
id: PluginId,
|
||||
name: String,
|
||||
enabled: bool,
|
||||
code: PluginCode,
|
||||
entrypoints: Vec<PluginEntrypoint>,
|
||||
}
|
||||
|
||||
impl Plugin {
|
||||
fn new(id: &str, name: &str, code: PluginCode, entrypoints: Vec<PluginEntrypoint>) -> Self {
|
||||
fn new(id: PluginId, name: &str, enabled: bool, code: PluginCode, entrypoints: Vec<PluginEntrypoint>) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(PluginInner {
|
||||
id: id.into(),
|
||||
name: name.into(),
|
||||
code,
|
||||
entrypoints,
|
||||
})
|
||||
id,
|
||||
name: name.into(),
|
||||
enabled,
|
||||
code,
|
||||
entrypoints,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
&self.inner.id
|
||||
pub fn id(&self) -> PluginId {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.inner.name
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
pub fn code(&self) -> &PluginCode {
|
||||
&self.inner.code
|
||||
&self.code
|
||||
}
|
||||
|
||||
pub fn entrypoints(&self) -> &Vec<PluginEntrypoint> {
|
||||
&self.inner.entrypoints
|
||||
&self.entrypoints
|
||||
}
|
||||
|
||||
pub fn entrypoints_mut(&mut self) -> &mut Vec<PluginEntrypoint> {
|
||||
&mut self.entrypoints
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginEntrypoint {
|
||||
id: String,
|
||||
id: EntrypointId,
|
||||
name: String,
|
||||
enabled: bool,
|
||||
path: String,
|
||||
}
|
||||
|
||||
impl PluginEntrypoint {
|
||||
fn new(id: String, name: String, path: String) -> Self {
|
||||
fn new(id: EntrypointId, name: String, path: String) -> Self {
|
||||
Self {
|
||||
id,
|
||||
name,
|
||||
enabled: true, // TODO load from config
|
||||
path,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
&self.id
|
||||
pub fn id(&self) -> EntrypointId {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.enabled
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
|
|
@ -225,17 +391,33 @@ impl PluginEntrypoint {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginCode {
|
||||
js: HashMap<String, String>,
|
||||
js: HashMap<String, JsCode>,
|
||||
}
|
||||
|
||||
impl PluginCode {
|
||||
fn new(js: HashMap<String, String>) -> Self {
|
||||
fn new(js: HashMap<String, JsCode>) -> Self {
|
||||
Self {
|
||||
js,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn js(&self) -> &HashMap<String, String> {
|
||||
pub fn js(&self) -> &HashMap<String, JsCode> {
|
||||
&self.js
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct JsCode(Arc<str>);
|
||||
|
||||
impl JsCode {
|
||||
pub fn new(code: impl ToString) -> Self {
|
||||
JsCode(code.to_string().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for JsCode {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
use std::thread;
|
||||
|
||||
use tantivy::{doc, Index, IndexReader, IndexWriter, ReloadPolicy, Searcher};
|
||||
use tantivy::{doc, Index, IndexReader, ReloadPolicy, Searcher};
|
||||
use tantivy::collector::TopDocs;
|
||||
use tantivy::query::{AllQuery, BooleanQuery, FuzzyTermQuery, Query};
|
||||
use tantivy::schema::*;
|
||||
use tantivy::tokenizer::TokenizerManager;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SearchIndex {
|
||||
index: Index,
|
||||
index_reader: IndexReader,
|
||||
index_writer: IndexWriter,
|
||||
|
||||
entrypoint_name: Field,
|
||||
entrypoint_id: Field,
|
||||
|
|
@ -35,11 +33,8 @@ impl SearchIndex {
|
|||
let plugin_name = schema.get_field("plugin_name").unwrap();
|
||||
let plugin_id = schema.get_field("plugin_id").unwrap();
|
||||
|
||||
|
||||
let index = Index::create_in_ram(schema.clone());
|
||||
|
||||
let index_writer = index.writer(50_000_000)?;
|
||||
|
||||
let index_reader = index
|
||||
.reader_builder()
|
||||
.reload_policy(ReloadPolicy::OnCommit)
|
||||
|
|
@ -48,7 +43,6 @@ impl SearchIndex {
|
|||
Ok(Self {
|
||||
index,
|
||||
index_reader,
|
||||
index_writer,
|
||||
entrypoint_name,
|
||||
entrypoint_id,
|
||||
plugin_name,
|
||||
|
|
@ -56,23 +50,24 @@ impl SearchIndex {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn add_entries(&mut self, entries: Vec<SearchItem>) -> tantivy::Result<()> {
|
||||
let index_writer = &mut self.index_writer;
|
||||
pub fn reload(&mut self, search_items: Vec<SearchItem>) -> tantivy::Result<()> {
|
||||
let mut index_writer = self.index.writer(50_000_000)?;
|
||||
|
||||
for entry in entries {
|
||||
index_writer.delete_all_documents()?;
|
||||
|
||||
println!("{:?}", search_items);
|
||||
|
||||
for search_item in search_items {
|
||||
index_writer.add_document(doc!(
|
||||
self.entrypoint_name => entry.entrypoint_name,
|
||||
self.entrypoint_id => entry.entrypoint_id,
|
||||
self.plugin_name => entry.plugin_name,
|
||||
self.plugin_id => entry.plugin_id,
|
||||
self.entrypoint_name => search_item.entrypoint_name,
|
||||
self.entrypoint_id => search_item.entrypoint_id,
|
||||
self.plugin_name => search_item.plugin_name,
|
||||
self.plugin_id => search_item.plugin_id,
|
||||
))?;
|
||||
}
|
||||
|
||||
index_writer.commit()?;
|
||||
|
||||
thread::sleep(std::time::Duration::from_secs(1)); // FIXME this shouldn't be needed because commit blocks, maybe inmemory index has race condition?
|
||||
println!("num_docs {:?}", self.index_reader.searcher().num_docs()); // shouldn't return 0
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,12 +25,12 @@
|
|||
},
|
||||
{
|
||||
"id": "other-view-1",
|
||||
"name": "Other view",
|
||||
"name": "Other view 1",
|
||||
"path": "src/other_view.tsx"
|
||||
},
|
||||
{
|
||||
"id": "other-view-2",
|
||||
"name": "Other view",
|
||||
"name": "Other view 2",
|
||||
"path": "src/other_view.tsx"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue