Skip to content

Commit

Permalink
Bundle the default public directory and serve it by default.
Browse files Browse the repository at this point in the history
It is important to have a default public directory, because the
default HTML fragments for api.toml assume the existence of
`style.css` and some icons. This can lead to confusing behavior
where the user has not custom-configured anything, but the website
doesn't display correctly out of the box, unless this directory is
included whenever the default HTML is included.
  • Loading branch information
jbearer committed Aug 18, 2022
1 parent eb6b3bf commit ba83d4a
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ edit-distance = "2.1.0"
futures = "0.3.21"
futures-util = "0.3.8"
http = "0.2.7"
include_dir = "0.7"
jf-utils = { features = ["std"], git = "https://github.com/EspressoSystems/jellyfish.git", tag = "0.1.1" }
lazy_static = "1.4.0"
libc = "0.2.126"
Expand Down
9 changes: 1 addition & 8 deletions examples/hello-world/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ use futures::FutureExt;
use serde::{Deserialize, Serialize};
use snafu::Snafu;
use std::io;
use std::path::PathBuf;
use std::str::FromStr;
use tide_disco::{http::StatusCode, Api, App, Error, RequestError};
use tracing::info;

Expand Down Expand Up @@ -40,12 +38,7 @@ async fn serve(port: u16) -> io::Result<()> {

let mut api =
Api::<RwLock<String>, HelloError>::from_file("examples/hello-world/api.toml").unwrap();
api.with_version(env!("CARGO_PKG_VERSION").parse().unwrap())
.with_public(
PathBuf::from_str(env!("CARGO_MANIFEST_DIR"))
.unwrap()
.join("public/media"),
);
api.with_version(env!("CARGO_PKG_VERSION").parse().unwrap());

// Can invoke by browsing
// `http://0.0.0.0:8080/hello/greeting/dude`
Expand Down
Empty file added public/media/js/script.js
Empty file.
33 changes: 30 additions & 3 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,20 @@ use crate::{
};
use async_std::sync::Arc;
use futures::future::BoxFuture;
use include_dir::{include_dir, Dir};
use lazy_static::lazy_static;
use maud::html;
use semver::Version;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
use snafu::{ResultExt, Snafu};
use std::collections::hash_map::{Entry, HashMap};
use std::convert::Infallible;
use std::env;
use std::fs;
use std::io;
use std::ops::{Deref, DerefMut};
use std::path::PathBuf;
use tide::{
http::{headers::HeaderValue, mime},
security::{CorsMiddleware, Origin},
Expand Down Expand Up @@ -196,15 +201,37 @@ impl<State: Send + Sync + 'static, Error: 'static> App<State, Error> {
}
}

static DEFAULT_PUBLIC_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/public/media");
lazy_static! {
static ref DEFAULT_PUBLIC_PATH: PathBuf = {
// The contents of the default public directory are included in the binary. The first time
// the default directory is used, if ever, we extract them to a directory on the host file
// system and return the path to that directory.
let path = dirs::data_local_dir()
.unwrap_or_else(|| env::current_dir().unwrap_or_else(|_| PathBuf::from("./")))
.join("tide-disco/public/media");
// If the path already exists, move it aside so we can update it.
let _ = fs::rename(&path, path.with_extension("old"));
DEFAULT_PUBLIC_DIR.extract(&path).unwrap();
path
};
}

impl<State: Send + Sync + 'static, Error: 'static + crate::Error> App<State, Error> {
/// Serve the [App] asynchronously.
pub async fn serve<L: ToListener<Arc<Self>>>(self, listener: L) -> io::Result<()> {
let state = Arc::new(self);
let mut server = tide::Server::with_state(state.clone());
for (name, api) in &state.apis {
if let Some(path) = api.public() {
server.at("/public").at(name).serve_dir(path)?;
}
// Clippy complains if the only non-trivial operation in an `unwrap_or_else` closure is
// a deref, but for `lazy_static` types, deref is an effectful operation that (in this
// case) causes a directory to be renamed and another extracted. We only want to execute
// this if we need to (if `api.public()` is `None`) so we disable the lint.
#[allow(clippy::unnecessary_lazy_evaluations)]
server
.at("/public")
.at(name)
.serve_dir(api.public().unwrap_or_else(|| &DEFAULT_PUBLIC_PATH))?;
}
server.with(add_error_body::<_, Error>);
server.with(
Expand Down

0 comments on commit ba83d4a

Please sign in to comment.