Skip to content

Commit

Permalink
Add static file server to http service (#483)
Browse files Browse the repository at this point in the history
* Add static file server to `http` service

* Create blobs directory when it doesn't exist

* Export `BLOBS_DIR_NAME` const

* Update CHANGELOG

* Create temporary base_path dir when Configuration is ephemeral

* `fmt`

* Create all dirs in one step

* Change CHANGELOG
  • Loading branch information
sandreae committed Aug 31, 2023
1 parent e5ac150 commit 57c85ab
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- Serve static files from `blobs` directory [#480](https://github.com/p2panda/aquadoggo/pull/480)
- Add method to store for pruning document views [#491](https://github.com/p2panda/aquadoggo/pull/491)
- Introduce `BlobStore` [#484](https://github.com/p2panda/aquadoggo/pull/484)

Expand Down
45 changes: 34 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion aquadoggo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ tokio = { version = "1.28.2", features = [
"time",
] }
tokio-stream = { version = "0.1.14", features = ["sync"] }
tower-http = { version = "0.3.4", default-features = false, features = [
tower-http = { version = "0.4.0", default-features = false, features = [
"cors",
"fs",
] }
triggered = "0.1.2"
void = "1.0.2"
Expand Down Expand Up @@ -109,5 +110,6 @@ rstest = "0.15.0"
rstest_reuse = "0.3.0"
serde_bytes = "0.11.12"
serde_json = "1.0.85"
tempfile = "3.7.0"
tower = "0.4.13"
tower-service = "0.3.2"
9 changes: 9 additions & 0 deletions aquadoggo/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ use p2panda_rs::schema::SchemaId;

use crate::network::NetworkConfiguration;

/// Data directory name.
const DATA_DIR_NAME: &str = "aquadoggo";

/// Filename of default sqlite database.
const DEFAULT_SQLITE_NAME: &str = "aquadoggo-node.sqlite3";

/// Blobs directory
pub const BLOBS_DIR_NAME: &str = "blobs";

/// Configuration object holding all important variables throughout the application.
#[derive(Debug, Clone)]
pub struct Configuration {
Expand Down
8 changes: 4 additions & 4 deletions aquadoggo/src/graphql/mutations/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ mod tests {

use crate::bus::ServiceMessage;
use crate::graphql::GraphQLSchemaManager;
use crate::http::HttpServiceContext;
use crate::http::{HttpServiceContext, BLOBS_ROUTE};
use crate::test_utils::{
add_schema, doggo_fields, doggo_schema, graphql_test_client, populate_and_materialize,
populate_store_config, test_runner, TestNode,
Expand Down Expand Up @@ -237,7 +237,7 @@ mod tests {
node.context.schema_provider.clone(),
)
.await;
let context = HttpServiceContext::new(manager);
let context = HttpServiceContext::new(manager, BLOBS_ROUTE.into());

let response = context.schema.execute(publish_request).await;

Expand Down Expand Up @@ -298,7 +298,7 @@ mod tests {
node.context.schema_provider.clone(),
)
.await;
let context = HttpServiceContext::new(manager);
let context = HttpServiceContext::new(manager, BLOBS_ROUTE.into());

let response = context
.schema
Expand Down Expand Up @@ -326,7 +326,7 @@ mod tests {
node.context.schema_provider.clone(),
)
.await;
let context = HttpServiceContext::new(manager);
let context = HttpServiceContext::new(manager, BLOBS_ROUTE.into());

context.schema.execute(publish_request).await;

Expand Down
12 changes: 10 additions & 2 deletions aquadoggo/src/http/context.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

use std::path::PathBuf;

use crate::graphql::GraphQLSchemaManager;

#[derive(Clone)]
pub struct HttpServiceContext {
/// Dynamic GraphQL schema manager.
pub schema: GraphQLSchemaManager,

/// Path of the directory where blobs should be served from
pub blob_dir_path: PathBuf,
}

impl HttpServiceContext {
/// Create a new HttpServiceContext.
pub fn new(schema: GraphQLSchemaManager) -> Self {
Self { schema }
pub fn new(schema: GraphQLSchemaManager, blob_dir_path: PathBuf) -> Self {
Self {
schema,
blob_dir_path,
}
}
}
2 changes: 1 addition & 1 deletion aquadoggo/src/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ mod context;
mod service;

pub use context::HttpServiceContext;
pub use service::{build_server, http_service};
pub use service::{build_server, http_service, BLOBS_ROUTE};
23 changes: 21 additions & 2 deletions aquadoggo/src/http/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,22 @@ use axum::Router;
use http::header::CONTENT_TYPE;
use log::{debug, warn};
use tower_http::cors::{Any, CorsLayer};
use tower_http::services::ServeDir;

use crate::bus::ServiceSender;
use crate::config::BLOBS_DIR_NAME;
use crate::context::Context;
use crate::graphql::GraphQLSchemaManager;
use crate::http::api::{handle_graphql_playground, handle_graphql_query};
use crate::http::context::HttpServiceContext;
use crate::manager::{ServiceReadySender, Shutdown};

/// Route to the GraphQL playground
const GRAPHQL_ROUTE: &str = "/graphql";

/// Route to the blobs static file server
pub const BLOBS_ROUTE: &str = "/blobs";

/// Build HTTP server with GraphQL API.
pub fn build_server(http_context: HttpServiceContext) -> Router {
// Configure CORS middleware
Expand All @@ -29,7 +35,12 @@ pub fn build_server(http_context: HttpServiceContext) -> Router {
.allow_credentials(false)
.allow_origin(Any);

// Construct static file server
let blob_service = ServeDir::new(http_context.blob_dir_path.clone());

Router::new()
// Add blobs static file server
.nest_service(BLOBS_ROUTE, blob_service)
// Add GraphQL routes
.route(
GRAPHQL_ROUTE,
Expand All @@ -55,8 +66,15 @@ pub async fn http_service(
let graphql_schema_manager =
GraphQLSchemaManager::new(context.store.clone(), tx, context.schema_provider.clone()).await;

let blob_dir_path = context
.config
.base_path
.as_ref()
.expect("Base path not set")
.join(BLOBS_DIR_NAME);

// Introduce a new context for all HTTP routes
let http_context = HttpServiceContext::new(graphql_schema_manager);
let http_context = HttpServiceContext::new(graphql_schema_manager, blob_dir_path);

// Start HTTP server with given port and re-attempt with random port if it was taken already
let builder = if let Ok(builder) = axum::Server::try_bind(&http_address) {
Expand Down Expand Up @@ -95,6 +113,7 @@ mod tests {

use crate::graphql::GraphQLSchemaManager;
use crate::http::context::HttpServiceContext;
use crate::http::service::BLOBS_DIR_NAME;
use crate::schema::SchemaProvider;
use crate::test_utils::TestClient;
use crate::test_utils::{test_runner, TestNode};
Expand All @@ -108,7 +127,7 @@ mod tests {
let schema_provider = SchemaProvider::default();
let graphql_schema_manager =
GraphQLSchemaManager::new(node.context.store.clone(), tx, schema_provider).await;
let context = HttpServiceContext::new(graphql_schema_manager);
let context = HttpServiceContext::new(graphql_schema_manager, BLOBS_DIR_NAME.into());
let client = TestClient::new(build_server(context));

let response = client
Expand Down
4 changes: 2 additions & 2 deletions aquadoggo/src/test_utils/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use tower::make::Shared;
use tower_service::Service;

use crate::graphql::GraphQLSchemaManager;
use crate::http::{build_server, HttpServiceContext};
use crate::http::{build_server, HttpServiceContext, BLOBS_ROUTE};
use crate::test_utils::TestNode;

/// GraphQL client which can be used for querying a node in tests.
Expand Down Expand Up @@ -74,7 +74,7 @@ pub async fn graphql_test_client(node: &TestNode) -> TestClient {
node.context.schema_provider.clone(),
)
.await;
let http_context = HttpServiceContext::new(manager);
let http_context = HttpServiceContext::new(manager, BLOBS_ROUTE.into());
TestClient::new(build_server(http_context))
}

Expand Down

0 comments on commit 57c85ab

Please sign in to comment.