improv(service): Load plugins from all paths in parallel

This commit is contained in:
Michael Aaron Murphy 2021-08-15 13:23:47 +02:00
parent 2c14701898
commit 251dcd5b2c
3 changed files with 33 additions and 43 deletions

View file

@ -1,7 +1,7 @@
mod plugins; mod plugins;
use pop_launcher::*;
use crate::plugins::*; use crate::plugins::*;
use pop_launcher::*;
use flume::{unbounded, Receiver, Sender}; use flume::{unbounded, Receiver, Sender};
use futures_lite::{future, StreamExt}; use futures_lite::{future, StreamExt};
@ -321,7 +321,10 @@ impl<O: Write> Service<O> {
} }
/// From a given position ID, fetch the search result and its associated plugin /// From a given position ID, fetch the search result and its associated plugin
fn search_result(&mut self, id: usize) -> Option<(&mut PluginConnector, &mut PluginSearchResult)> { fn search_result(
&mut self,
id: usize,
) -> Option<(&mut PluginConnector, &mut PluginSearchResult)> {
let &mut Self { let &mut Self {
ref mut active_search, ref mut active_search,
ref mut plugins, ref mut plugins,

View file

@ -1,57 +1,44 @@
use crate::PluginConfig; use crate::PluginConfig;
use flume::Sender; use flume::Sender;
use futures_lite::{Stream, StreamExt}; use futures_lite::{future::zip, Stream, StreamExt};
use regex::Regex; use regex::Regex;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
/// Fetches plugins installed on the system in parallel. /// Fetches plugins installed on the system in parallel.
///
/// Searches plugin paths from highest to least priority. User plugins will override
/// distribution plugins. Plugins are loaded in the order they are found.
pub async fn from_paths(tx: Sender<(PathBuf, PluginConfig, Option<Regex>)>) { pub async fn from_paths(tx: Sender<(PathBuf, PluginConfig, Option<Regex>)>) {
const PLUGIN_PATHS: &[&str] = &[ let (tasks_tx, tasks_rx) = flume::unbounded();
// User plugins
".local/share/pop-launcher/plugins/",
// System plugins configured by admin
"/etc/pop-launcher/plugins/",
// Distribution plugins
"/usr/lib/pop-launcher/plugins/",
];
let mut futures = Vec::new(); // Spawns a background task to run in parallel for each plugin found
let task_spawner = async move {
for path in crate::plugin_paths() {
let loadable_plugins = from_path(&path);
futures_lite::pin!(loadable_plugins);
// Searches plugin paths from highest to least priority. while let Some((source, config)) = loadable_plugins.next().await {
// User plugins will override distribution plugins. let future = smol::unblock(move || crate::plugins::config::load(&source, &config));
for path in PLUGIN_PATHS { if tasks_tx.send_async(smol::spawn(future)).await.is_err() {
let path_buf; break;
#[allow(deprecated)]
let path = if !path.starts_with('/') {
path_buf = std::env::home_dir()
.expect("user does not have home dir")
.join(path);
path_buf.as_path()
} else {
Path::new(&path)
};
let loadable_plugins = from_path(path);
futures_lite::pin!(loadable_plugins);
// Spawn a background task to parse the config for each plugin found.
while let Some((source, config)) = loadable_plugins.next().await {
let tx = tx.clone();
let future = smol::unblock(move || {
if let Some(plugin) = crate::plugins::config::load(&source, &config) {
let _ = tx.send(plugin);
} }
}); }
futures.push(smol::spawn(future))
} }
};
// Ensures that plugins are loaded in the order that they were spawned. // This future ensures that plugins are returned in the order they were spawned.
for future in futures.drain(..) { let task_listener = async move {
future.await; while let Ok(task) = tasks_rx.recv_async().await {
if let Some(plugin) = task.await {
if tx.send_async(plugin).await.is_err() {
break;
}
}
} }
} };
zip(task_spawner, task_listener).await;
} }
/// Loads all plugin information found in the given path. /// Loads all plugin information found in the given path.

View file

@ -1,6 +1,6 @@
use crate::*; use crate::*;
use pop_launcher::*;
use flume::Sender; use flume::Sender;
use pop_launcher::*;
use slab::Slab; use slab::Slab;
use std::borrow::Cow; use std::borrow::Cow;