Skip to content

Commit

Permalink
New category info endpoint and FS methods to support
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-robbins committed Apr 2, 2024
1 parent f73dee7 commit 4f4d6d0
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 14 deletions.
11 changes: 4 additions & 7 deletions config.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
[agent]
port = 3000
name = "Agent Smith"
base_path = "/path/to/stuff"
base_path = "C:\\media"

[[categories]]
name = "Category A"
relative_path = "a/"

[[categories]]
name = "Category B"
relative_path = "tv"
id = "movies"
name = "Movies"
relative_path = "movies\\"
1 change: 1 addition & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct AgentConfig {

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Category {
pub id: String,
pub name: String,
pub relative_path: String,
}
Expand Down
38 changes: 38 additions & 0 deletions src/filesystem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::{Path, PathBuf};

/* generic functions */
pub fn build_path(base_path: &String, category_path: &String) -> PathBuf {
Path::new(base_path).join(category_path)
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub(crate) struct CategoryItem {
category: String,
id: String,
name: String,
items: Vec<CategoryItem>,
}

fn entry_to_item(entry: fs::DirEntry, category_id: String) -> CategoryItem {
CategoryItem {
category: category_id.clone(),
id: entry.file_name().into_string().unwrap(),
name: entry.file_name().into_string().unwrap(),
items: vec![],
}
}

pub fn get_category_items(category_path: PathBuf, category_id: String) -> Vec<CategoryItem> {
match fs::read_dir(category_path) {
Err(why) => {
println!("ERROR: Unable to list path: {:?}", why.kind());
vec![]
}
Ok(paths) => paths
.filter(|i| i.as_ref().unwrap().file_type().unwrap().is_dir())
.map(|i| entry_to_item(i.unwrap(), category_id.clone()))
.collect(),
}
}
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod config;
mod filesystem;
mod tasks;

use axum::{routing::get, Router};
Expand All @@ -15,7 +16,8 @@ async fn main() {
/* configure application routes */
let app = Router::new()
.route("/", get(tasks::help))
.route("/api/v1/discover", get(tasks::category_listing))
.route("/api/v1/categories", get(tasks::category_listing))
.route("/api/v1/categories/:id", get(tasks::category_info))
.with_state(data.clone());

/* bind to the port and listen */
Expand Down
53 changes: 47 additions & 6 deletions src/tasks.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::config;
use crate::filesystem;
use axum::{
extract::State,
extract::{Path, State},
http::StatusCode,
response::{Html, IntoResponse},
response::{Html, IntoResponse, Response},
Json,
};
use serde::{Deserialize, Serialize};
Expand All @@ -11,13 +12,53 @@ pub async fn help() -> Html<&'static str> {
Html("Please visit <a href='https://github.com/dalmura/stignore-agent'>the documentation</a> for further information")
}

// Category Listing Endpoint
// GET categories
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CategoryListingResponse {
pub(crate) categories: Vec<String>,
struct CategoryListingResponse {
categories: Vec<String>,
}

pub async fn category_listing(State(data): State<config::Data>) -> impl IntoResponse {
let categories: Vec<String> = data.categories.iter().map(|x| x.name.clone()).collect();
let categories: Vec<String> = data.categories.iter().map(|x| x.id.clone()).collect();
(StatusCode::OK, Json(CategoryListingResponse { categories }))
}

// GET category info
#[derive(Debug, Serialize, Deserialize, Clone)]
struct CategoryInfoResponse {
name: String,
items: Vec<filesystem::CategoryItem>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
struct CategoryInfoNotFoundResponse {
message: String,
}

pub async fn category_info(
State(data): State<config::Data>,
Path(category_id): Path<String>,
) -> Response {
match data.categories.iter().find(|x| x.id == category_id) {
Some(category) => {
let category_path =
filesystem::build_path(&data.agent.base_path, &category.relative_path);

(
StatusCode::OK,
Json(CategoryInfoResponse {
name: category.name.clone(),
items: filesystem::get_category_items(category_path, category.id.clone()),
}),
)
.into_response()
}
None => (
StatusCode::NOT_FOUND,
Json(CategoryInfoNotFoundResponse {
message: "Category ID not found".to_string(),
}),
)
.into_response(),
}
}

0 comments on commit 4f4d6d0

Please sign in to comment.