mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-08-17 19:07:12 +02:00
adapt plugin to notify v5
This commit is contained in:
Generated
+13
@@ -2303,10 +2303,22 @@ dependencies = [
|
|||||||
"kqueue",
|
"kqueue",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
|
"serde",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "notify-debouncer-mini"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e23e9fa24f094b143c1eb61f90ac6457de87be6987bc70746e0179f7dbc9007b"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-channel",
|
||||||
|
"notify",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
@@ -4048,6 +4060,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"notify",
|
"notify",
|
||||||
|
"notify-debouncer-mini",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
|
|||||||
@@ -15,4 +15,5 @@ serde_json.workspace = true
|
|||||||
tauri.workspace = true
|
tauri.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
notify = "5.0"
|
notify = { version = "5.0" , features = ["serde"] }
|
||||||
|
notify-debouncer-mini = { version = "0.2.1" , features = ["serde"] }
|
||||||
|
|||||||
@@ -1,110 +1,103 @@
|
|||||||
import { invoke } from "@tauri-apps/api/tauri";
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
import { UnlistenFn } from "@tauri-apps/api/event";
|
import { UnlistenFn } from '@tauri-apps/api/event';
|
||||||
import { appWindow, WebviewWindow } from "@tauri-apps/api/window";
|
import { appWindow, WebviewWindow } from '@tauri-apps/api/window';
|
||||||
|
|
||||||
const w: WebviewWindow = appWindow;
|
const w: WebviewWindow = appWindow;
|
||||||
|
|
||||||
export interface WatchOptions {
|
export interface WatchOptions {
|
||||||
recursive?: boolean;
|
recursive?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DebouncedWatchOptions extends WatchOptions {
|
export interface DebouncedWatchOptions extends WatchOptions {
|
||||||
delayMs?: number;
|
delayMs?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RawEvent {
|
export type RawEvent = {
|
||||||
path: string | null;
|
type: RawEventKind;
|
||||||
operation: number;
|
paths: string[];
|
||||||
cookie: number | null;
|
attrs: unknown;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type DebouncedEvent =
|
type RawEventKind =
|
||||||
| { type: "NoticeWrite"; payload: string }
|
| 'any '
|
||||||
| { type: "NoticeRemove"; payload: string }
|
| {
|
||||||
| { type: "Create"; payload: string }
|
access?: unknown;
|
||||||
| { type: "Write"; payload: string }
|
}
|
||||||
| { type: "Chmod"; payload: string }
|
| {
|
||||||
| { type: "Remove"; payload: string }
|
create?: unknown;
|
||||||
| { type: "Rename"; payload: string }
|
}
|
||||||
| { type: "Rescan"; payload: null }
|
| {
|
||||||
| { type: "Error"; payload: { error: string; path: string | null } };
|
modify?: unknown;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
remove?: unknown;
|
||||||
|
}
|
||||||
|
| 'other';
|
||||||
|
|
||||||
|
export type DebouncedEvent = { kind: 'any'; path: string } | { kind: 'AnyContinous'; path: string };
|
||||||
|
|
||||||
async function unwatch(id: number): Promise<void> {
|
async function unwatch(id: number): Promise<void> {
|
||||||
await invoke("plugin:fs-watch|unwatch", { id });
|
await invoke('plugin:fs-watch|unwatch', { id });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function watch(
|
export async function watch(paths: string | string[], options: DebouncedWatchOptions, cb: (event: DebouncedEvent) => void): Promise<UnlistenFn> {
|
||||||
paths: string | string[],
|
const opts = {
|
||||||
options: DebouncedWatchOptions,
|
recursive: false,
|
||||||
cb: (event: DebouncedEvent) => void
|
delayMs: 2000,
|
||||||
): Promise<UnlistenFn> {
|
...options,
|
||||||
const opts = {
|
};
|
||||||
recursive: false,
|
let watchPaths;
|
||||||
delayMs: 2000,
|
if (typeof paths === 'string') {
|
||||||
...options,
|
watchPaths = [paths];
|
||||||
};
|
} else {
|
||||||
let watchPaths;
|
watchPaths = paths;
|
||||||
if (typeof paths === "string") {
|
|
||||||
watchPaths = [paths];
|
|
||||||
} else {
|
|
||||||
watchPaths = paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = window.crypto.getRandomValues(new Uint32Array(1))[0];
|
|
||||||
|
|
||||||
await invoke("plugin:fs-watch|watch", {
|
|
||||||
id,
|
|
||||||
paths: watchPaths,
|
|
||||||
options: opts,
|
|
||||||
});
|
|
||||||
|
|
||||||
const unlisten = await w.listen<DebouncedEvent>(
|
|
||||||
`watcher://debounced-event/${id}`,
|
|
||||||
(event) => {
|
|
||||||
cb(event.payload);
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
const id = window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||||
void unwatch(id);
|
|
||||||
unlisten();
|
await invoke('plugin:fs-watch|watch', {
|
||||||
};
|
id,
|
||||||
|
paths: watchPaths,
|
||||||
|
options: opts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unlisten = await w.listen<DebouncedEvent>(`watcher://debounced-event/${id}`, (event) => {
|
||||||
|
cb(event.payload);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
void unwatch(id);
|
||||||
|
unlisten();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function watchImmediate(
|
export async function watchImmediate(paths: string | string[], options: WatchOptions, cb: (event: RawEvent) => void): Promise<UnlistenFn> {
|
||||||
paths: string | string[],
|
const opts = {
|
||||||
options: WatchOptions,
|
recursive: false,
|
||||||
cb: (event: RawEvent) => void
|
...options,
|
||||||
): Promise<UnlistenFn> {
|
delayMs: null,
|
||||||
const opts = {
|
};
|
||||||
recursive: false,
|
let watchPaths;
|
||||||
...options,
|
if (typeof paths === 'string') {
|
||||||
delayMs: null,
|
watchPaths = [paths];
|
||||||
};
|
} else {
|
||||||
let watchPaths;
|
watchPaths = paths;
|
||||||
if (typeof paths === "string") {
|
|
||||||
watchPaths = [paths];
|
|
||||||
} else {
|
|
||||||
watchPaths = paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = window.crypto.getRandomValues(new Uint32Array(1))[0];
|
|
||||||
|
|
||||||
await invoke("plugin:fs-watch|watch", {
|
|
||||||
id,
|
|
||||||
paths: watchPaths,
|
|
||||||
options: opts,
|
|
||||||
});
|
|
||||||
|
|
||||||
const unlisten = await w.listen<RawEvent>(
|
|
||||||
`watcher://raw-event/${id}`,
|
|
||||||
(event) => {
|
|
||||||
cb(event.payload);
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
const id = window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||||
void unwatch(id);
|
|
||||||
unlisten();
|
await invoke('plugin:fs-watch|watch', {
|
||||||
};
|
id,
|
||||||
|
paths: watchPaths,
|
||||||
|
options: opts,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unlisten = await w.listen<RawEvent>(`watcher://raw-event/${id}`, (event) => {
|
||||||
|
cb(event.payload);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
void unwatch(id);
|
||||||
|
unlisten();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-65
@@ -1,7 +1,5 @@
|
|||||||
use notify::{
|
use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher};
|
||||||
raw_watcher, watcher, DebouncedEvent, Op, RawEvent, RecommendedWatcher, RecursiveMode,
|
use notify_debouncer_mini::{new_debouncer, DebounceEventResult, Debouncer};
|
||||||
Watcher as _,
|
|
||||||
};
|
|
||||||
use serde::{ser::Serializer, Deserialize, Serialize};
|
use serde::{ser::Serializer, Deserialize, Serialize};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
command,
|
command,
|
||||||
@@ -39,72 +37,33 @@ impl Serialize for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct WatcherCollection(Mutex<HashMap<Id, (RecommendedWatcher, Vec<PathBuf>)>>);
|
struct WatcherCollection(Mutex<HashMap<Id, (WatcherKind, Vec<PathBuf>)>>);
|
||||||
|
|
||||||
#[derive(Clone, Serialize)]
|
enum WatcherKind {
|
||||||
struct RawEventWrapper {
|
Debouncer(Debouncer<RecommendedWatcher>),
|
||||||
path: Option<PathBuf>,
|
Watcher(RecommendedWatcher),
|
||||||
operation: u32,
|
|
||||||
cookie: Option<u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize)]
|
fn watch_raw<R: Runtime>(window: Window<R>, rx: Receiver<notify::Result<Event>>, id: Id) {
|
||||||
#[serde(tag = "type", content = "payload")]
|
|
||||||
enum DebouncedEventWrapper {
|
|
||||||
NoticeWrite(PathBuf),
|
|
||||||
NoticeRemove(PathBuf),
|
|
||||||
Create(PathBuf),
|
|
||||||
Write(PathBuf),
|
|
||||||
Chmod(PathBuf),
|
|
||||||
Remove(PathBuf),
|
|
||||||
Rename(PathBuf, PathBuf),
|
|
||||||
Rescan,
|
|
||||||
Error {
|
|
||||||
error: String,
|
|
||||||
path: Option<PathBuf>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DebouncedEvent> for DebouncedEventWrapper {
|
|
||||||
fn from(event: DebouncedEvent) -> Self {
|
|
||||||
match event {
|
|
||||||
DebouncedEvent::NoticeWrite(path) => Self::NoticeWrite(path),
|
|
||||||
DebouncedEvent::NoticeRemove(path) => Self::NoticeRemove(path),
|
|
||||||
DebouncedEvent::Create(path) => Self::Create(path),
|
|
||||||
DebouncedEvent::Write(path) => Self::Write(path),
|
|
||||||
DebouncedEvent::Chmod(path) => Self::Chmod(path),
|
|
||||||
DebouncedEvent::Remove(path) => Self::Remove(path),
|
|
||||||
DebouncedEvent::Rename(from, to) => Self::Rename(from, to),
|
|
||||||
DebouncedEvent::Rescan => Self::Rescan,
|
|
||||||
DebouncedEvent::Error(error, path) => Self::Error {
|
|
||||||
error: error.to_string(),
|
|
||||||
path,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn watch_raw<R: Runtime>(window: Window<R>, rx: Receiver<RawEvent>, id: Id) {
|
|
||||||
spawn(move || {
|
spawn(move || {
|
||||||
let event_name = format!("watcher://raw-event/{}", id);
|
let event_name = format!("watcher://raw-event/{}", id);
|
||||||
while let Ok(event) = rx.recv() {
|
while let Ok(event) = rx.recv() {
|
||||||
let _ = window.emit(
|
if let Ok(event) = event {
|
||||||
&event_name,
|
// TODO: Should errors be emitted too?
|
||||||
RawEventWrapper {
|
let _ = window.emit(&event_name, event);
|
||||||
path: event.path,
|
}
|
||||||
operation: event.op.unwrap_or_else(|_| Op::empty()).bits(),
|
|
||||||
cookie: event.cookie,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn watch_debounced<R: Runtime>(window: Window<R>, rx: Receiver<DebouncedEvent>, id: Id) {
|
fn watch_debounced<R: Runtime>(window: Window<R>, rx: Receiver<DebounceEventResult>, id: Id) {
|
||||||
spawn(move || {
|
spawn(move || {
|
||||||
let event_name = format!("watcher://debounced-event/{}", id);
|
let event_name = format!("watcher://debounced-event/{}", id);
|
||||||
while let Ok(event) = rx.recv() {
|
while let Ok(event) = rx.recv() {
|
||||||
let _ = window.emit(&event_name, DebouncedEventWrapper::from(event));
|
if let Ok(event) = event {
|
||||||
|
// TODO: Should errors be emitted too?
|
||||||
|
let _ = window.emit(&event_name, event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -132,20 +91,21 @@ async fn watch<R: Runtime>(
|
|||||||
|
|
||||||
let watcher = if let Some(delay) = options.delay_ms {
|
let watcher = if let Some(delay) = options.delay_ms {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let mut watcher = watcher(tx, Duration::from_millis(delay))?;
|
let mut debouncer = new_debouncer(Duration::from_millis(delay), None, tx)?;
|
||||||
|
let watcher = debouncer.watcher();
|
||||||
for path in &paths {
|
for path in &paths {
|
||||||
watcher.watch(path, mode)?;
|
watcher.watch(path, mode)?;
|
||||||
}
|
}
|
||||||
watch_debounced(window, rx, id);
|
watch_debounced(window, rx, id);
|
||||||
watcher
|
WatcherKind::Debouncer(debouncer)
|
||||||
} else {
|
} else {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let mut watcher = raw_watcher(tx)?;
|
let mut watcher = RecommendedWatcher::new(tx, Config::default())?;
|
||||||
for path in &paths {
|
for path in &paths {
|
||||||
watcher.watch(path, mode)?;
|
watcher.watch(path, mode)?;
|
||||||
}
|
}
|
||||||
watch_raw(window, rx, id);
|
watch_raw(window, rx, id);
|
||||||
watcher
|
WatcherKind::Watcher(watcher)
|
||||||
};
|
};
|
||||||
|
|
||||||
watchers.0.lock().unwrap().insert(id, (watcher, paths));
|
watchers.0.lock().unwrap().insert(id, (watcher, paths));
|
||||||
@@ -155,10 +115,19 @@ async fn watch<R: Runtime>(
|
|||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
async fn unwatch(watchers: State<'_, WatcherCollection>, id: Id) -> Result<()> {
|
async fn unwatch(watchers: State<'_, WatcherCollection>, id: Id) -> Result<()> {
|
||||||
if let Some((mut watcher, paths)) = watchers.0.lock().unwrap().remove(&id) {
|
if let Some((watcher, paths)) = watchers.0.lock().unwrap().remove(&id) {
|
||||||
for path in paths {
|
match watcher {
|
||||||
watcher.unwatch(path)?;
|
WatcherKind::Debouncer(mut debouncer) => {
|
||||||
}
|
for path in paths {
|
||||||
|
debouncer.watcher().unwatch(&path)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WatcherKind::Watcher(mut watcher) => {
|
||||||
|
for path in paths {
|
||||||
|
watcher.unwatch(&path)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user