Skip to content

Commit

Permalink
Add shared_dir method for Application
Browse files Browse the repository at this point in the history
  • Loading branch information
photino committed Sep 7, 2023
1 parent d5e81b9 commit a48a64b
Show file tree
Hide file tree
Showing 19 changed files with 108 additions and 60 deletions.
3 changes: 3 additions & 0 deletions examples/actix-app/config/config.dev.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
name = "data-cube"
version = "0.6.1"

[dirs]
uploads = "local/uploads"

[main]
host = "127.0.0.1"
port = 6080
Expand Down
5 changes: 4 additions & 1 deletion examples/actix-app/config/config.prod.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
name = "data-cube"
version = "0.6.1"

[dirs]
uploads = "local/uploads"

[main]
host = "127.0.0.1"
port = 6080
Expand Down Expand Up @@ -70,4 +73,4 @@ span = { "http.method" = "string", "http.target" = "string", "http.status_code"
app-name = "data-cube"

[openapi]
show-docs = false
show-docs = true
14 changes: 9 additions & 5 deletions examples/actix-app/local/docs/rapidoc.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
<script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script>
</head>
<body>
<rapi-doc spec-url="$specUrl" heading-text="RapiDoc"
schema-style="table" default-schema-tab="schema"
show-method-in-nav-bar="as-colored-block" sort-endpoints-by="method"
persist-auth="true" allow-spec-file-download="true"
<rapi-doc spec-url="$specUrl"
heading-text="RapiDoc"
schema-style="table"
default-schema-tab="schema"
show-method-in-nav-bar="as-colored-block"
sort-endpoints-by="method"
persist-auth="true"
allow-spec-file-download="true"
primary-color="#2d87e2">
</rapi-doc>
</body>
</html>
</html>
4 changes: 2 additions & 2 deletions examples/actix-app/src/controller/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use zino::{prelude::*, Cluster, Request, Response, Result};
pub async fn upload(mut req: Request) -> Result {
let (mut body, files) = req.parse_form_data::<Map>().await?;

let dir = Cluster::relative_path("local/uploads");
let dir = Cluster::shared_dir("uploads");
let expires = DateTime::now() + Duration::from_secs(600);
let mut encryption_duration = Duration::ZERO;
let mut uploads = Vec::new();
Expand Down Expand Up @@ -54,7 +54,7 @@ pub async fn decrypt(req: Request) -> Result {
let Some(file_name) = query.get_str("file_name") else {
reject!(req, "file_name", "it should be specified");
};
let file_path = Cluster::relative_path(format!("local/uploads/{file_name}"));
let file_path = Cluster::shared_dir("uploads").join(file_name);

let mut file = NamedFile::try_from_local(file_path).extract(&req)?;
let decryption_start_time = Instant::now();
Expand Down
2 changes: 1 addition & 1 deletion examples/actix-app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mod service;
use zino::prelude::*;

fn main() {
zino::Cluster::init_dirs(&["local/uploads"])
zino::Cluster::boot()
.register(router::routes())
.spawn(schedule::jobs())
.run(schedule::async_jobs())
Expand Down
3 changes: 3 additions & 0 deletions examples/axum-app/config/config.dev.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
name = "data-cube"
version = "0.6.1"

[dirs]
uploads = "local/uploads"

[main]
host = "127.0.0.1"
port = 6080
Expand Down
5 changes: 4 additions & 1 deletion examples/axum-app/config/config.prod.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
name = "data-cube"
version = "0.6.1"

[dirs]
uploads = "local/uploads"

[main]
host = "127.0.0.1"
port = 6080
Expand Down Expand Up @@ -70,4 +73,4 @@ span = { "http.method" = "string", "http.target" = "string", "http.status_code"
app-name = "data-cube"

[openapi]
show-docs = false
show-docs = true
14 changes: 9 additions & 5 deletions examples/axum-app/local/docs/rapidoc.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
<script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script>
</head>
<body>
<rapi-doc spec-url="$specUrl" heading-text="RapiDoc"
schema-style="table" default-schema-tab="schema"
show-method-in-nav-bar="as-colored-block" sort-endpoints-by="method"
persist-auth="true" allow-spec-file-download="true"
<rapi-doc spec-url="$specUrl"
heading-text="RapiDoc"
schema-style="table"
default-schema-tab="schema"
show-method-in-nav-bar="as-colored-block"
sort-endpoints-by="method"
persist-auth="true"
allow-spec-file-download="true"
primary-color="#2d87e2">
</rapi-doc>
</body>
</html>
</html>
4 changes: 2 additions & 2 deletions examples/axum-app/src/controller/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use zino::{prelude::*, Cluster, Request, Response, Result};
pub async fn upload(mut req: Request) -> Result {
let (mut body, files) = req.parse_form_data::<Map>().await?;

let dir = Cluster::relative_path("local/uploads");
let dir = Cluster::shared_dir("uploads");
let expires = DateTime::now() + Duration::from_secs(600);
let mut encryption_duration = Duration::ZERO;
let mut uploads = Vec::new();
Expand Down Expand Up @@ -54,7 +54,7 @@ pub async fn decrypt(req: Request) -> Result {
let Some(file_name) = query.get_str("file_name") else {
reject!(req, "file_name", "it should be specified");
};
let file_path = Cluster::relative_path(format!("local/uploads/{file_name}"));
let file_path = Cluster::shared_dir("uploads").join(file_name);

let mut file = NamedFile::try_from_local(file_path).extract(&req)?;
let decryption_start_time = Instant::now();
Expand Down
2 changes: 1 addition & 1 deletion examples/axum-app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mod service;
use zino::prelude::*;

fn main() {
zino::Cluster::init_dirs(&["local/uploads"])
zino::Cluster::boot()
.register(router::routes())
.spawn(schedule::jobs())
.run(schedule::async_jobs())
Expand Down
4 changes: 2 additions & 2 deletions examples/axum-app/src/middleware/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ pub async fn init_user_session(mut req: Request, next: Next<Body>) -> Result<Res
match User::verify_jwt_claims(&claims).await {
Ok(verified) => {
if verified {
let mut user_session = UserSession::<Uuid>::try_from_jwt_claims(claims)
.extract(&req)?;
let mut user_session =
UserSession::<Uuid>::try_from_jwt_claims(claims).extract(&req)?;
if let Ok(session_id) = req.parse_session_id() {
user_session.set_session_id(session_id);
}
Expand Down
3 changes: 3 additions & 0 deletions examples/dioxus-desktop/config/config.dev.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
name = "data-cube"
version = "0.1.0"

[dirs]
uploads = "local/uploads"

[window]
title = "DataCube"
theme = "Light"
Expand Down
3 changes: 3 additions & 0 deletions examples/dioxus-desktop/config/config.prod.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
name = "data-cube"
version = "0.1.0"

[dirs]
uploads = "local/uploads"

[window]
title = "DataCube"
theme = "Dark"
Expand Down
2 changes: 1 addition & 1 deletion examples/dioxus-desktop/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod service;
use zino::prelude::*;

fn main() {
zino::Desktop::init_dirs(&["local/uploads"])
zino::Desktop::boot()
.register(router::Route::default())
.spawn(schedule::jobs())
.run(schedule::async_jobs())
Expand Down
68 changes: 33 additions & 35 deletions zino-core/src/application/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,7 @@ use crate::{
};
use reqwest::Response;
use serde::de::DeserializeOwned;
use std::{
env, fs,
path::{Path, PathBuf},
sync::LazyLock,
thread,
};
use std::{env, fs, path::PathBuf, sync::LazyLock, thread};
use toml::value::Table;
use utoipa::openapi::{OpenApi, OpenApiBuilder};

Expand All @@ -41,12 +36,28 @@ pub trait Application {
/// Runs the application.
fn run(self, async_jobs: Vec<(&'static str, AsyncCronJob)>);

/// Boots the application. It also setups the default secret key,
/// the tracing subscriber, the metrics exporter and a global HTTP client.
/// Boots the application. It also initializes the required directories
/// and setups the default secret key, the tracing subscriber,
/// the metrics exporter and a global HTTP client.
fn boot() -> Self
where
Self: Default,
{
if let Some(dirs) = SHARED_APP_STATE.get_config("dirs") {
let project_dir = Self::project_dir();
for dir in dirs.values().filter_map(|v| v.as_str()) {
let path = if dir.starts_with('/') {
PathBuf::from(dir)
} else {
project_dir.join(dir)
};
if !path.exists() && let Err(err) = fs::create_dir_all(&path) {
let path = path.to_string_lossy();
tracing::error!("fail to create the directory {path}: {err}");
}
}
}

secret_key::init::<Self>();
tracing_subscriber::init::<Self>();
metrics_exporter::init::<Self>();
Expand All @@ -70,27 +81,6 @@ pub trait Application {
Self::boot()
}

/// Initializes the directories to ensure that they are ready for use,
/// then boots the application.
fn init_dirs(dirs: &[&'static str]) -> Self
where
Self: Default,
{
let project_dir = Self::project_dir();
for dir in dirs {
let path = if dir.starts_with('/') {
PathBuf::from(dir)
} else {
project_dir.join(dir)
};
if !path.exists() && let Err(err) = fs::create_dir_all(&path) {
let path = path.to_string_lossy();
tracing::error!("fail to create the directory {}: {}", path, err);
}
}
Self::boot()
}

/// Gets the system’s information.
#[inline]
fn sysinfo() -> Map {
Expand Down Expand Up @@ -159,12 +149,6 @@ pub trait Application {
LazyLock::force(&PROJECT_DIR)
}

/// Returns the path relative to the project directory.
#[inline]
fn relative_path<P: AsRef<Path>>(path: P) -> PathBuf {
PROJECT_DIR.join(path)
}

/// Returns the secret key for the application.
/// It should have at least 64 bytes.
///
Expand All @@ -176,6 +160,20 @@ pub trait Application {
SECRET_KEY.get().expect("fail to get the secret key")
}

/// Returns the shared directory with the specific name,
/// which is defined in the `dirs` table.
#[inline]
fn shared_dir(name: &str) -> PathBuf {
let path = if let Some(dirs) = SHARED_APP_STATE.get_config("dirs") &&
let Some(path) = dirs.get_str(name)
{
path
} else {
name
};
Self::project_dir().join(path)
}

/// Spawns a new thread to run cron jobs.
fn spawn(self, jobs: Vec<(&'static str, CronJob)>) -> Self
where
Expand Down
19 changes: 19 additions & 0 deletions zino-core/src/extension/json_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,25 @@ mod tests {
Map,
};

#[test]
fn it_parses_str_array() {
let mut map = Map::new();
map.upsert("roles", vec!["admin", "", "worker"]);

assert_eq!(
map.get_str_array("roles"),
Some(vec!["admin", "", "worker"])
);
assert_eq!(
map.parse_str_array("roles"),
Some(vec!["admin", "", "worker"])
);
assert_eq!(
map.parse_array::<String>("roles"),
Some(vec!["admin".to_owned(), "worker".to_owned()])
);
}

#[test]
fn it_lookups_json_value() {
let mut map = Map::new();
Expand Down
3 changes: 3 additions & 0 deletions zino-model/src/user/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ impl User {
} else if !USER_ROLE_PATTERN.is_match(role) {
let message = format!("the role `{role}` is invalid");
return Err(Error::new(message));
} else if role.is_empty() {
let message = format!("the `roles` can not contain empty values");
return Err(Error::new(message));
}
}
self.roles = roles.into_iter().map(|s| s.to_owned()).collect();
Expand Down
5 changes: 3 additions & 2 deletions zino/src/application/actix_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ impl Application for ActixCluster {
});

// Server config
let project_dir = Self::project_dir();
let mut body_limit = 100 * 1024 * 1024; // 100MB
let mut public_dir = PathBuf::new();
let default_public_dir = Self::relative_path("public");
let default_public_dir = project_dir.join("public");
if let Some(server_config) = Self::config().get_table("server") {
if let Some(limit) = server_config.get_usize("body-limit") {
body_limit = limit;
Expand Down Expand Up @@ -111,7 +112,7 @@ impl Application for ActixCluster {
RapiDoc::with_openapi("/api-docs/openapi.json", Self::openapi())
.path("/rapidoc");
if let Some(custom_html) = openapi_config.get_str("custom-html") &&
let Ok(html) = fs::read_to_string(Self::relative_path(custom_html))
let Ok(html) = fs::read_to_string(project_dir.join(custom_html))
{
rapidoc = rapidoc.custom_html(html.leak());
}
Expand Down
5 changes: 3 additions & 2 deletions zino/src/application/axum_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ impl Application for AxumCluster {
});

// Server config
let project_dir = Self::project_dir();
let mut body_limit = 100 * 1024 * 1024; // 100MB
let mut request_timeout = Duration::from_secs(10); // 10 seconds
let mut public_dir = PathBuf::new();
let default_public_dir = Self::relative_path("public");
let default_public_dir = project_dir.join("public");
if let Some(server_config) = Self::config().get_table("server") {
if let Some(limit) = server_config.get_usize("body-limit") {
body_limit = limit;
Expand Down Expand Up @@ -119,7 +120,7 @@ impl Application for AxumCluster {
RapiDoc::with_openapi("/api-docs/openapi.json", Self::openapi())
.path("/rapidoc");
if let Some(custom_html) = openapi_config.get_str("custom-html") &&
let Ok(html) = fs::read_to_string(Self::relative_path(custom_html))
let Ok(html) = fs::read_to_string(project_dir.join(custom_html))
{
app = app.merge(rapidoc.custom_html(html.as_str()));
} else {
Expand Down

0 comments on commit a48a64b

Please sign in to comment.