|
| 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 | +} |