Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitbd32c0b

Browse files
authored
feat: support opfs watch (#2)
1 parent62778b8 commitbd32c0b

File tree

9 files changed

+278
-5
lines changed

9 files changed

+278
-5
lines changed

‎Cargo.lock‎

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ keywords = ["tokio", "fs", "wasm", "opfs"]
1313
crate-type = ["cdylib","rlib"]
1414

1515
[features]
16-
wasm_offload = ["tokio/sync"]
16+
default = []
17+
opfs_offload = ["tokio/sync"]
18+
opfs_watch = ["tokio/sync","notify-types"]
1719
opfs_tracing = ["tracing"]
1820

1921
[dependencies]
@@ -57,6 +59,7 @@ wasm-bindgen-futures = { version = "0.4.50", features = [
5759
tokio = {version ="1.46.1",default-features =false,optional =true }
5860
bitflags ="2.9.1"
5961
rustc-hash ="2.1.1"
62+
notify-types = {version ="2.0.0",optional =true }
6063
tracing = {version ="0.1.41",optional =true }
6164

6265
[target.'cfg(all(target_family="wasm",target_os="unknown"))'.dev-dependencies]

‎src/fs/mod.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ cfg_if! {
1616

1717
pubuse wasm::ReadDirStream;
1818

19-
#[cfg(feature ="wasm_offload")]
19+
#[cfg(feature ="opfs_offload")]
2020
pubuse wasm::offload;
2121

22+
#[cfg(feature ="opfs_watch")]
23+
pubuse wasm::watch;
24+
2225
} elseif #[cfg(any(target_family ="unix", target_family ="windows"))]{
2326

2427
mod native;

‎src/fs/wasm/mod.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,8 @@ pub use symlink_metadata::symlink_metadata;
4545
pubuse try_exists::try_exists;
4646
pubuse write::write;
4747

48-
#[cfg(feature ="wasm_offload")]
48+
#[cfg(feature ="opfs_offload")]
4949
pubmod offload;
50+
51+
#[cfg(feature ="opfs_watch")]
52+
pubuse opfs::watch;

‎src/fs/wasm/offload/client.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use std::{io, path::Path};
22

33
use tokio::sync::{mpsc, oneshot};
44

5+
#[cfg(feature ="opfs_watch")]
6+
usesuper::super::opfs::watch::event;
57
usesuper::{FsTask,Metadata,ReadDir};
68

79
#[derive(Clone)]
@@ -68,6 +70,23 @@ impl Client {
6870
.await
6971
}
7072

73+
#[cfg(feature ="opfs_watch")]
74+
pubasyncfnwatch_dir(
75+
&self,
76+
path:implAsRef<Path>,
77+
recursive:bool,
78+
cb:implFn(event::Event) +Send +Sync +'static,
79+
) -> io::Result<()>{
80+
let path = path.as_ref().into();
81+
self.dispatch(|sender|FsTask::WatchDir{
82+
path,
83+
recursive,
84+
cb:Box::new(cb),
85+
sender,
86+
})
87+
.await
88+
}
89+
7190
asyncfndispatch<T,F>(&self,create_task:F) -> io::Result<T>
7291
where
7392
F:FnOnce(oneshot::Sender<io::Result<T>>) ->FsTask,

‎src/fs/wasm/offload/mod.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use std::{io, path::Path};
22

33
use tokio::sync::mpsc;
44

5+
#[cfg(feature ="opfs_watch")]
6+
usesuper::opfs::watch::{event, watch_dir};
57
usesuper::{
68
Metadata,ReadDir, copy, create_dir, create_dir_all, metadata, read, read_dir, remove_dir,
79
remove_dir_all, remove_file, write,
@@ -30,6 +32,13 @@ pub trait FsOffload {
3032
asyncfnremove_dir(&self,path:implAsRef<Path>) -> io::Result<()>;
3133
asyncfnremove_dir_all(&self,path:implAsRef<Path>) -> io::Result<()>;
3234
asyncfnmetadata(&self,path:implAsRef<Path>) -> io::Result<Metadata>;
35+
#[cfg(feature ="opfs_watch")]
36+
asyncfnwatch_dir(
37+
&self,
38+
path:implAsRef<Path>,
39+
recursive:bool,
40+
cb:implFn(event::Event) +Send +Sync +'static,
41+
) -> io::Result<()>;
3342
}
3443

3544
pubstructFsOffloadDefault;
@@ -74,4 +83,14 @@ impl FsOffload for FsOffloadDefault {
7483
asyncfnmetadata(&self,path:implAsRef<Path>) -> io::Result<Metadata>{
7584
metadata(path).await
7685
}
86+
87+
#[cfg(feature ="opfs_watch")]
88+
asyncfnwatch_dir(
89+
&self,
90+
path:implAsRef<Path>,
91+
recursive:bool,
92+
cb:implFn(event::Event) +Send +Sync +'static,
93+
) -> io::Result<()>{
94+
watch_dir(path, recursive, cb).await
95+
}
7796
}

‎src/fs/wasm/offload/task.rs‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use std::{io, path::PathBuf};
22

33
use tokio::sync::oneshot;
44

5+
#[cfg(feature ="opfs_watch")]
6+
usesuper::super::opfs::watch::{event, watch_dir};
57
usesuper::{FsOffload,Metadata,ReadDir};
68

79
pubenumFsTask{
@@ -47,18 +49,26 @@ pub enum FsTask {
4749
path:PathBuf,
4850
sender: oneshot::Sender<io::Result<Metadata>>,
4951
},
52+
#[cfg(feature ="opfs_watch")]
53+
WatchDir{
54+
path:PathBuf,
55+
recursive:bool,
56+
cb:Box<dynFn(event::Event) +Send +Sync +'static>,
57+
sender: oneshot::Sender<io::Result<()>>,
58+
},
5059
}
5160

5261
macro_rules! impl_fs_task_execute{
5362
(
5463
$offload_trait:ident,
5564
$task_enum:ident,
56-
[ $(($variant:ident, $method:ident,( $( $arg:ident: $arg_type:ty),*))),*]
65+
[ $($(#[$attr:meta])*($variant:ident, $method:ident,( $( $arg:ident: $arg_type:ty),*))),*]
5766
) =>{
5867
impl $task_enum{
5968
pub(super)asyncfn execute(self, offload:&impl $offload_trait){
6069
matchself{
6170
$(
71+
$(#[$attr])*
6272
$task_enum::$variant{ $( $arg,)* sender} =>{
6373
let _ = sender.send(offload.$method( $( $arg),*).await);
6474
}
@@ -82,6 +92,8 @@ impl_fs_task_execute!(
8292
(RemoveFile, remove_file,(path:PathBuf)),
8393
(RemoveDir, remove_dir,(path:PathBuf)),
8494
(RemoveDirAll, remove_dir_all,(path:PathBuf)),
85-
(Metadata, metadata,(path:PathBuf))
95+
(Metadata, metadata,(path:PathBuf)),
96+
#[cfg(feature ="opfs_watch")]
97+
(WatchDir, watch_dir,(path:PathBuf, recursive:bool, cb:Box<dynFn(event::Event) +Send +Sync +'static>))
8698
]
8799
);

‎src/fs/wasm/opfs/mod.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ mod options;
66
mod remove;
77
mod root;
88
mod virtualize;
9+
#[cfg(feature ="opfs_watch")]
10+
pubmod watch;
911

1012
pub(super)use error::OpfsError;
1113
pub(super)use open_dir::open_dir;

‎src/fs/wasm/opfs/watch.rs‎

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
use std::{
2+
io,
3+
path::{MAIN_SEPARATOR_STR,Path},
4+
};
5+
6+
use js_sys::{Array,JsString};
7+
pubuse notify_types::event;
8+
use wasm_bindgen::{
9+
JsCast,
10+
prelude::{Closure, wasm_bindgen},
11+
};
12+
use wasm_bindgen_futures::JsFuture;
13+
use web_sys::{FileSystemDirectoryHandle,FileSystemHandle,FileSystemSyncAccessHandle};
14+
15+
usesuper::{super::opfs::OpfsError,CreateFileMode,OpenDirType,SyncAccessMode, open_file};
16+
17+
#[wasm_bindgen]
18+
extern"C"{
19+
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemObserver
20+
#[wasm_bindgen(extends = js_sys::Object, js_name =FileSystemObserver, typescript_type ="FileSystemObserver")]
21+
#[derive(Debug,Clone,PartialEq,Eq)]
22+
pubtypeFileSystemObserver;
23+
24+
#[wasm_bindgen(constructor, js_class ="FileSystemObserver")]
25+
pubfnnew(callback:&js_sys::Function) ->FileSystemObserver;
26+
27+
#[wasm_bindgen(method, structural, js_class ="FileSystemObserver", js_name = observe)]
28+
pubfnobserve_file(
29+
this:&FileSystemObserver,
30+
target:&FileSystemSyncAccessHandle,
31+
) -> js_sys::Promise;
32+
33+
#[wasm_bindgen(method, structural, js_class ="FileSystemObserver", js_name = observe)]
34+
pubfnobserve_dir(
35+
this:&FileSystemObserver,
36+
handdle:&FileSystemSyncAccessHandle,
37+
) -> js_sys::Promise;
38+
39+
#[wasm_bindgen(method, structural, js_class ="FileSystemObserver", js_name = observe)]
40+
pubfnobserve_dir_with_options(
41+
this:&FileSystemObserver,
42+
handdle:&FileSystemDirectoryHandle,
43+
options:&FileSystemDirObserverOptions,
44+
) -> js_sys::Promise;
45+
46+
#[wasm_bindgen(method, structural, js_class ="FileSystemObserver", js_name = disconnect)]
47+
pubfndisconnect(this:&FileSystemObserver);
48+
49+
}
50+
51+
#[wasm_bindgen]
52+
extern"C"{
53+
#[wasm_bindgen(extends = js_sys::Object, js_name =FileSystemObserverOptions)]
54+
#[derive(Debug,Clone,PartialEq,Eq)]
55+
pubtypeFileSystemDirObserverOptions;
56+
#[wasm_bindgen(method, getter ="recursive")]
57+
pubfnget_recursive(this:&FileSystemDirObserverOptions) ->Option<bool>;
58+
#[wasm_bindgen(method, setter ="recursive")]
59+
pubfnset_recursive(this:&FileSystemDirObserverOptions,val:bool);
60+
}
61+
implFileSystemDirObserverOptions{
62+
pubfnnew() ->Self{
63+
wasm_bindgen::JsCast::unchecked_into(js_sys::Object::new())
64+
}
65+
}
66+
67+
implDefaultforFileSystemDirObserverOptions{
68+
fndefault() ->Self{
69+
Self::new()
70+
}
71+
}
72+
73+
#[wasm_bindgen]
74+
extern"C"{
75+
#[wasm_bindgen(extends = js_sys::Object, js_name =FileSystemChangeRecord)]
76+
#[derive(Debug,Clone,PartialEq,Eq)]
77+
pubtypeFileSystemChangeRecord;
78+
79+
#[wasm_bindgen(method, getter, js_class ="FileSystemChangeRecord", js_name =type)]
80+
pubfnr#type(this:&FileSystemChangeRecord) ->FileSystemChangeRecordType;
81+
82+
#[wasm_bindgen(method, getter, structural, js_class ="FileSystemChangeRecord", js_name = relativePathComponents)]
83+
pubfnrelative_path_components(this:&FileSystemChangeRecord) ->Array;
84+
85+
#[wasm_bindgen(method, getter, structural, js_class ="FileSystemChangeRecord", js_name = changedHandle)]
86+
pubfnchanged_handle(this:&FileSystemChangeRecord) ->FileSystemHandle;
87+
88+
}
89+
90+
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemChangeRecord#type
91+
#[wasm_bindgen]
92+
pubenumFileSystemChangeRecordType{
93+
Appeared ="appeared",
94+
Disappeared ="disappeared",
95+
Errored ="errored",
96+
Modified ="modified",
97+
Moved ="moved",
98+
Unknown ="unknown",
99+
}
100+
101+
implFrom<&FileSystemChangeRecord>for event::Event{
102+
fnfrom(record:&FileSystemChangeRecord) ->Self{
103+
let kind = record.changed_handle().kind();
104+
105+
event::Event{
106+
kind:match record.r#type(){
107+
FileSystemChangeRecordType::Appeared => event::EventKind::Create(match kind{
108+
web_sys::FileSystemHandleKind::File => event::CreateKind::File,
109+
web_sys::FileSystemHandleKind::Directory => event::CreateKind::Folder,
110+
_ => event::CreateKind::Any,
111+
}),
112+
FileSystemChangeRecordType::Disappeared => event::EventKind::Remove(match kind{
113+
web_sys::FileSystemHandleKind::File => event::RemoveKind::File,
114+
web_sys::FileSystemHandleKind::Directory => event::RemoveKind::Folder,
115+
_ => event::RemoveKind::Any,
116+
}),
117+
FileSystemChangeRecordType::Modified =>match kind{
118+
web_sys::FileSystemHandleKind::File =>{
119+
event::EventKind::Modify(event::ModifyKind::Data(event::DataChange::Any))
120+
}
121+
web_sys::FileSystemHandleKind::Directory => event::EventKind::Modify(
122+
event::ModifyKind::Metadata(event::MetadataKind::Any),
123+
),
124+
_ => event::EventKind::Modify(event::ModifyKind::Any),
125+
},
126+
FileSystemChangeRecordType::Moved =>{
127+
event::EventKind::Modify(event::ModifyKind::Name(event::RenameMode::Any))
128+
}
129+
FileSystemChangeRecordType::Unknown => event::EventKind::Other,
130+
FileSystemChangeRecordType::Errored => event::EventKind::Other,
131+
FileSystemChangeRecordType::__Invalid => event::EventKind::Other,
132+
},
133+
paths:vec![
134+
format!(
135+
"./{}",
136+
record
137+
.relative_path_components()
138+
.iter()
139+
.map(|p|String::from(p.unchecked_ref::<JsString>()))
140+
.collect::<Vec<_>>()
141+
.join(MAIN_SEPARATOR_STR)
142+
)
143+
.into(),
144+
],
145+
..Default::default()
146+
}
147+
}
148+
}
149+
150+
pubasyncfnwatch_dir(
151+
path:implAsRef<Path>,
152+
recursive:bool,
153+
cb:implFn(event::Event) +Send +Sync +'static,
154+
) -> io::Result<()>{
155+
let observer =FileSystemObserver::new(
156+
Closure::<dynFn(Array)>::new(move |records:Array|{
157+
records.iter().for_each(|record|{
158+
let event = event::Event::from(record.unchecked_ref::<FileSystemChangeRecord>());
159+
cb(event)
160+
});
161+
})
162+
.into_js_value()
163+
.unchecked_ref(),
164+
);
165+
166+
let dir_handle =super::open_dir(path,OpenDirType::NotCreate).await?;
167+
let options =FileSystemDirObserverOptions::new();
168+
options.set_recursive(recursive);
169+
JsFuture::from(observer.observe_dir_with_options(&dir_handle,&options))
170+
.await
171+
.map_err(|e|OpfsError::from(e).into_io_err())?;
172+
Ok(())
173+
}
174+
175+
#[allow(dead_code)]
176+
pubasyncfnwatch_file(
177+
path:implAsRef<Path>,
178+
cb:implFn(event::Event) +Send +Sync +'static,
179+
) -> io::Result<()>{
180+
let observer =FileSystemObserver::new(
181+
Closure::<dynFn(Array)>::new(move |records:Array|{
182+
records.iter().for_each(|record|{
183+
let event = event::Event::from(record.unchecked_ref::<FileSystemChangeRecord>());
184+
cb(event)
185+
});
186+
})
187+
.into_js_value()
188+
.unchecked_ref(),
189+
);
190+
191+
let file_handle =open_file(
192+
path,
193+
CreateFileMode::NotCreate,
194+
SyncAccessMode::Readonly,
195+
false,
196+
)
197+
.await?
198+
.sync_access_handle
199+
.clone();
200+
201+
JsFuture::from(observer.observe_file(&file_handle))
202+
.await
203+
.map_err(|e|OpfsError::from(e).into_io_err())?;
204+
Ok(())
205+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp