mirror of
https://github.com/arabianq/pipewire-soundpad.git
synced 2026-06-19 04:03:33 +00:00
Refactor to Cargo Workspace (#129)
* Refactor project into a Cargo workspace with distinct packages - Created a root `Cargo.toml` defining a workspace. - Moved `src/types` and `src/utils` into a new `pwsp-lib` crate for shared logic. - Split binaries into their own crates: `pwsp-daemon`, `pwsp-cli`, and `pwsp-gui`. - Shifted all dependencies into `[workspace.dependencies]` for centralized version management. - Updated import paths across all crates (e.g. from `pwsp::` to `pwsp_lib::`). - Updated build scripts, GitHub actions, Flatpak manifest, and AUR PKGBUILD to support the new workspace structure. - Ensured no core application logic was altered. Co-authored-by: arabianq <55220741+arabianq@users.noreply.github.com> * Fix cargo-deb build process in GitHub actions for workspace architecture Co-authored-by: arabianq <55220741+arabianq@users.noreply.github.com> * Fix cargo-deb asset discovery by using exact target/release paths Co-authored-by: arabianq <55220741+arabianq@users.noreply.github.com> * refactor deps in Cargo.toml files * fix incorrect assets path --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
6c59137639
commit
0476329798
@@ -42,7 +42,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
BIN_NAMES=$(cargo metadata --no-deps --format-version 1 \
|
||||
| jq -r '.packages[0].targets[] | select(.kind[] | contains("bin")) | .name')
|
||||
| jq -r '.packages[].targets[] | select(.kind[] | contains("bin")) | .name')
|
||||
echo "bin_names<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "$BIN_NAMES" >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
@@ -93,7 +93,8 @@ jobs:
|
||||
cargo install --locked cargo-deb
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
|
||||
cargo-deb
|
||||
cargo build --release --locked
|
||||
cargo-deb -p pwsp-gui
|
||||
|
||||
- name: Upload .deb(s) as artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
BIN_NAMES=$(cargo metadata --no-deps --format-version 1 \
|
||||
| jq -r '.packages[0].targets[] | select(.kind[] | contains("bin")) | .name')
|
||||
| jq -r '.packages[].targets[] | select(.kind[] | contains("bin")) | .name')
|
||||
echo "bin_names<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "$BIN_NAMES" >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
@@ -146,7 +146,8 @@ jobs:
|
||||
cargo install --locked cargo-deb
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
|
||||
cargo-deb
|
||||
cargo build --release --locked
|
||||
cargo-deb -p pwsp-gui
|
||||
|
||||
- name: Upload .deb(s) to release
|
||||
uses: softprops/action-gh-release@v2
|
||||
|
||||
Generated
+43
-7
@@ -3279,28 +3279,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
|
||||
|
||||
[[package]]
|
||||
name = "pwsp"
|
||||
name = "pwsp-cli"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"clap",
|
||||
"dirs",
|
||||
"pwsp-lib",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pwsp-daemon"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"pipewire",
|
||||
"pwsp-lib",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pwsp-gui"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"eframe",
|
||||
"egui",
|
||||
"egui_dnd",
|
||||
"egui_extras",
|
||||
"egui_material_icons",
|
||||
"evdev",
|
||||
"itertools 0.14.0",
|
||||
"opener",
|
||||
"percent-encoding",
|
||||
"pipewire",
|
||||
"pwsp-lib",
|
||||
"reqwest",
|
||||
"rfd",
|
||||
"rodio",
|
||||
"rust-i18n",
|
||||
"rustix 1.1.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sys-locale",
|
||||
@@ -3308,6 +3325,25 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pwsp-lib"
|
||||
version = "1.10.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"dirs",
|
||||
"egui",
|
||||
"evdev",
|
||||
"itertools 0.14.0",
|
||||
"pipewire",
|
||||
"reqwest",
|
||||
"rodio",
|
||||
"rustix 1.1.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.29"
|
||||
|
||||
+16
-52
@@ -1,17 +1,28 @@
|
||||
[package]
|
||||
name = "pwsp"
|
||||
[workspace]
|
||||
members = [
|
||||
"pwsp-lib",
|
||||
"pwsp-daemon",
|
||||
"pwsp-cli",
|
||||
"pwsp-gui"
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "1.10.0"
|
||||
edition = "2024"
|
||||
authors = ["arabian"]
|
||||
description = "PWSP lets you play audio files through your microphone. Has both CLI and GUI clients."
|
||||
readme = "README.md"
|
||||
homepage = "https://pwsp.arabianq.ru"
|
||||
repository = "https://github.com/arabianq/pipewire-soundpad"
|
||||
license = "MIT"
|
||||
description = "PWSP lets you play audio files through your microphone. Has both CLI and GUI clients."
|
||||
keywords = ["soundpad", "pipewire", "linux", "cli", "gui"]
|
||||
|
||||
[workspace.dependencies]
|
||||
pwsp-lib = { path = "pwsp-lib" }
|
||||
pwsp-daemon = { path = "pwsp-daemon" }
|
||||
pwsp-cli = { path = "pwsp-cli" }
|
||||
pwsp-gui = { path = "pwsp-gui" }
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.52.3", features = ["full"] }
|
||||
async-trait = "0.1.89"
|
||||
|
||||
@@ -31,9 +42,7 @@ dirs = "6.0.0"
|
||||
itertools = "0.14.0"
|
||||
evdev = { version = "0.13.2", features = ["tokio"] }
|
||||
rfd = { version = "0.17.2", default-features = false, features = [
|
||||
|
||||
"xdg-portal",
|
||||
|
||||
] }
|
||||
opener = { version = "0.8.4", features = ["reveal"] }
|
||||
system-fonts = "0.1.1"
|
||||
@@ -67,18 +76,6 @@ egui_dnd = "0.15.0"
|
||||
reqwest = "0.13.4"
|
||||
percent-encoding = "2.3.2"
|
||||
|
||||
[[bin]]
|
||||
name = "pwsp-daemon"
|
||||
path = "src/bin/daemon.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "pwsp-cli"
|
||||
path = "src/bin/cli.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "pwsp-gui"
|
||||
path = "src/main.rs"
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
lto = true
|
||||
@@ -86,36 +83,3 @@ codegen-units = 1
|
||||
opt-level = "z"
|
||||
panic = "abort"
|
||||
|
||||
[package.metadata.deb]
|
||||
assets = [
|
||||
[
|
||||
"target/release/pwsp-daemon",
|
||||
"usr/bin/",
|
||||
"755",
|
||||
],
|
||||
[
|
||||
"target/release/pwsp-cli",
|
||||
"usr/bin/",
|
||||
"755",
|
||||
],
|
||||
[
|
||||
"target/release/pwsp-gui",
|
||||
"usr/bin/",
|
||||
"755",
|
||||
],
|
||||
[
|
||||
"assets/pwsp-gui.desktop",
|
||||
"usr/share/applications/pwsp.desktop",
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"assets/icon.png",
|
||||
"usr/share/icons/hicolor/256x256/apps/pwsp.png",
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"assets/pwsp-daemon.service",
|
||||
"usr/lib/systemd/user/pwsp-daemon.service",
|
||||
"644",
|
||||
],
|
||||
]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
<h1>🎵 PipeWire Soundpad (PWSP)</h1>
|
||||
<p><b>A simple, modern, and powerful soundboard for Linux, written in Rust.</b></p>
|
||||
<img src="assets/screenshot.png" alt="PWSP Screenshot" width="700"/>
|
||||
<img src="pwsp-gui/assets/screenshot.png" alt="PWSP Screenshot" width="700"/>
|
||||
</div>
|
||||
|
||||
## 🌟 Overview
|
||||
|
||||
@@ -40,8 +40,8 @@ package() {
|
||||
install -Dm755 "target/release/pwsp-daemon" "${pkgdir}/usr/bin/pwsp-daemon"
|
||||
install -Dm755 "target/release/pwsp-gui" "${pkgdir}/usr/bin/pwsp-gui"
|
||||
|
||||
install -Dm644 "assets/pwsp-gui.desktop" "${pkgdir}/usr/share/applications/pwsp-gui.desktop"
|
||||
install -Dm644 "assets/icon.png" "${pkgdir}/usr/share/icons/hicolor/256x256/apps/pwsp.png"
|
||||
install -Dm644 "pwsp-gui/assets/pwsp-gui.desktop" "${pkgdir}/usr/share/applications/pwsp-gui.desktop"
|
||||
install -Dm644 "pwsp-gui/assets/icon.png" "${pkgdir}/usr/share/icons/hicolor/256x256/apps/pwsp.png"
|
||||
|
||||
install -Dm644 "assets/pwsp-daemon.service" "${pkgdir}/usr/lib/systemd/user/pwsp-daemon.service"
|
||||
install -Dm644 "pwsp-gui/assets/pwsp-daemon.service" "${pkgdir}/usr/lib/systemd/user/pwsp-daemon.service"
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<launchable type="desktop-id">ru.arabianq.pwsp.desktop</launchable>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://raw.githubusercontent.com/arabianq/pipewire-soundpad/master/assets/screenshot.png</image>
|
||||
<image>https://raw.githubusercontent.com/arabianq/pipewire-soundpad/main/pwsp-gui/assets/screenshot.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<url type="homepage">https://pwsp.arabianq.ru</url>
|
||||
|
||||
@@ -35,7 +35,7 @@ modules:
|
||||
- install -Dm755 target/release/pwsp-cli /app/bin/pwsp-cli
|
||||
- install -Dm755 target/release/pwsp-gui /app/bin/pwsp-gui
|
||||
- install -Dm755 packages/flatpak/pwsp-wrapper.py /app/bin/pwsp-wrapper.py
|
||||
- install -Dm644 assets/icon.png /app/share/icons/hicolor/256x256/apps/ru.arabianq.pwsp.png
|
||||
- install -Dm644 pwsp-gui/assets/icon.png /app/share/icons/hicolor/256x256/apps/ru.arabianq.pwsp.png
|
||||
- install -Dm644 packages/flatpak/ru.arabianq.pwsp.desktop /app/share/applications/ru.arabianq.pwsp.desktop
|
||||
- install -Dm644 packages/flatpak/ru.arabianq.pwsp.metainfo.xml /app/share/metainfo/ru.arabianq.pwsp.metainfo.xml
|
||||
sources:
|
||||
|
||||
@@ -39,10 +39,10 @@ install -Dm755 target/release/pwsp-cli %{buildroot}%{_bindir}/pwsp-cli
|
||||
install -Dm755 target/release/pwsp-daemon %{buildroot}%{_bindir}/pwsp-daemon
|
||||
install -Dm755 target/release/pwsp-gui %{buildroot}%{_bindir}/pwsp-gui
|
||||
|
||||
install -Dm644 assets/pwsp-gui.desktop %{buildroot}%{_datadir}/applications/pwsp.desktop
|
||||
install -Dm644 assets/icon.png %{buildroot}%{_datadir}/icons/hicolor/256x256/apps/pwsp.png
|
||||
install -Dm644 pwsp-gui/assets/pwsp-gui.desktop %{buildroot}%{_datadir}/applications/pwsp.desktop
|
||||
install -Dm644 pwsp-gui/assets/icon.png %{buildroot}%{_datadir}/icons/hicolor/256x256/apps/pwsp.png
|
||||
|
||||
install -Dm644 assets/pwsp-daemon.service %{buildroot}/usr/lib/systemd/user/pwsp-daemon.service
|
||||
install -Dm644 pwsp-gui/assets/pwsp-daemon.service %{buildroot}/usr/lib/systemd/user/pwsp-daemon.service
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "pwsp-cli"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
pwsp-lib.workspace = true
|
||||
|
||||
tokio.workspace = true
|
||||
|
||||
anyhow.workspace = true
|
||||
clap.workspace = true
|
||||
|
||||
serde_json.workspace = true
|
||||
@@ -1,6 +1,6 @@
|
||||
use anyhow::{Result, anyhow};
|
||||
use clap::{Parser, Subcommand};
|
||||
use pwsp::{
|
||||
use pwsp_lib::{
|
||||
types::socket::Request,
|
||||
utils::daemon::{make_request, wait_for_daemon},
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "pwsp-daemon"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
pwsp-lib.workspace = true
|
||||
|
||||
tokio.workspace = true
|
||||
|
||||
serde_json.workspace = true
|
||||
|
||||
clap.workspace = true
|
||||
anyhow.workspace = true
|
||||
|
||||
pipewire.workspace = true
|
||||
@@ -1,5 +1,5 @@
|
||||
use anyhow::{Result, anyhow};
|
||||
use pwsp::{
|
||||
use pwsp_lib::{
|
||||
types::socket::{MAX_MESSAGE_SIZE, Request, Response},
|
||||
utils::{
|
||||
commands::parse_command,
|
||||
@@ -0,0 +1,69 @@
|
||||
[package]
|
||||
name = "pwsp-gui"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
description.workspace = true
|
||||
|
||||
[dependencies]
|
||||
pwsp-lib.workspace = true
|
||||
|
||||
tokio.workspace = true
|
||||
|
||||
opener.workspace = true
|
||||
rfd.workspace = true
|
||||
itertools.workspace = true
|
||||
anyhow.workspace = true
|
||||
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
egui.workspace = true
|
||||
eframe.workspace = true
|
||||
egui_extras.workspace = true
|
||||
egui_material_icons.workspace = true
|
||||
egui_dnd.workspace = true
|
||||
|
||||
system-fonts.workspace = true
|
||||
rust-i18n.workspace = true
|
||||
sys-locale.workspace = true
|
||||
|
||||
reqwest.workspace = true
|
||||
percent-encoding.workspace = true
|
||||
|
||||
[package.metadata.deb]
|
||||
assets = [
|
||||
[
|
||||
"target/release/pwsp-daemon",
|
||||
"usr/bin/",
|
||||
"755",
|
||||
],
|
||||
[
|
||||
"target/release/pwsp-cli",
|
||||
"usr/bin/",
|
||||
"755",
|
||||
],
|
||||
[
|
||||
"target/release/pwsp-gui",
|
||||
"usr/bin/",
|
||||
"755",
|
||||
],
|
||||
[
|
||||
"assets/pwsp-gui.desktop",
|
||||
"usr/share/applications/pwsp.desktop",
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"assets/icon.png",
|
||||
"usr/share/icons/hicolor/256x256/apps/pwsp.png",
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"assets/pwsp-daemon.service",
|
||||
"usr/lib/systemd/user/pwsp-daemon.service",
|
||||
"644",
|
||||
],
|
||||
]
|
||||
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
@@ -1,7 +1,7 @@
|
||||
use crate::gui::SoundpadGui;
|
||||
use egui::{Context, Id, Key, Modifiers};
|
||||
use pwsp::types::socket::Request;
|
||||
use pwsp::utils::gui::make_request_async;
|
||||
use pwsp_lib::types::socket::Request;
|
||||
use pwsp_lib::utils::gui::make_request_async;
|
||||
|
||||
/// Convert an egui Key + Modifiers to a normalized chord string like "Ctrl+Shift+A".
|
||||
fn chord_from_event(modifiers: &Modifiers, key: &Key) -> Option<String> {
|
||||
@@ -6,7 +6,7 @@ use anyhow::{Result, anyhow};
|
||||
use eframe::{HardwareAcceleration, NativeOptions, icon_data::from_png_bytes, run_native};
|
||||
use egui::{Context, FontData, FontDefinitions, FontFamily, FontTweak, Vec2, ViewportBuilder};
|
||||
use itertools::Itertools;
|
||||
use pwsp::{
|
||||
use pwsp_lib::{
|
||||
types::{
|
||||
audio_player::PlayerState,
|
||||
config::GuiConfig,
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::gui::SoundpadGui;
|
||||
use eframe::{App, Frame as EFrame};
|
||||
use egui::{CentralPanel, Context, ThemePreference};
|
||||
use pwsp::{
|
||||
use pwsp_lib::{
|
||||
types::{config::PreferredTheme, socket::Request},
|
||||
utils::{daemon::get_daemon_config, gui::make_request_async},
|
||||
};
|
||||
@@ -5,7 +5,7 @@ use egui::{
|
||||
};
|
||||
use egui_dnd::dnd;
|
||||
use egui_material_icons::icons::*;
|
||||
use pwsp::types::{gui::AppState, gui::AudioPlayerState};
|
||||
use pwsp_lib::types::{gui::AppState, gui::AudioPlayerState};
|
||||
use rust_i18n::t;
|
||||
use std::{cmp::Ordering, path::Path, path::PathBuf};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::gui::SoundpadGui;
|
||||
use egui::{Button, CollapsingHeader, FontFamily, Label, RichText, Slider, Ui};
|
||||
use egui_material_icons::icons::*;
|
||||
use pwsp::types::{audio_player::TrackInfo, gui::AppState};
|
||||
use pwsp::utils::gui::format_time_pair;
|
||||
use pwsp_lib::types::{audio_player::TrackInfo, gui::AppState};
|
||||
use pwsp_lib::utils::gui::format_time_pair;
|
||||
use std::time::Instant;
|
||||
|
||||
pub(crate) enum TrackAction {
|
||||
@@ -91,7 +91,7 @@ impl SoundpadGui {
|
||||
|
||||
fn draw_position_control(
|
||||
ui: &mut Ui,
|
||||
ui_state: &mut pwsp::types::gui::TrackUiState,
|
||||
ui_state: &mut pwsp_lib::types::gui::TrackUiState,
|
||||
track: &TrackInfo,
|
||||
default_slider_width: f32,
|
||||
) {
|
||||
@@ -117,7 +117,7 @@ impl SoundpadGui {
|
||||
|
||||
fn draw_volume_control(
|
||||
ui: &mut Ui,
|
||||
ui_state: &mut pwsp::types::gui::TrackUiState,
|
||||
ui_state: &mut pwsp_lib::types::gui::TrackUiState,
|
||||
track: &TrackInfo,
|
||||
default_slider_width: f32,
|
||||
) {
|
||||
@@ -2,8 +2,8 @@ use crate::gui::SoundpadGui;
|
||||
use egui::{Button, Color32, Label, RichText, TextEdit, Ui};
|
||||
use egui_extras::{Column, TableBuilder};
|
||||
use egui_material_icons::icons::*;
|
||||
use pwsp::types::socket::Request;
|
||||
use pwsp::utils::gui::make_request_async;
|
||||
use pwsp_lib::types::socket::Request;
|
||||
use pwsp_lib::utils::gui::make_request_async;
|
||||
use rust_i18n::t;
|
||||
use std::path::Path;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::gui::SoundpadGui;
|
||||
use egui::{Align, Button, Color32, ComboBox, Layout, RichText, Ui};
|
||||
use egui_material_icons::icons::ICON_ARROW_BACK;
|
||||
use pwsp::types::config::PreferredTheme;
|
||||
use pwsp_lib::types::config::PreferredTheme;
|
||||
use rust_i18n::t;
|
||||
|
||||
impl SoundpadGui {
|
||||
@@ -1,7 +1,7 @@
|
||||
mod gui;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use pwsp::utils::gui::ensure_pwsp_audio_dir;
|
||||
use pwsp_lib::utils::gui::ensure_pwsp_audio_dir;
|
||||
use rust_i18n::i18n;
|
||||
use std::{env, path::PathBuf};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "pwsp-lib"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
tokio.workspace = true
|
||||
async-trait.workspace = true
|
||||
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
dirs.workspace = true
|
||||
itertools.workspace = true
|
||||
evdev.workspace = true
|
||||
anyhow.workspace = true
|
||||
rustix.workspace = true
|
||||
|
||||
rodio.workspace = true
|
||||
pipewire.workspace = true
|
||||
|
||||
egui.workspace = true
|
||||
|
||||
reqwest.workspace = true
|
||||
Reference in New Issue
Block a user