aboutsummaryrefslogtreecommitdiffstats
path: root/components/net/filemanager_thread.rs
diff options
context:
space:
mode:
authorZhen Zhang <izgzhen@gmail.com>2016-08-01 21:06:58 +0200
committerZhen Zhang <izgzhen@gmail.com>2016-08-02 23:51:51 +0200
commit17ae38a31880e32afe8458a132b838241579f073 (patch)
tree419954a6061f18b47448b3a4e5a29c1ab639d83c /components/net/filemanager_thread.rs
parent7807895d5839ddd8e042b7e741961a75b70c37d8 (diff)
downloadservo-17ae38a31880e32afe8458a132b838241579f073.tar.gz
servo-17ae38a31880e32afe8458a132b838241579f073.zip
Add cancellability to file manager load and related refactoring
Diffstat (limited to 'components/net/filemanager_thread.rs')
-rw-r--r--components/net/filemanager_thread.rs170
1 files changed, 81 insertions, 89 deletions
diff --git a/components/net/filemanager_thread.rs b/components/net/filemanager_thread.rs
index 10989f1a0cb..5f9e6654bed 100644
--- a/components/net/filemanager_thread.rs
+++ b/components/net/filemanager_thread.rs
@@ -2,12 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::ipc::IpcSender;
use mime_guess::guess_mime_type_opt;
use net_traits::blob_url_store::{BlobBuf, BlobURLStoreError};
use net_traits::filemanager_thread::{FileManagerThreadMsg, FileManagerResult, FilterPattern, FileOrigin};
use net_traits::filemanager_thread::{SelectedFile, RelativePos, FileManagerThreadError};
use net_traits::filemanager_thread::{SelectedFileId, ReadFileProgress};
+use resource_thread::CancellationListener;
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
@@ -22,10 +23,6 @@ use util::prefs::PREFS;
use util::thread::spawn_named;
use uuid::Uuid;
-pub trait FileManagerThreadFactory<UI: 'static + UIProvider> {
- fn new(&'static UI) -> Self;
-}
-
/// Trait that provider of file-dialog UI should implement.
/// It will be used to initialize a generic FileManager.
/// For example, we can choose a dummy UI for testing purpose.
@@ -79,19 +76,6 @@ impl UIProvider for TFDProvider {
}
}
-impl<UI: 'static + UIProvider> FileManagerThreadFactory<UI> for IpcSender<FileManagerThreadMsg> {
- /// Create a FileManagerThread
- fn new(ui: &'static UI) -> IpcSender<FileManagerThreadMsg> {
- let (chan, recv) = ipc::channel().unwrap();
-
- spawn_named("FileManager".to_owned(), move || {
- FileManager::new(recv, ui).start();
- });
-
- chan
- }
-}
-
/// FileManagerStore's entry
struct FileStoreEntry {
/// Origin of the entry's "creator"
@@ -127,83 +111,79 @@ enum FileImpl {
Sliced(Uuid, RelativePos),
}
-struct FileManager<UI: 'static + UIProvider> {
- receiver: IpcReceiver<FileManagerThreadMsg>,
+pub struct FileManager<UI: 'static + UIProvider> {
store: Arc<FileManagerStore<UI>>,
}
impl<UI: 'static + UIProvider> FileManager<UI> {
- fn new(recv: IpcReceiver<FileManagerThreadMsg>, ui: &'static UI) -> FileManager<UI> {
+ pub fn new(ui: &'static UI) -> FileManager<UI> {
FileManager {
- receiver: recv,
store: Arc::new(FileManagerStore::new(ui)),
}
}
- /// Start the file manager event loop
- fn start(&mut self) {
- loop {
- let store = self.store.clone();
- match self.receiver.recv().unwrap() {
- FileManagerThreadMsg::SelectFile(filter, sender, origin, opt_test_path) => {
- spawn_named("select file".to_owned(), move || {
- store.select_file(filter, sender, origin, opt_test_path);
- });
- }
- FileManagerThreadMsg::SelectFiles(filter, sender, origin, opt_test_paths) => {
- spawn_named("select files".to_owned(), move || {
- store.select_files(filter, sender, origin, opt_test_paths);
- })
- }
- FileManagerThreadMsg::ReadFile(sender, id, check_url_validity, origin) => {
- spawn_named("read file".to_owned(), move || {
- if let Err(e) = store.try_read_file(sender.clone(), id, check_url_validity, origin) {
- let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e)));
- }
- })
- }
- FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, sender, origin) => {
- spawn_named("transfer memory".to_owned(), move || {
- store.promote_memory(blob_buf, set_valid, sender, origin);
+ /// Message handler
+ pub fn handle(&self, msg: FileManagerThreadMsg, cancel_listener: Option<CancellationListener>) {
+ let store = self.store.clone();
+ match msg {
+ FileManagerThreadMsg::SelectFile(filter, sender, origin, opt_test_path) => {
+ spawn_named("select file".to_owned(), move || {
+ store.select_file(filter, sender, origin, opt_test_path);
+ });
+ }
+ FileManagerThreadMsg::SelectFiles(filter, sender, origin, opt_test_paths) => {
+ spawn_named("select files".to_owned(), move || {
+ store.select_files(filter, sender, origin, opt_test_paths);
+ })
+ }
+ FileManagerThreadMsg::ReadFile(sender, id, check_url_validity, origin) => {
+ spawn_named("read file".to_owned(), move || {
+ if let Err(e) = store.try_read_file(sender.clone(), id, check_url_validity,
+ origin, cancel_listener) {
+ let _ = sender.send(Err(FileManagerThreadError::BlobURLStoreError(e)));
+ }
+ })
+ }
+ FileManagerThreadMsg::PromoteMemory(blob_buf, set_valid, sender, origin) => {
+ spawn_named("transfer memory".to_owned(), move || {
+ store.promote_memory(blob_buf, set_valid, sender, origin);
+ })
+ }
+ FileManagerThreadMsg::AddSlicedURLEntry(id, rel_pos, sender, origin) =>{
+ spawn_named("add sliced URL entry".to_owned(), move || {
+ store.add_sliced_url_entry(id, rel_pos, sender, origin);
+ })
+ }
+ FileManagerThreadMsg::DecRef(id, origin, sender) => {
+ if let Ok(id) = Uuid::parse_str(&id.0) {
+ spawn_named("dec ref".to_owned(), move || {
+ // Since it is simple DecRef (possibly caused by close/drop),
+ // unset_url_validity is false
+ let _ = sender.send(store.dec_ref(&id, &origin));
})
+ } else {
+ let _ = sender.send(Err(BlobURLStoreError::InvalidFileID));
}
- FileManagerThreadMsg::AddSlicedURLEntry(id, rel_pos, sender, origin) =>{
- spawn_named("add sliced URL entry".to_owned(), move || {
- store.add_sliced_url_entry(id, rel_pos, sender, origin);
+ }
+ FileManagerThreadMsg::RevokeBlobURL(id, origin, sender) => {
+ if let Ok(id) = Uuid::parse_str(&id.0) {
+ spawn_named("revoke blob url".to_owned(), move || {
+ // Since it is revocation, unset_url_validity is true
+ let _ = sender.send(store.set_blob_url_validity(false, &id, &origin));
})
+ } else {
+ let _ = sender.send(Err(BlobURLStoreError::InvalidFileID));
}
- FileManagerThreadMsg::RevokeBlobURL(id, origin, sender) => {
- if let Ok(id) = Uuid::parse_str(&id.0) {
- spawn_named("revoke blob url".to_owned(), move || {
- // Since it is revocation, unset_url_validity is true
- let _ = sender.send(store.set_blob_url_validity(false, &id, &origin));
- })
- } else {
- let _ = sender.send(Err(BlobURLStoreError::InvalidFileID));
- }
- }
- FileManagerThreadMsg::DecRef(id, origin, sender) => {
- if let Ok(id) = Uuid::parse_str(&id.0) {
- spawn_named("dec ref".to_owned(), move || {
- // Since it is simple DecRef (possibly caused by close/drop),
- // unset_url_validity is false
- let _ = sender.send(store.dec_ref(&id, &origin));
- })
- } else {
- let _ = sender.send(Err(BlobURLStoreError::InvalidFileID));
- }
- }
- FileManagerThreadMsg::ActivateBlobURL(id, sender, origin) => {
- if let Ok(id) = Uuid::parse_str(&id.0) {
- spawn_named("activate blob url".to_owned(), move || {
- let _ = sender.send(store.set_blob_url_validity(true, &id, &origin));
- });
- } else {
- let _ = sender.send(Err(BlobURLStoreError::InvalidFileID));
- }
+ }
+ FileManagerThreadMsg::ActivateBlobURL(id, sender, origin) => {
+ if let Ok(id) = Uuid::parse_str(&id.0) {
+ spawn_named("activate blob url".to_owned(), move || {
+ let _ = sender.send(store.set_blob_url_validity(true, &id, &origin));
+ });
+ } else {
+ let _ = sender.send(Err(BlobURLStoreError::InvalidFileID));
}
- FileManagerThreadMsg::Exit => break,
- };
+ }
}
}
}
@@ -405,7 +385,8 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> {
fn get_blob_buf(&self, sender: IpcSender<FileManagerResult<ReadFileProgress>>,
id: &Uuid, origin_in: &FileOrigin, rel_pos: RelativePos,
- check_url_validity: bool) -> Result<(), BlobURLStoreError> {
+ check_url_validity: bool,
+ cancel_listener: Option<CancellationListener>) -> Result<(), BlobURLStoreError> {
let file_impl = try!(self.get_impl(id, origin_in, check_url_validity));
match file_impl {
FileImpl::Memory(buf) => {
@@ -437,7 +418,7 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> {
let range = rel_pos.to_abs_range(metadata.size as usize);
let mut file = try!(File::open(&metadata.path)
- .map_err(|e| BlobURLStoreError::External(e.to_string())));
+ .map_err(|e| BlobURLStoreError::External(e.to_string())));
let seeked_start = try!(file.seek(SeekFrom::Start(range.start as u64))
.map_err(|e| BlobURLStoreError::External(e.to_string())));
@@ -447,7 +428,8 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> {
None => "".to_string(),
};
- chunked_read(sender, &mut file, range.len(), opt_filename, type_string);
+ chunked_read(sender, &mut file, range.len(), opt_filename,
+ type_string, cancel_listener);
Ok(())
} else {
Err(BlobURLStoreError::InvalidEntry)
@@ -456,17 +438,20 @@ impl <UI: 'static + UIProvider> FileManagerStore<UI> {
FileImpl::Sliced(parent_id, inner_rel_pos) => {
// Next time we don't need to check validity since
// we have already done that for requesting URL if necessary
- self.get_blob_buf(sender, &parent_id, origin_in, rel_pos.slice_inner(&inner_rel_pos), false)
+ self.get_blob_buf(sender, &parent_id, origin_in,
+ rel_pos.slice_inner(&inner_rel_pos), false,
+ cancel_listener)
}
}
}
// Convenient wrapper over get_blob_buf
fn try_read_file(&self, sender: IpcSender<FileManagerResult<ReadFileProgress>>,
- id: SelectedFileId, check_url_validity: bool,
- origin_in: FileOrigin) -> Result<(), BlobURLStoreError> {
+ id: SelectedFileId, check_url_validity: bool, origin_in: FileOrigin,
+ cancel_listener: Option<CancellationListener>) -> Result<(), BlobURLStoreError> {
let id = try!(Uuid::parse_str(&id.0).map_err(|_| BlobURLStoreError::InvalidFileID));
- self.get_blob_buf(sender, &id, &origin_in, RelativePos::full_range(), check_url_validity)
+ self.get_blob_buf(sender, &id, &origin_in, RelativePos::full_range(),
+ check_url_validity, cancel_listener)
}
fn dec_ref(&self, id: &Uuid, origin_in: &FileOrigin) -> Result<(), BlobURLStoreError> {
@@ -580,7 +565,8 @@ fn select_files_pref_enabled() -> bool {
const CHUNK_SIZE: usize = 8192;
fn chunked_read(sender: IpcSender<FileManagerResult<ReadFileProgress>>,
- file: &mut File, size: usize, opt_filename: Option<String>, type_string: String) {
+ file: &mut File, size: usize, opt_filename: Option<String>,
+ type_string: String, cancel_listener: Option<CancellationListener>) {
// First chunk
let mut buf = vec![0; CHUNK_SIZE];
match file.read(&mut buf) {
@@ -602,6 +588,12 @@ fn chunked_read(sender: IpcSender<FileManagerResult<ReadFileProgress>>,
// Send the remaining chunks
loop {
+ if let Some(ref listener) = cancel_listener.as_ref() {
+ if listener.is_cancelled() {
+ break;
+ }
+ }
+
let mut buf = vec![0; CHUNK_SIZE];
match file.read(&mut buf) {
Ok(0) => {