Use a Mutex to protect the URI storage

get_uri()/set_uri() can be called at any time from any thread, only
all other methods of Source/Sink are guaranteed to be called by only
a single thread at a time.
This commit is contained in:
Sebastian Dröge 2016-05-23 20:29:01 +03:00
parent 2d4dd7a218
commit 8514d46092
3 changed files with 45 additions and 24 deletions

View file

@ -21,13 +21,14 @@ use std::path::PathBuf;
use url::Url; use url::Url;
use std::io::Write; use std::io::Write;
use std::sync::Mutex;
use utils::*; use utils::*;
use rssink::*; use rssink::*;
#[derive(Debug)] #[derive(Debug)]
pub struct FileSink { pub struct FileSink {
location: Option<PathBuf>, location: Mutex<Option<PathBuf>>,
file: Option<File>, file: Option<File>,
position: u64, position: u64,
} }
@ -37,7 +38,7 @@ unsafe impl Send for FileSink {}
impl FileSink { impl FileSink {
fn new() -> FileSink { fn new() -> FileSink {
FileSink { location: None, file: None, position: 0 } FileSink { location: Mutex::new(None), file: None, position: 0 }
} }
fn new_source() -> Box<Sink> { fn new_source() -> Box<Sink> {
@ -53,7 +54,8 @@ impl Sink for FileSink {
fn set_uri(&mut self, uri_str: Option<&str>) -> bool { fn set_uri(&mut self, uri_str: Option<&str>) -> bool {
match uri_str { match uri_str {
None => { None => {
self.location = None; let mut location = self.location.lock().unwrap();
*location = None;
return true; return true;
}, },
Some(ref uri_str) => { Some(ref uri_str) => {
@ -62,18 +64,21 @@ impl Sink for FileSink {
Ok(u) => { Ok(u) => {
match u.to_file_path().ok() { match u.to_file_path().ok() {
Some(p) => { Some(p) => {
self.location = Some(p); let mut location = self.location.lock().unwrap();
*location = Some(p);
return true; return true;
}, },
None => { None => {
self.location = None; let mut location = self.location.lock().unwrap();
*location = None;
println_err!("Unsupported file URI '{}'", uri_str); println_err!("Unsupported file URI '{}'", uri_str);
return false; return false;
} }
} }
}, },
Err(err) => { Err(err) => {
self.location = None; let mut location = self.location.lock().unwrap();
*location = None;
println_err!("Failed to parse URI '{}': {}", uri_str, err); println_err!("Failed to parse URI '{}': {}", uri_str, err);
return false; return false;
} }
@ -83,7 +88,8 @@ impl Sink for FileSink {
} }
fn get_uri(&self) -> Option<String> { fn get_uri(&self) -> Option<String> {
self.location.as_ref() let location = self.location.lock().unwrap();
(*location).as_ref()
.map(|l| Url::from_file_path(l).ok()) .map(|l| Url::from_file_path(l).ok())
.and_then(|i| i) // join() .and_then(|i| i) // join()
.map(|u| u.into_string()) .map(|u| u.into_string())
@ -93,7 +99,8 @@ impl Sink for FileSink {
self.file = None; self.file = None;
self.position = 0; self.position = 0;
match self.location { let location = self.location.lock().unwrap();
match *location {
None => return false, None => return false,
Some(ref location) => { Some(ref location) => {
match File::create(location.as_path()) { match File::create(location.as_path()) {

View file

@ -19,6 +19,7 @@ use std::u64;
use std::io::{Read, Seek, SeekFrom}; use std::io::{Read, Seek, SeekFrom};
use std::fs::File; use std::fs::File;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Mutex;
use url::Url; use url::Url;
use std::io::Write; use std::io::Write;
@ -28,7 +29,7 @@ use rssource::*;
#[derive(Debug)] #[derive(Debug)]
pub struct FileSrc { pub struct FileSrc {
location: Option<PathBuf>, location: Mutex<Option<PathBuf>>,
file: Option<File>, file: Option<File>,
position: u64, position: u64,
} }
@ -38,7 +39,7 @@ unsafe impl Send for FileSrc {}
impl FileSrc { impl FileSrc {
fn new() -> FileSrc { fn new() -> FileSrc {
FileSrc { location: None, file: None, position: 0 } FileSrc { location: Mutex::new(None), file: None, position: 0 }
} }
fn new_source() -> Box<Source> { fn new_source() -> Box<Source> {
@ -54,7 +55,8 @@ impl Source for FileSrc {
fn set_uri(&mut self, uri_str: Option<&str>) -> bool { fn set_uri(&mut self, uri_str: Option<&str>) -> bool {
match uri_str { match uri_str {
None => { None => {
self.location = None; let mut location = self.location.lock().unwrap();
*location = None;
return true; return true;
}, },
Some(ref uri_str) => { Some(ref uri_str) => {
@ -63,18 +65,21 @@ impl Source for FileSrc {
Ok(u) => { Ok(u) => {
match u.to_file_path().ok() { match u.to_file_path().ok() {
Some(p) => { Some(p) => {
self.location = Some(p); let mut location = self.location.lock().unwrap();
*location = Some(p);
return true; return true;
}, },
None => { None => {
self.location = None; let mut location = self.location.lock().unwrap();
*location = None;
println_err!("Unsupported file URI '{}'", uri_str); println_err!("Unsupported file URI '{}'", uri_str);
return false; return false;
} }
} }
}, },
Err(err) => { Err(err) => {
self.location = None; let mut location = self.location.lock().unwrap();
*location = None;
println_err!("Failed to parse URI '{}': {}", uri_str, err); println_err!("Failed to parse URI '{}': {}", uri_str, err);
return false; return false;
} }
@ -84,7 +89,8 @@ impl Source for FileSrc {
} }
fn get_uri(&self) -> Option<String> { fn get_uri(&self) -> Option<String> {
self.location.as_ref() let location = self.location.lock().unwrap();
(*location).as_ref()
.map(|l| Url::from_file_path(l).ok()) .map(|l| Url::from_file_path(l).ok())
.and_then(|i| i) // join() .and_then(|i| i) // join()
.map(|u| u.into_string()) .map(|u| u.into_string())
@ -105,8 +111,9 @@ impl Source for FileSrc {
fn start(&mut self) -> bool { fn start(&mut self) -> bool {
self.file = None; self.file = None;
self.position = 0; self.position = 0;
let location = self.location.lock().unwrap();
match self.location { match *location {
None => return false, None => return false,
Some(ref location) => { Some(ref location) => {
match File::open(location.as_path()) { match File::open(location.as_path()) {

View file

@ -23,13 +23,14 @@ use hyper::client::Client;
use hyper::client::response::Response; use hyper::client::response::Response;
use std::io::Write; use std::io::Write;
use std::sync::Mutex;
use utils::*; use utils::*;
use rssource::*; use rssource::*;
#[derive(Debug)] #[derive(Debug)]
pub struct HttpSrc { pub struct HttpSrc {
url: Option<Url>, url: Mutex<Option<Url>>,
client: Client, client: Client,
response: Option<Response>, response: Option<Response>,
seekable: bool, seekable: bool,
@ -44,7 +45,7 @@ unsafe impl Send for HttpSrc {}
impl HttpSrc { impl HttpSrc {
fn new() -> HttpSrc { fn new() -> HttpSrc {
HttpSrc { url: None, client: Client::new(), response: None, seekable: false, position: 0, size: u64::MAX, start: 0, stop: u64::MAX } HttpSrc { url: Mutex::new(None), client: Client::new(), response: None, seekable: false, position: 0, size: u64::MAX, start: 0, stop: u64::MAX }
} }
fn new_source() -> Box<Source> { fn new_source() -> Box<Source> {
@ -61,7 +62,8 @@ impl HttpSrc {
self.position = 0; self.position = 0;
self.size = u64::MAX; self.size = u64::MAX;
match self.url { let url = self.url.lock().unwrap();
match *url {
None => return false, None => return false,
Some(ref url) => { Some(ref url) => {
let mut req = self.client.get(url.clone()); let mut req = self.client.get(url.clone());
@ -131,7 +133,8 @@ impl Source for HttpSrc {
match uri_str { match uri_str {
None => { None => {
self.url = None; let mut url = self.url.lock().unwrap();
*url = None;
return true; return true;
}, },
Some(ref uri_str) => { Some(ref uri_str) => {
@ -140,16 +143,19 @@ impl Source for HttpSrc {
Ok(u) => { Ok(u) => {
if u.scheme() == "http" || if u.scheme() == "http" ||
u.scheme() == "https" { u.scheme() == "https" {
self.url = Some(u); let mut url = self.url.lock().unwrap();
*url = Some(u);
return true; return true;
} else { } else {
self.url = None; let mut url = self.url.lock().unwrap();
*url = None;
println_err!("Unsupported file URI '{}'", uri_str); println_err!("Unsupported file URI '{}'", uri_str);
return false; return false;
} }
}, },
Err(err) => { Err(err) => {
self.url = None; let mut url = self.url.lock().unwrap();
*url = None;
println_err!("Failed to parse URI '{}': {}", uri_str, err); println_err!("Failed to parse URI '{}': {}", uri_str, err);
return false; return false;
} }
@ -159,7 +165,8 @@ impl Source for HttpSrc {
} }
fn get_uri(&self) -> Option<String> { fn get_uri(&self) -> Option<String> {
self.url.as_ref().map(|u| String::from(u.as_str())) let url = self.url.lock().unwrap();
(*url).as_ref().map(|u| String::from(u.as_str()))
} }
fn is_seekable(&self) -> bool { fn is_seekable(&self) -> bool {