yew_stdweb/services/reader/
std_web.rs1use super::*;
4use crate::callback::Callback;
5use crate::services::Task;
6use std::cmp;
7use stdweb::unstable::{TryFrom, TryInto};
8use stdweb::web::event::LoadEndEvent;
9#[doc(no_inline)]
10pub use stdweb::web::{Blob, File, IBlob};
11use stdweb::web::{FileReader, FileReaderReadyState, FileReaderResult, IEventTarget, TypedArray};
12#[allow(unused_imports)]
13use stdweb::{_js_impl, js};
14
15fn new_file_reader() -> Result<FileReader, &'static str> {
16 let file_reader = js! {
17 try {
18 return new FileReader;
19 } catch(error) {
20 return error;
21 }
22 };
23 FileReader::try_from(js!( return @{file_reader.as_ref()}; ))
24 .map_err(|_| "couldn't aquire file reader")
25}
26
27impl ReaderService {
28 pub fn read_file(file: File, callback: Callback<FileData>) -> Result<ReaderTask, &'static str> {
30 let file_reader = new_file_reader()?;
31 let reader = file_reader.clone();
32 let name = file.name();
33 file_reader.add_event_listener(move |_event: LoadEndEvent| match reader.result() {
34 Some(FileReaderResult::String(_)) => {
35 unreachable!();
36 }
37 Some(FileReaderResult::ArrayBuffer(buffer)) => {
38 let array: TypedArray<u8> = buffer.into();
39 let data = FileData {
40 name: name.clone(),
41 content: array.to_vec(),
42 };
43 callback.emit(data);
44 }
45 None => {}
46 });
47 file_reader.read_as_array_buffer(&file).unwrap();
48 Ok(ReaderTask { file_reader })
49 }
50
51 pub fn read_file_by_chunks(
53 file: File,
54 callback: Callback<Option<FileChunk>>,
55 chunk_size: usize,
56 ) -> Result<ReaderTask, &'static str> {
57 let file_reader = new_file_reader()?;
58 let name = file.name();
59 let mut position = 0;
60 let total_size = file.len() as usize;
61 let reader = file_reader.clone();
62 file_reader.add_event_listener(move |_event: LoadEndEvent| {
63 if let Some(result) = reader.result() {
64 match result {
65 FileReaderResult::String(_) => {
67 let started = FileChunk::Started { name: name.clone() };
68 callback.emit(Some(started));
69 }
70 FileReaderResult::ArrayBuffer(buffer) => {
72 let array: TypedArray<u8> = buffer.into();
73 let chunk = FileChunk::DataChunk {
74 data: array.to_vec(),
75 progress: position as f32 / total_size as f32,
76 };
77 callback.emit(Some(chunk));
78 }
79 }
80
81 if position < total_size {
83 let file = &file;
84 let from = position;
85 let to = cmp::min(position + chunk_size, total_size);
86 position = to;
87 let blob: Blob = (js! {
89 return @{file}.slice(@{from as u32}, @{to as u32});
90 })
91 .try_into()
92 .unwrap();
93 reader.read_as_array_buffer(&blob).unwrap();
94 } else {
95 let finished = FileChunk::Finished;
96 callback.emit(Some(finished));
97 }
98 } else {
99 callback.emit(None);
100 }
101 });
102 let blob: Blob = (js! {
103 return (new Blob());
104 })
105 .try_into()
106 .unwrap();
107 file_reader.read_as_text(&blob).unwrap();
108 Ok(ReaderTask { file_reader })
109 }
110}
111
112#[must_use = "the reader will abort when the task is dropped"]
114pub struct ReaderTask {
115 pub(super) file_reader: FileReader,
116}
117
118impl Task for ReaderTask {
119 fn is_active(&self) -> bool {
120 self.file_reader.ready_state() == FileReaderReadyState::Loading
121 }
122}