Skip to content

Commit

Permalink
Merge branch 'static-file-server' into blobs
Browse files Browse the repository at this point in the history
  • Loading branch information
sandreae committed Aug 4, 2023
2 parents 149d5f6 + 2b400ef commit 37a0ef5
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 23 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased.Blobs]

- Serve static files from `blobs` directory [#480](https://github.com/p2panda/aquadoggo/pull/480)

## [Unreleased]

### Added
Expand Down
54 changes: 43 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 @@ -76,8 +76,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"

Expand Down Expand Up @@ -105,5 +106,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"
8 changes: 8 additions & 0 deletions aquadoggo/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ 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.
///
/// Each configuration also assures that a data directory exists on the host machine where database
Expand Down Expand Up @@ -81,6 +84,7 @@ impl Configuration {

// Create folders when they don't exist yet
fs::create_dir_all(&base_path)?;
fs::create_dir(base_path.join(BLOBS_DIR_NAME))?;

Ok(base_path)
}
Expand Down Expand Up @@ -115,8 +119,12 @@ impl Configuration {
impl Configuration {
/// Returns a new configuration object for a node which stores all data temporarily in memory.
pub fn new_ephemeral() -> Self {
let tmp_dir = tempfile::TempDir::new().unwrap();
let tmp_path = tmp_dir.path().to_owned();

Configuration {
database_url: Some("sqlite::memory:".to_string()),
base_path: Some(tmp_path),
..Default::default()
}
}
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);

axum::Server::try_bind(&http_address)?
.serve(build_server(http_context).into_make_service())
Expand All @@ -80,6 +98,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 @@ -93,7 +112,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 37a0ef5

Please sign in to comment.