Get rid of read_file_into, use streams to serve files from domain manager
This commit is contained in:
parent
8b75b141f4
commit
82290d8b0b
@ -57,8 +57,6 @@ impl From<origin::GetFileError> for GetFileError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ReadFileIntoError = GetFileError;
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum SyncError {
|
pub enum SyncError {
|
||||||
#[error("not found")]
|
#[error("not found")]
|
||||||
@ -138,13 +136,6 @@ pub type GetAcmeHttp01ChallengeKeyError = acme::manager::GetHttp01ChallengeKeyEr
|
|||||||
pub trait Manager: Sync + Send + rustls::server::ResolvesServerCert {
|
pub trait Manager: Sync + Send + rustls::server::ResolvesServerCert {
|
||||||
fn get_config(&self, domain: &domain::Name) -> Result<config::Config, GetConfigError>;
|
fn get_config(&self, domain: &domain::Name) -> Result<config::Config, GetConfigError>;
|
||||||
|
|
||||||
fn read_file_into(
|
|
||||||
&self,
|
|
||||||
domain: &domain::Name,
|
|
||||||
path: &str,
|
|
||||||
into: &mut dyn std::io::Write,
|
|
||||||
) -> Result<(), ReadFileIntoError>;
|
|
||||||
|
|
||||||
fn get_file<'store>(
|
fn get_file<'store>(
|
||||||
&'store self,
|
&'store self,
|
||||||
domain: &domain::Name,
|
domain: &domain::Name,
|
||||||
@ -237,18 +228,6 @@ impl Manager for ManagerImpl {
|
|||||||
Ok(self.domain_config_store.get(domain)?)
|
Ok(self.domain_config_store.get(domain)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_file_into(
|
|
||||||
&self,
|
|
||||||
domain: &domain::Name,
|
|
||||||
path: &str,
|
|
||||||
into: &mut dyn std::io::Write,
|
|
||||||
) -> Result<(), ReadFileIntoError> {
|
|
||||||
let config = self.domain_config_store.get(domain)?;
|
|
||||||
self.origin_store
|
|
||||||
.read_file_into(&config.origin_descr, path, into)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_file<'store>(
|
fn get_file<'store>(
|
||||||
&'store self,
|
&'store self,
|
||||||
domain: &domain::Name,
|
domain: &domain::Name,
|
||||||
|
@ -41,8 +41,6 @@ pub enum GetFileError {
|
|||||||
Unexpected(#[from] unexpected::Error),
|
Unexpected(#[from] unexpected::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ReadFileIntoError = GetFileError;
|
|
||||||
|
|
||||||
#[mockall::automock]
|
#[mockall::automock]
|
||||||
/// Describes a storage mechanism for Origins. Each Origin is uniquely identified by its Descr.
|
/// Describes a storage mechanism for Origins. Each Origin is uniquely identified by its Descr.
|
||||||
pub trait Store {
|
pub trait Store {
|
||||||
@ -52,13 +50,6 @@ pub trait Store {
|
|||||||
|
|
||||||
fn all_descrs(&self) -> Result<Vec<Descr>, AllDescrsError>;
|
fn all_descrs(&self) -> Result<Vec<Descr>, AllDescrsError>;
|
||||||
|
|
||||||
fn read_file_into(
|
|
||||||
&self,
|
|
||||||
descr: &Descr,
|
|
||||||
path: &str,
|
|
||||||
into: &mut dyn std::io::Write,
|
|
||||||
) -> Result<(), ReadFileIntoError>;
|
|
||||||
|
|
||||||
fn get_file(&self, descr: &Descr, path: &str) -> Result<util::BoxByteStream, GetFileError>;
|
fn get_file(&self, descr: &Descr, path: &str) -> Result<util::BoxByteStream, GetFileError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,16 +66,6 @@ impl Store for sync::Arc<sync::Mutex<MockStore>> {
|
|||||||
self.lock().unwrap().all_descrs()
|
self.lock().unwrap().all_descrs()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deprecated, use get_file
|
|
||||||
fn read_file_into(
|
|
||||||
&self,
|
|
||||||
descr: &Descr,
|
|
||||||
path: &str,
|
|
||||||
into: &mut dyn std::io::Write,
|
|
||||||
) -> Result<(), ReadFileIntoError> {
|
|
||||||
self.lock().unwrap().read_file_into(descr, path, into)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_file<'store>(
|
fn get_file<'store>(
|
||||||
&'store self,
|
&'store self,
|
||||||
descr: &Descr,
|
descr: &Descr,
|
||||||
|
@ -290,50 +290,6 @@ impl super::Store for FSStore {
|
|||||||
).try_collect()
|
).try_collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_file_into(
|
|
||||||
&self,
|
|
||||||
descr: &origin::Descr,
|
|
||||||
path: &str,
|
|
||||||
into: &mut dyn std::io::Write,
|
|
||||||
) -> Result<(), origin::ReadFileIntoError> {
|
|
||||||
let repo_snapshot = match self.get_repo_snapshot(descr) {
|
|
||||||
Ok(Some(repo_snapshot)) => repo_snapshot,
|
|
||||||
Ok(None) => return Err(origin::ReadFileIntoError::DescrNotSynced),
|
|
||||||
Err(e) => return Err(e.into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut clean_path = Path::new(path);
|
|
||||||
clean_path = clean_path.strip_prefix("/").unwrap_or(clean_path);
|
|
||||||
|
|
||||||
let repo = repo_snapshot.repo.to_thread_local();
|
|
||||||
|
|
||||||
let file_object = repo
|
|
||||||
.find_object(repo_snapshot.tree_object_id)
|
|
||||||
.map_unexpected_while(|| {
|
|
||||||
format!("finding tree object {}", repo_snapshot.tree_object_id)
|
|
||||||
})?
|
|
||||||
.peel_to_tree()
|
|
||||||
.map_unexpected_while(|| {
|
|
||||||
format!("peeling tree object {}", repo_snapshot.tree_object_id)
|
|
||||||
})?
|
|
||||||
.lookup_entry_by_path(clean_path)
|
|
||||||
.map_unexpected_while(|| {
|
|
||||||
format!(
|
|
||||||
"looking up {} in tree object {}",
|
|
||||||
clean_path.display(),
|
|
||||||
repo_snapshot.tree_object_id
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.ok_or(origin::ReadFileIntoError::FileNotFound)?
|
|
||||||
.object()
|
|
||||||
.or_unexpected()?;
|
|
||||||
|
|
||||||
into.write_all(file_object.data.as_ref())
|
|
||||||
.or_unexpected_while("copying out file")?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_file<'store>(
|
fn get_file<'store>(
|
||||||
&'store self,
|
&'store self,
|
||||||
descr: &origin::Descr,
|
descr: &origin::Descr,
|
||||||
@ -405,17 +361,14 @@ mod tests {
|
|||||||
store.sync(&descr).expect("sync should succeed");
|
store.sync(&descr).expect("sync should succeed");
|
||||||
store.sync(&descr).expect("second sync should succeed");
|
store.sync(&descr).expect("second sync should succeed");
|
||||||
|
|
||||||
{
|
// RepoSnapshot doesn't exist
|
||||||
// RepoSnapshot doesn't exist
|
match store.get_file(&other_descr, "DNE") {
|
||||||
let mut into: Vec<u8> = vec![];
|
Err(origin::GetFileError::DescrNotSynced) => (),
|
||||||
assert!(matches!(
|
_ => assert!(false, "descr should have not been found"),
|
||||||
store.read_file_into(&other_descr, "DNE", &mut into),
|
};
|
||||||
Err::<_, origin::ReadFileIntoError>(origin::ReadFileIntoError::DescrNotSynced),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let assert_file_dne = |path: &str| match store.get_file(&descr, path) {
|
let assert_file_dne = |path: &str| match store.get_file(&descr, path) {
|
||||||
Err(origin::ReadFileIntoError::FileNotFound) => (),
|
Err(origin::GetFileError::FileNotFound) => (),
|
||||||
_ => assert!(false, "file should have not been found"),
|
_ => assert!(false, "file should have not been found"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,17 +41,6 @@ where
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_file_into(
|
|
||||||
&self,
|
|
||||||
descr: &origin::Descr,
|
|
||||||
path: &str,
|
|
||||||
into: &mut dyn std::io::Write,
|
|
||||||
) -> Result<(), origin::ReadFileIntoError> {
|
|
||||||
(self.mapping_fn)(descr)
|
|
||||||
.or_unexpected_while(format!("mapping {:?} to store", &descr))?
|
|
||||||
.read_file_into(descr, path, into)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_file<'store>(
|
fn get_file<'store>(
|
||||||
&'store self,
|
&'store self,
|
||||||
descr: &origin::Descr,
|
descr: &origin::Descr,
|
||||||
|
@ -11,7 +11,7 @@ use std::{future, net, sync};
|
|||||||
use crate::error::unexpected;
|
use crate::error::unexpected;
|
||||||
use crate::{domain, service, util};
|
use crate::{domain, service, util};
|
||||||
|
|
||||||
type SvcResponse = Result<Response<hyper::body::Body>, String>;
|
type SvcResponse = Result<Response<Body>, String>;
|
||||||
|
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
domain_manager: sync::Arc<dyn domain::manager::Manager>,
|
domain_manager: sync::Arc<dyn domain::manager::Manager>,
|
||||||
@ -94,7 +94,7 @@ struct DomainSyncArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'svc> Service {
|
impl<'svc> Service {
|
||||||
fn serve_string(&self, status_code: u16, path: &'_ str, body: Vec<u8>) -> SvcResponse {
|
fn serve(&self, status_code: u16, path: &'_ str, body: Body) -> SvcResponse {
|
||||||
let content_type = mime_guess::from_path(path)
|
let content_type = mime_guess::from_path(path)
|
||||||
.first_or_octet_stream()
|
.first_or_octet_stream()
|
||||||
.to_string();
|
.to_string();
|
||||||
@ -102,14 +102,13 @@ impl<'svc> Service {
|
|||||||
match Response::builder()
|
match Response::builder()
|
||||||
.status(status_code)
|
.status(status_code)
|
||||||
.header("Content-Type", content_type)
|
.header("Content-Type", content_type)
|
||||||
.body(body.into())
|
.body(body)
|
||||||
{
|
{
|
||||||
Ok(res) => Ok(res),
|
Ok(res) => Ok(res),
|
||||||
Err(err) => Err(format!("failed to build {}: {}", path, err)),
|
Err(err) => Err(format!("failed to build {}: {}", path, err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//// TODO make this use an io::Write, rather than SvcResponse
|
|
||||||
fn render<T>(&self, status_code: u16, name: &'_ str, value: T) -> SvcResponse
|
fn render<T>(&self, status_code: u16, name: &'_ str, value: T) -> SvcResponse
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
@ -125,7 +124,7 @@ impl<'svc> Service {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.serve_string(status_code, name, rendered.into())
|
self.serve(status_code, name, rendered.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_error_page(&'svc self, status_code: u16, e: &'_ str) -> SvcResponse {
|
fn render_error_page(&'svc self, status_code: u16, e: &'_ str) -> SvcResponse {
|
||||||
@ -170,16 +169,15 @@ impl<'svc> Service {
|
|||||||
false => path,
|
false => path,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buf = Vec::<u8>::new();
|
match self.domain_manager.get_file(&domain, path) {
|
||||||
match self.domain_manager.read_file_into(&domain, path, &mut buf) {
|
Ok(f) => self.serve(200, path, Body::wrap_stream(f)),
|
||||||
Ok(_) => self.serve_string(200, path, buf),
|
Err(domain::manager::GetFileError::DomainNotFound) => {
|
||||||
Err(domain::manager::ReadFileIntoError::DomainNotFound) => {
|
|
||||||
return self.render_error_page(404, "Domain not found")
|
return self.render_error_page(404, "Domain not found")
|
||||||
}
|
}
|
||||||
Err(domain::manager::ReadFileIntoError::FileNotFound) => {
|
Err(domain::manager::GetFileError::FileNotFound) => {
|
||||||
self.render_error_page(404, "File not found")
|
self.render_error_page(404, "File not found")
|
||||||
}
|
}
|
||||||
Err(domain::manager::ReadFileIntoError::Unexpected(e)) => {
|
Err(domain::manager::GetFileError::Unexpected(e)) => {
|
||||||
self.render_error_page(500, format!("failed to fetch file {path}: {e}").as_str())
|
self.render_error_page(500, format!("failed to fetch file {path}: {e}").as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,14 +353,7 @@ impl<'svc> Service {
|
|||||||
let token = path.trim_start_matches("/.well-known/acme-challenge/");
|
let token = path.trim_start_matches("/.well-known/acme-challenge/");
|
||||||
|
|
||||||
if let Ok(key) = self.domain_manager.get_acme_http01_challenge_key(token) {
|
if let Ok(key) = self.domain_manager.get_acme_http01_challenge_key(token) {
|
||||||
let body: hyper::Body = key.into();
|
return self.serve(200, "token.txt", key.into());
|
||||||
return match Response::builder().status(200).body(body) {
|
|
||||||
Ok(res) => Ok(res),
|
|
||||||
Err(err) => Err(format!(
|
|
||||||
"failed to write acme http-01 challenge key: {}",
|
|
||||||
err
|
|
||||||
)),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user