diff --git a/src/gtfs/mod.rs b/src/gtfs/mod.rs index 6a0d3f53f..e079ceb6b 100644 --- a/src/gtfs/mod.rs +++ b/src/gtfs/mod.rs @@ -333,13 +333,7 @@ where /// Imports a `Model` from the [GTFS](https://gtfs.org/reference/static) /// files in the `path` directory. /// -/// The `config_path` argument allows you to give a path to a file -/// containing a json representing the contributor and dataset used -/// for this GTFS. If not given, default values will be created. -/// -/// The `prefix` argument is a string that will be prepended to every -/// identifiers, allowing to namespace the dataset. By default, no -/// prefix will be added to the identifiers. +/// The `Configuration` is used to control various parameters during the import. pub fn read_from_path>(p: P, configuration: Configuration) -> Result { let mut file_handle = read_utils::PathFileHandler::new(p.as_ref().to_path_buf()); read(&mut file_handle, configuration) @@ -348,15 +342,33 @@ pub fn read_from_path>(p: P, configuration: Configuration) -> Res /// Imports a `Model` from a zip file containing the /// [GTFS](https://gtfs.org/reference/static). /// -/// The `config_path` argument allows you to give a path to a file -/// containing a json representing the contributor and dataset used -/// for this GTFS. If not given, default values will be created. +/// The `Configuration` is used to control various parameters during the import. +pub fn read_from_zip>(p: P, configuration: Configuration) -> Result { + let reader = std::fs::File::open(p.as_ref())?; + let mut file_handler = read_utils::ZipHandler::new(reader, p)?; + read(&mut file_handler, configuration) +} + +/// Imports a `Model` from an object implementing `Read` and `Seek` and containing the +/// [GTFS](https://gtfs.org/reference/static). /// -/// The `prefix` argument is a string that will be prepended to every -/// identifiers, allowing to namespace the dataset. By default, no -/// prefix will be added to the identifiers. -pub fn read_from_zip>(path: P, configuration: Configuration) -> Result { - let mut file_handler = read_utils::ZipHandler::new(path)?; +/// This method makes it possible to read from a variety of sources like read a GTFS +/// from the network. +/// +/// ``` +// let url = "http://some_url/gtfs.zip"; +// let resp = reqwest::blocking::get(url)?; // or async call +// let data = std::io::Cursor::new(resp.bytes()?.to_vec()); +// let model = transit_model::gtfs::from_read(data, &url, configuration)?; +/// ``` +/// +/// The `source_name` is needed to have nicer error messages. +/// The `Configuration` is used to control various parameters during the import. +pub fn from_read(reader: R, source_name: &str, configuration: Configuration) -> Result +where + R: std::io::Seek + std::io::Read, +{ + let mut file_handler = read_utils::ZipHandler::new(reader, &source_name)?; read(&mut file_handler, configuration) } diff --git a/src/read_utils.rs b/src/read_utils.rs index ce30e46c1..73fcf67e6 100644 --- a/src/read_utils.rs +++ b/src/read_utils.rs @@ -20,10 +20,10 @@ use crate::{ use failure::{format_err, ResultExt}; use log::info; use serde::Deserialize; -use std::collections::BTreeMap; -use std::fs::File; use std::path; use std::path::{Path, PathBuf}; +use std::{collections::BTreeMap, io::Read}; +use std::{fs::File, io::Seek}; use typed_index_collection::{CollectionWithId, Id}; #[derive(Deserialize, Debug)] @@ -97,7 +97,7 @@ pub(crate) trait FileHandler where Self: std::marker::Sized, { - type Reader: std::io::Read; + type Reader: Read; fn get_file_if_exists(self, name: &str) -> Result<(Option, PathBuf)>; @@ -142,16 +142,18 @@ impl<'a, P: AsRef> FileHandler for &'a mut PathFileHandler

{ /// Unlike ZipArchive, it gives access to a file by its name not regarding its path in the ZipArchive /// It thus cannot be correct if there are 2 files with the same name in the archive, /// but for transport data if will make it possible to handle a zip with a sub directory -pub(crate) struct ZipHandler { - archive: zip::ZipArchive, +pub(crate) struct ZipHandler { + archive: zip::ZipArchive, archive_path: PathBuf, index_by_name: BTreeMap, } -impl ZipHandler { - pub(crate) fn new>(path: P) -> Result { - let file = File::open(path.as_ref())?; - let mut archive = zip::ZipArchive::new(file)?; +impl ZipHandler +where + R: Seek + Read, +{ + pub(crate) fn new>(r: R, path: P) -> Result { + let mut archive = zip::ZipArchive::new(r)?; Ok(ZipHandler { index_by_name: Self::files_by_name(&mut archive), archive, @@ -159,7 +161,7 @@ impl ZipHandler { }) } - fn files_by_name(archive: &mut zip::ZipArchive) -> BTreeMap { + fn files_by_name(archive: &mut zip::ZipArchive) -> BTreeMap { (0..archive.len()) .filter_map(|i| { let file = archive.by_index(i).ok()?; @@ -172,7 +174,10 @@ impl ZipHandler { } } -impl<'a> FileHandler for &'a mut ZipHandler { +impl<'a, R> FileHandler for &'a mut ZipHandler +where + R: Seek + Read, +{ type Reader = zip::read::ZipFile<'a>; fn get_file_if_exists(self, name: &str) -> Result<(Option, PathBuf)> { let p = self.archive_path.join(name); @@ -273,8 +278,9 @@ mod tests { #[test] fn zip_file_handler() { - let mut file_handler = - ZipHandler::new(PathBuf::from("tests/fixtures/file-handler.zip")).unwrap(); + let p = "tests/fixtures/file-handler.zip"; + let reader = File::open(p).unwrap(); + let mut file_handler = ZipHandler::new(reader, p).unwrap(); { let (mut hello, _) = file_handler.get_file("hello.txt").unwrap();