feat: Switch from smol runtime to tokio

This commit is contained in:
Michael Aaron Murphy 2022-03-27 17:38:37 +02:00 committed by Michael Murphy
parent 4153f9f060
commit dbfb3921ae
23 changed files with 242 additions and 235 deletions

178
Cargo.lock generated
View file

@ -62,17 +62,6 @@ dependencies = [
"slab",
]
[[package]]
name = "async-fs"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b3ca4f8ff117c37c278a2f7415ce9be55560b846b5bc4412aaa5d29c1c3dae2"
dependencies = [
"async-lock",
"blocking",
"futures-lite",
]
[[package]]
name = "async-io"
version = "1.6.0"
@ -101,17 +90,6 @@ dependencies = [
"event-listener",
]
[[package]]
name = "async-net"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5373304df79b9b4395068fb080369ec7178608827306ce4d081cba51cac551df"
dependencies = [
"async-io",
"blocking",
"futures-lite",
]
[[package]]
name = "async-oneshot"
version = "0.5.0"
@ -131,23 +109,6 @@ dependencies = [
"libc",
]
[[package]]
name = "async-process"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83137067e3a2a6a06d67168e49e68a0957d215410473a740cea95a2425c0b7c6"
dependencies = [
"async-io",
"blocking",
"cfg-if",
"event-listener",
"futures-lite",
"libc",
"once_cell",
"signal-hook",
"winapi",
]
[[package]]
name = "async-recursion"
version = "0.3.2"
@ -200,12 +161,6 @@ dependencies = [
"system-deps",
]
[[package]]
name = "atomic-waker"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
[[package]]
name = "autocfg"
version = "1.1.0"
@ -230,20 +185,6 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "blocking"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc"
dependencies = [
"async-channel",
"async-task",
"atomic-waker",
"fastrand",
"futures-lite",
"once_cell",
]
[[package]]
name = "bumpalo"
version = "3.9.1"
@ -784,7 +725,7 @@ dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasi 0.10.2+wasi-snapshot-preview1",
"wasm-bindgen",
]
@ -1171,6 +1112,29 @@ version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "mio"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
dependencies = [
"libc",
"log",
"miow",
"ntapi",
"wasi 0.11.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "miow"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
"winapi",
]
[[package]]
name = "nanorand"
version = "0.7.0"
@ -1203,6 +1167,15 @@ dependencies = [
"memoffset",
]
[[package]]
name = "ntapi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
dependencies = [
"winapi",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
@ -1404,13 +1377,14 @@ dependencies = [
name = "pop-launcher"
version = "1.1.1"
dependencies = [
"blocking",
"const_format",
"dirs 4.0.0",
"futures",
"serde",
"serde_json",
"serde_with",
"tokio",
"tokio-stream",
]
[[package]]
@ -1419,7 +1393,7 @@ version = "1.1.1"
dependencies = [
"pop-launcher-plugins",
"pop-launcher-service",
"smol",
"tokio",
"tracing",
"tracing-subscriber",
]
@ -1446,9 +1420,9 @@ dependencies = [
"serde",
"serde_json",
"slab",
"smol",
"strsim",
"sysfs-class",
"tokio",
"tracing",
"tracing-subscriber",
"url",
@ -1463,9 +1437,7 @@ name = "pop-launcher-service"
version = "1.1.1"
dependencies = [
"anyhow",
"async-io",
"async-oneshot",
"async-process",
"async-trait",
"flume",
"futures",
@ -1479,8 +1451,9 @@ dependencies = [
"serde_json",
"serde_with",
"slab",
"smol",
"strsim",
"tokio",
"tokio-stream",
"toml",
"tracing",
"tracing-subscriber",
@ -1775,16 +1748,6 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "signal-hook"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
@ -1817,24 +1780,6 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
[[package]]
name = "smol"
version = "1.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85cf3b5351f3e783c1d79ab5fc604eeed8b8ae9abd36b166e8b87a089efd85e4"
dependencies = [
"async-channel",
"async-executor",
"async-fs",
"async-io",
"async-lock",
"async-net",
"async-process",
"blocking",
"futures-lite",
"once_cell",
]
[[package]]
name = "socket2"
version = "0.4.4"
@ -1949,6 +1894,45 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
dependencies = [
"bytes 1.1.0",
"libc",
"memchr",
"mio",
"once_cell",
"pin-project-lite",
"signal-hook-registry",
"tokio-macros",
"winapi",
]
[[package]]
name = "tokio-macros"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio-stream"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "toml"
version = "0.5.8"
@ -2127,6 +2111,12 @@ version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.79"

View file

@ -11,10 +11,17 @@ edition = "2018"
members = ["bin", "plugins", "service"]
[dependencies]
blocking = "1.2.0"
const_format = "0.2.22"
dirs = "4.0.0"
futures = "0.3.21"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
serde_with = "1.12.0"
[dependencies.tokio]
version = "1.17.0"
features = ["io-std", "io-util"]
[dependencies.tokio-stream]
version = "0.1.8"
features = ["io-util"]

View file

@ -10,6 +10,9 @@ publish = false
[dependencies]
pop-launcher-plugins = { path = "../plugins" }
pop-launcher-service = { path = "../service" }
smol = "1.2.5"
tracing = "0.1.32"
tracing-subscriber = { version = "0.3.9", features = ["env-filter"] }
[dependencies.tokio]
version = "1.17.0"
features = ["rt"]

View file

@ -3,10 +3,10 @@
use pop_launcher_plugins as plugins;
use pop_launcher_service as service;
use smol::block_on;
use std::io;
fn main() {
#[tokio::main(flavor = "current_thread")]
async fn main() {
tracing_subscriber::fmt()
.with_writer(io::stderr)
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
@ -16,17 +16,17 @@ fn main() {
let start = plugin.rfind('/').map(|v| v + 1).unwrap_or(0);
let cmd = &plugin.as_str()[start..];
match cmd {
"calc" => block_on(plugins::calc::main()),
"desktop-entries" => block_on(plugins::desktop_entries::main()),
"find" => block_on(plugins::find::main()),
"files" => block_on(plugins::files::main()),
"pop-launcher" => block_on(service::main()),
"pop-shell" => block_on(plugins::pop_shell::main()),
"pulse" => block_on(plugins::pulse::main()),
"recent" => block_on(plugins::recent::main()),
"scripts" => block_on(plugins::scripts::main()),
"terminal" => block_on(plugins::terminal::main()),
"web" => block_on(plugins::web::main()),
"calc" => plugins::calc::main().await,
"desktop-entries" => plugins::desktop_entries::main().await,
"find" => plugins::find::main().await,
"files" => plugins::files::main().await,
"pop-launcher" => service::main().await,
"pop-shell" => plugins::pop_shell::main().await,
"pulse" => plugins::pulse::main().await,
"recent" => plugins::recent::main().await,
"scripts" => plugins::scripts::main().await,
"terminal" => plugins::terminal::main().await,
"web" => plugins::web::main().await,
unknown => {
eprintln!("unknown cmd: {}", unknown);
}

1
debian/rules vendored
View file

@ -2,6 +2,7 @@
VENDOR ?= 1
CLEAN ?= 1
DEBUG ?= 0
DESTDIR=debian/tmp
%:

View file

@ -20,7 +20,6 @@ ron = "0.7.0"
serde = "1.0.136"
serde_json = "1.0.79"
slab = "0.4.5"
smol = "1.2.5"
strsim = "0.10.0"
tracing = "0.1.32"
tracing-subscriber = "0.3.9"
@ -35,3 +34,7 @@ anyhow = "1.0.56"
flume = "0.10.12"
dirs = "4.0.0"
futures = "0.3.21"
[dependencies.tokio]
version = "1.17.0"
features = ["fs", "io-std", "macros", "process", "rt"]

View file

@ -1,14 +1,14 @@
// SPDX-License-Identifier: GPL-3.0-only
// Copyright © 2021 System76
use futures::{AsyncBufReadExt, AsyncWriteExt, StreamExt};
use futures::StreamExt;
use pop_launcher::*;
use regex::Regex;
use smol::{
process::{Command, Stdio},
Unblock,
use std::{borrow::Cow, io, process::Stdio};
use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt},
process::Command,
};
use std::{borrow::Cow, io};
pub async fn main() {
let mut requests = json_input_stream(async_stdin());
@ -37,7 +37,7 @@ pub async fn main() {
pub struct App {
pub decimal_comma: bool,
out: Unblock<io::Stdout>,
out: tokio::io::Stdout,
outcome: Option<String>,
regex: Regex,
}
@ -158,14 +158,17 @@ async fn qcalc(regex: &mut Regex, expression: &str, decimal_comma: bool) -> Opti
}
};
let mut reader = futures::io::BufReader::new(stdout).lines().skip(2);
let mut reader = tokio::io::BufReader::new(stdout).lines();
let mut output = String::new();
let _ = reader.next_line().await;
let _ = reader.next_line().await;
fn has_issue(line: &str) -> bool {
line.starts_with("error") || line.starts_with("warning")
}
while let Some(Ok(line)) = reader.next().await {
while let Ok(Some(line)) = reader.next_line().await {
let line = line.trim();
if line.is_empty() {
@ -260,9 +263,9 @@ mod tests {
);
}
#[test]
fn approximate_result_formatting() {
let task = smol::spawn(async {
#[tokio::test]
async fn approximate_result_formatting() {
let task = tokio::spawn(async {
let mut app = App {
decimal_comma: false,
..Default::default()
@ -271,10 +274,8 @@ mod tests {
app.outcome.take()
});
smol::block_on(async {
if let Some(result) = task.await {
assert_eq!("≈ 2.333333333", result);
}
})
if let Some(result) = task.await.unwrap() {
assert_eq!("≈ 2.333333333", result);
}
}
}

View file

@ -5,11 +5,12 @@ mod graphics;
use crate::*;
use freedesktop_desktop_entry::{default_paths, DesktopEntry, Iter as DesktopIter, PathSource};
use futures::{AsyncWrite, StreamExt};
use futures::StreamExt;
use pop_launcher::*;
use std::borrow::Cow;
use std::hash::{Hash, Hasher};
use std::path::PathBuf;
use tokio::io::AsyncWrite;
#[derive(Debug, Eq)]
struct Item {

View file

@ -3,8 +3,7 @@
use futures::prelude::*;
use pop_launcher::*;
use smol::Unblock;
use std::{collections::BTreeMap, io, path::PathBuf};
use std::{collections::BTreeMap, path::PathBuf};
#[derive(Clone)]
struct Item {
@ -38,7 +37,7 @@ pub async fn main() {
pub struct App {
entries: BTreeMap<PathBuf, Vec<Item>>,
home: PathBuf,
out: Unblock<io::Stdout>,
out: tokio::io::Stdout,
search_results: Vec<Item>,
}

View file

@ -3,11 +3,13 @@
use futures::*;
use pop_launcher::*;
use smol::process::{Child, ChildStdout, Command, Stdio};
use std::cell::Cell;
use std::io;
use std::path::PathBuf;
use std::process::Stdio;
use std::rc::Rc;
use tokio::io::AsyncBufReadExt;
use tokio::process::{Child, ChildStdout, Command};
enum Event {
Activate(u32),
@ -37,12 +39,10 @@ pub async fn main() {
Event::Activate(id) => {
if let Some(selection) = app.search_results.get(id as usize) {
let path = selection.clone();
let handle = smol::spawn(async move {
tokio::spawn(async move {
crate::xdg_open(&path);
});
handle.detach();
crate::send(&mut app.out, PluginResponse::Close).await;
}
}
@ -114,7 +114,7 @@ pub async fn main() {
struct SearchContext {
pub active: Rc<Cell<bool>>,
pub interrupt_rx: flume::Receiver<()>,
pub out: smol::Unblock<io::Stdout>,
pub out: tokio::io::Stdout,
pub search_results: Vec<PathBuf>,
}
@ -148,7 +148,7 @@ impl SearchContext {
tracing::debug!("searching for {}", search);
let (mut child, mut stdout) = match query(&search).await {
Ok((child, stdout)) => (child, futures::io::BufReader::new(stdout).lines()),
Ok((child, stdout)) => (child, tokio::io::BufReader::new(stdout).lines()),
Err(why) => {
tracing::error!("failed to spawn fdfind process: {}", why);
@ -176,19 +176,16 @@ impl SearchContext {
'stream: loop {
let interrupt = async {
let _ = self.interrupt_rx.recv_async().await;
None
Ok(None)
};
match crate::or(interrupt, stdout.next()).await {
Some(result) => match result {
Ok(line) => append = line,
Err(why) => {
tracing::error!("error on stdout line read: {}", why);
break 'stream;
}
},
None => break 'stream,
match crate::or(interrupt, stdout.next_line()).await {
Ok(Some(line)) => append = line,
Ok(None) => break 'stream,
Err(why) => {
tracing::error!("error on stdout line read: {}", why);
break 'stream;
}
}
self.append(id, append).await;
@ -201,7 +198,7 @@ impl SearchContext {
}
let _ = child.kill();
let _ = child.status().await;
let _ = child.wait().await;
}
}

View file

@ -12,9 +12,9 @@ pub mod scripts;
pub mod terminal;
pub mod web;
use futures::{AsyncWrite, AsyncWriteExt};
use pop_launcher::PluginResponse;
use std::{borrow::Cow, ffi::OsStr, future::Future, path::Path};
use tokio::io::{AsyncWrite, AsyncWriteExt};
pub async fn send<W: AsyncWrite + Unpin>(tx: &mut W, response: PluginResponse) {
if let Ok(mut bytes) = serde_json::to_string(&response) {
@ -47,5 +47,5 @@ pub fn mime_from_path(path: &Path) -> Cow<'static, str> {
/// Launches a file with its default appplication via `xdg-open`.
pub fn xdg_open<S: AsRef<OsStr>>(file: S) {
let _ = smol::process::Command::new("xdg-open").arg(file).spawn();
let _ = tokio::process::Command::new("xdg-open").arg(file).spawn();
}

View file

@ -3,10 +3,11 @@
use crate::*;
use freedesktop_desktop_entry as fde;
use futures::{AsyncWrite, AsyncWriteExt, StreamExt};
use futures::StreamExt;
use pop_launcher::*;
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, fs, path::PathBuf, sync::Arc};
use tokio::io::{AsyncWrite, AsyncWriteExt};
use zbus::Connection;
use zvariant::{Signature, Type};

View file

@ -4,7 +4,6 @@
use async_pidfd::AsyncPidFd;
use futures::prelude::*;
use pop_launcher::*;
use smol::Unblock;
use std::io;
struct Selection {
@ -15,7 +14,7 @@ struct Selection {
pub struct App {
selections: Vec<Selection>,
out: Unblock<io::Stdout>,
out: tokio::io::Stdout,
}
impl Default for App {
@ -77,7 +76,7 @@ impl App {
let sinks = pactl_sinks();
while let Ok(id) = sinks.recv_async().await {
handles.push(smol::spawn(async move {
handles.push(tokio::spawn(async move {
let args = &[arg1, id.as_str(), arg2];
let _ = command_spawn(cmd, args).await;
}));
@ -136,25 +135,25 @@ async fn command_spawn(cmd: &str, args: &[&str]) -> io::Result<()> {
fn pactl_sinks() -> flume::Receiver<String> {
let (tx, rx) = flume::bounded(4);
smol::spawn(async move {
let child = smol::process::Command::new("pactl")
tokio::spawn(async move {
let child = tokio::process::Command::new("pactl")
.env("LANG", "C")
.args(&["list", "sinks"])
.stdout(smol::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.spawn();
if let Ok(mut child) = child {
if let Some(stdout) = child.stdout.take() {
let mut lines = futures::io::BufReader::new(stdout).lines();
while let Some(Ok(line)) = lines.next().await {
use tokio::io::AsyncBufReadExt;
let mut lines = tokio::io::BufReader::new(stdout).lines();
while let Ok(Some(line)) = lines.next_line().await {
if let Some(stripped) = line.strip_prefix("Sink #") {
let _ = tx.send_async(stripped.trim().to_owned()).await;
}
}
}
}
})
.detach();
});
rx
}

View file

@ -5,12 +5,11 @@ use futures::prelude::*;
use gtk::prelude::*;
use pop_launcher::*;
use slab::Slab;
use smol::Unblock;
use std::{borrow::Cow, io};
use std::borrow::Cow;
pub struct App {
manager: gtk::RecentManager,
out: Unblock<io::Stdout>,
out: tokio::io::Stdout,
uris: Slab<String>,
}

View file

@ -5,13 +5,12 @@ use crate::*;
use pop_launcher::*;
use flume::Sender;
use futures::{AsyncBufReadExt, StreamExt};
use smol::process::{Command, Stdio};
use futures::StreamExt;
use std::collections::VecDeque;
use std::{
io,
path::{Path, PathBuf},
};
use std::path::{Path, PathBuf};
use std::process::Stdio;
use tokio::io::AsyncBufReadExt;
use tokio::process::Command;
const LOCAL_PATH: &str = ".local/share/pop-launcher/scripts";
const SYSTEM_ADMIN_PATH: &str = "/etc/pop-launcher/scripts";
@ -42,7 +41,7 @@ pub async fn main() {
pub struct App {
scripts: Vec<ScriptInfo>,
out: smol::Unblock<io::Stdout>,
out: tokio::io::Stdout,
}
impl App {
@ -156,9 +155,9 @@ async fn load_from(path: &Path, paths: &mut VecDeque<PathBuf>, tx: Sender<Script
continue;
}
smol::spawn(async move {
let mut file = match smol::fs::File::open(&path).await {
Ok(file) => futures::io::BufReader::new(file).lines(),
tokio::spawn(async move {
let mut file = match tokio::fs::File::open(&path).await {
Ok(file) => tokio::io::BufReader::new(file).lines(),
Err(why) => {
tracing::error!("cannot open script at {}: {}", path.display(), why);
return;
@ -172,7 +171,7 @@ async fn load_from(path: &Path, paths: &mut VecDeque<PathBuf>, tx: Sender<Script
let mut first = true;
while let Some(Ok(line)) = file.next().await {
while let Ok(Some(line)) = file.next_line().await {
if !line.starts_with('#') {
break;
}
@ -200,8 +199,7 @@ async fn load_from(path: &Path, paths: &mut VecDeque<PathBuf>, tx: Sender<Script
}
let _ = tx.send_async(info).await;
})
.detach();
});
}
}
}

View file

@ -3,12 +3,11 @@
use futures::prelude::*;
use pop_launcher::*;
use smol::Unblock;
use std::{io, path::PathBuf};
use std::path::PathBuf;
pub struct App {
last_query: Option<String>,
out: Unblock<io::Stdout>,
out: tokio::io::Stdout,
shell_only: bool,
}

View file

@ -2,7 +2,6 @@
// Copyright © 2021 System76
use std::borrow::Cow;
use std::io;
use std::path::{Path, PathBuf};
use std::time::Duration;
@ -11,7 +10,6 @@ use futures::StreamExt;
use isahc::config::{Configurable, RedirectPolicy};
use isahc::http::header::CONTENT_TYPE;
use isahc::{AsyncReadResponseExt, HttpClient};
use smol::Unblock;
use url::Url;
use pop_launcher::*;
@ -42,7 +40,7 @@ pub async fn main() {
pub struct App {
config: Config,
queries: Vec<String>,
out: Unblock<io::Stdout>,
out: tokio::io::Stdout,
client: HttpClient,
cache: PathBuf,
}
@ -145,7 +143,7 @@ impl App {
let favicon_path = favicon_path.to_path_buf();
smol::spawn(async move {
tokio::spawn(async move {
let favicon_url = favicon_url_from_page_source(&domain, &client)
.await
.unwrap_or_else(|| {
@ -162,15 +160,14 @@ impl App {
std::fs::create_dir_all(cache_dir).expect("error creating cache directory");
}
let copy = smol::fs::write(&favicon_path, icon).await;
let copy = tokio::fs::write(&favicon_path, icon).await;
if let Err(err) = copy {
tracing::error!("error writing favicon to {:?}: {}", &favicon_path, err);
}
}
None => tracing::error!("no icon found for {}", domain),
}
})
.detach();
});
}
}

View file

@ -5,25 +5,30 @@ license = "MPL-2.0"
edition = "2018"
[dependencies]
anyhow = "1.0.55"
async-io = "1.6.0"
anyhow = "1.0.56"
async-oneshot = "0.5.0"
async-trait = "0.1.52"
async-trait = "0.1.53"
futures = "0.3.21"
futures_codec = "0.4.1"
gen-z = "0.1.0"
num_cpus = "1.13.1"
pop-launcher = { path = "../" }
regex = "1.5.4"
regex = "1.5.5"
ron = "0.7.0"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
serde_with = "1.12.0"
slab = "0.4.5"
smol = "1.2.5"
strsim = "0.10.0"
toml = "0.5.8"
tracing = "0.1.31"
tracing = "0.1.32"
tracing-subscriber = { version = "0.3.9", features = ["fmt"] }
async-process = "1.3.0"
flume = "0.10.12"
[dependencies.tokio]
version = "1.17.0"
features = ["io-std", "process", "rt"]
[dependencies.tokio-stream]
version = "0.1.8"
features = ["io-util"]

View file

@ -1,10 +1,12 @@
// Copyright 2021 System76 <info@system76.com>
// SPDX-License-Identifier: MPL-2.0
use async_process as process;
use futures::{AsyncBufReadExt, AsyncWriteExt, Stream, StreamExt};
use futures::{Stream, StreamExt};
use pop_launcher::{Request, Response};
use std::io;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt};
use tokio::process;
use tokio_stream::wrappers::LinesStream;
pub struct IpcClient {
pub child: process::Child,
@ -14,8 +16,8 @@ pub struct IpcClient {
impl IpcClient {
pub fn new() -> io::Result<(Self, impl Stream<Item = Response>)> {
let mut child = process::Command::new("pop-launcher")
.stdin(process::Stdio::piped())
.stdout(process::Stdio::piped())
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.spawn()?;
let stdin = child
@ -28,18 +30,17 @@ impl IpcClient {
.take()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "failed to find child stdout"))?;
let responses =
futures::io::BufReader::new(stdout)
.lines()
.filter_map(|result| async move {
if let Ok(line) = result {
if let Ok(event) = serde_json::from_str::<Response>(&line) {
return Some(event);
}
let responses = LinesStream::new(tokio::io::BufReader::new(stdout).lines()).filter_map(
|result| async move {
if let Ok(line) = result {
if let Ok(event) = serde_json::from_str::<Response>(&line) {
return Some(event);
}
}
None
});
None
},
);
let client = Self { child, stdin };
@ -57,6 +58,6 @@ impl IpcClient {
pub async fn exit(mut self) {
let _ = self.send(Request::Exit).await;
let _ = self.child.status().await;
let _ = self.child.wait().await;
}
}

View file

@ -34,7 +34,7 @@ pub struct PluginHelp {
pub async fn main() {
// Listens for a stream of requests from stdin.
let input_stream = json_input_stream(async_stdin()).filter_map(|result| {
let input_stream = json_input_stream(tokio::io::stdin()).filter_map(|result| {
future::ready(match result {
Ok(request) => Some(request),
Err(why) => {
@ -124,7 +124,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
futures::pin_mut!(f1);
futures::pin_mut!(f2);
futures::future::select(f1, f2).await.factor_first().0;
let _ = futures::future::select(f1, f2).await.factor_first().0;
}
async fn response_handler(&mut self, service_rx: Receiver<Event>) {
@ -229,10 +229,9 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
let init = init.clone();
let service_tx = service_tx.clone();
smol::spawn(async move {
tokio::spawn(async move {
init(id, service_tx).run(request_rx).await;
})
.detach();
});
request_tx
}),

View file

@ -15,10 +15,10 @@ pub fn from_paths() -> impl Stream<Item = (PathBuf, PluginConfig, Option<Regex>)
stream::iter(crate::plugin_paths())
.flat_map(|path| from_path(path.to_path_buf()))
.map(|(source, config)| {
smol::unblock(move || crate::plugins::config::load(&source, &config))
tokio::task::spawn_blocking(move || crate::plugins::config::load(&source, &config))
})
.buffered(num_cpus::get())
.filter_map(|x| async move { x })
.filter_map(|x| async move { x.ok().flatten() })
}
/// Loads all plugin information found in the given path.

View file

@ -6,6 +6,7 @@ pub mod load;
use std::{
io,
path::PathBuf,
process::Stdio,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
@ -15,10 +16,11 @@ use std::{
use crate::{Event, Indice, Plugin, PluginResponse, Request};
use async_oneshot::oneshot;
use flume::Sender;
use futures::{AsyncWriteExt, StreamExt};
use smol::{
process::{Child, Command, Stdio},
Task,
use futures::StreamExt;
use tokio::{
io::AsyncWriteExt,
process::{Child, Command},
task::JoinHandle,
};
use tracing::{event, Level};
@ -28,7 +30,7 @@ pub struct ExternalPlugin {
name: String,
pub cmd: PathBuf,
pub args: Vec<String>,
process: Option<(Task<()>, Child, async_oneshot::Sender<()>)>,
process: Option<(JoinHandle<()>, Child, async_oneshot::Sender<()>)>,
detached: Arc<AtomicBool>,
searching: Arc<AtomicBool>,
}
@ -53,7 +55,7 @@ impl ExternalPlugin {
}
}
pub fn launch(&mut self) -> Option<&mut (Task<()>, Child, async_oneshot::Sender<()>)> {
pub fn launch(&mut self) -> Option<&mut (JoinHandle<()>, Child, async_oneshot::Sender<()>)> {
event!(Level::DEBUG, "{}: launching plugin", self.name());
let child = Command::new(&self.cmd)
@ -74,7 +76,7 @@ impl ExternalPlugin {
let id = self.id;
// Spawn a background task to forward JSON responses from the child process.
let task = smol::spawn(async move {
let task = tokio::spawn(async move {
let tx_ = tx.clone();
let searching_ = searching.clone();
let name_ = name.clone();
@ -105,7 +107,13 @@ impl ExternalPlugin {
let _ = trip_rx.await;
};
let _ = crate::or(responder, trip).await;
futures::pin_mut!(responder);
futures::pin_mut!(trip);
let _ = futures::future::select(responder, trip)
.await
.factor_first()
.0;
// Ensure that a task that was searching sends a finished signal if it dies.
if searching.swap(false, Ordering::SeqCst) {
@ -128,9 +136,9 @@ impl ExternalPlugin {
pub async fn process_check(&mut self) {
if let Some(mut child) = self.process.take() {
match child.1.try_status() {
match child.1.try_wait() {
Err(_) | Ok(Some(_)) => {
child.0.cancel().await;
child.0.abort();
}
Ok(None) => self.process = Some(child),
}

View file

@ -1,19 +1,18 @@
// Copyright 2021 System76 <info@system76.com>
// SPDX-License-Identifier: MPL-2.0
use blocking::Unblock;
use futures::{AsyncBufReadExt, AsyncRead, Stream, StreamExt};
use futures::{Stream, StreamExt};
use serde::Deserialize;
use std::io;
use tokio::io::{AsyncBufReadExt, AsyncRead};
/// stdin with AsyncRead support
pub fn async_stdin() -> Unblock<io::Stdin> {
Unblock::new(io::stdin())
pub fn async_stdin() -> tokio::io::Stdin {
tokio::io::stdin()
}
/// stdout with AsyncWrite support
pub fn async_stdout() -> Unblock<io::Stdout> {
Unblock::new(io::stdout())
pub fn async_stdout() -> tokio::io::Stdout {
tokio::io::stdout()
}
/// Creates a stream that parses JSON input line-by-line
@ -22,8 +21,8 @@ where
I: AsyncRead + Unpin + Send,
S: for<'a> Deserialize<'a>,
{
futures::io::BufReader::new(input)
.lines()
let line_reader = tokio::io::BufReader::new(input).lines();
tokio_stream::wrappers::LinesStream::new(line_reader)
.take_while(|x| futures::future::ready(x.is_ok()))
.map(Result::unwrap)
.map(|line| serde_json::from_str::<S>(&line))