Skip to content
This repository was archived by the owner on Apr 5, 2024. It is now read-only.

Commit 7a6ccc9

Browse files
committed
Refactored util functions
1 parent 0d830b9 commit 7a6ccc9

File tree

11 files changed

+135
-147
lines changed

11 files changed

+135
-147
lines changed

.github/workflows/featureRelease.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@ on:
55
push:
66
branches:
77
- "feature/**"
8-
paths:
9-
- "src/**"
10-
- "src/api/**"
11-
- "src/server/**"
12-
- "**/Cargo.toml"
13-
- "**/Cargo.lock"
148

159
jobs:
1610
Build_Docker_Image_on_Push:

.github/workflows/featureTests.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@ on:
66
branches:
77
- "feature/**"
88
- "renovate/**"
9-
paths:
10-
- "src/**"
11-
- "src/api/**"
12-
- "src/server/**"
13-
- "**/Cargo.toml"
14-
- "**/Cargo.lock"
15-
- ".github/workflows/featureTests.yml"
169

1710
jobs:
1811
test:

.github/workflows/latestRelease.yml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@ on:
44
workflow_dispatch:
55
push:
66
branches:
7-
- master
8-
paths:
9-
- "src/**"
10-
- "src/api/**"
11-
- "src/server/**"
12-
- "**/Cargo.toml"
13-
- "**/Cargo.lock"
7+
- "master"
148

159
jobs:
1610
Build_Docker_Image_on_Push:

.github/workflows/masterTests.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@ on:
55
push:
66
branches:
77
- "master"
8-
paths:
9-
- "src/**"
10-
- "src/api/**"
11-
- "src/server/**"
12-
- "**/Cargo.toml"
13-
- "**/Cargo.lock"
14-
- ".github/workflows/masterTests.yml"
158

169
jobs:
1710
test:

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ members = [".", "server", "api"]
99

1010
[dependencies]
1111
# cli parsing
12-
clap = { version = "4.0.7", features = ["derive", "env"] }
12+
clap = { version = "4.0.8", features = ["derive", "env"] }
1313
# ftp lib
1414
libunftp = "0.18.5"
1515
# own implementations

README.org

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
A small rust service faking a FTP-server by forwarding the requests to the FileFighter Backend (FileSystemService)
55

6-
[[https://drone.filefighter.de/api/badges/FileFighter/FTP-Service/status.svg]]
6+
[[https://github.com/FileFighter/FTP-Service/actions/workflows/masterTests.yml/badge.svg]]
7+
[[https://github.com/FileFighter/FTP-Service/actions/workflows/stableRelease.yml/badge.svg]]
8+
[[https://github.com/FileFighter/FTP-Service/actions/workflows/latestRelease.yml/badge.svg]]
79

810
* Run in Docker with local fss and fhs
911
#+begin_src shell

server/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ edition = "2021"
55
authors = ["open-schnick <[email protected]>", "qvalentin <[email protected]>"]
66

77
[dependencies]
8-
async-trait = "0.1.56"
8+
async-trait = "0.1.57"
99
libunftp = "0.18.5"
1010
tokio = "1.21.1"
1111
tracing = "0.1.36"

server/src/backend/storage_backend.rs

Lines changed: 8 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
1-
use super::{metadata::InodeMetaData, utils::validate_and_normalize_path};
1+
use super::{
2+
metadata::InodeMetaData,
3+
utils::{
4+
get_parent_and_name, path_contains_rclone_modification_date, transform_to_ftp_error,
5+
validate_and_normalize_path,
6+
},
7+
};
28
use crate::auth::user::FileFighterUser;
39
use async_trait::async_trait;
4-
use chrono::NaiveDateTime;
510
use filefighter_api::ffs_api::{
611
endpoints::{
712
create_directory, delete_inode, download_file, get_contents_of_folder, get_inode,
813
move_inode, rename_inode, set_last_modified_of_inode, upload_file,
914
},
1015
ApiConfig,
11-
ApiError::{self, ReqwestError, ResponseMalformed},
1216
};
1317
use libunftp::storage::{
1418
Error, ErrorKind, Fileinfo, Metadata, Result, StorageBackend, FEATURE_RESTART,
1519
};
1620
use std::{
1721
fmt::Debug,
18-
path::{Component, Path, PathBuf},
22+
path::{Path, PathBuf},
1923
};
2024
use tokio::io::AsyncRead;
2125
use tracing::{debug, error, instrument, warn};
@@ -258,110 +262,3 @@ impl StorageBackend<FileFighterUser> for FileFighter {
258262
}
259263
}
260264
}
261-
262-
fn get_parent_and_name(path: &Path) -> Result<(PathBuf, &str)> {
263-
match (path.parent(), path.file_name()) {
264-
(Some(parent), Some(name)) => Ok((
265-
parent.to_path_buf(),
266-
name.to_str()
267-
.ok_or_else(|| Error::new(ErrorKind::LocalError, "Filename was not valid utf-8"))?,
268-
)),
269-
(_, _) => Err(Error::new(
270-
ErrorKind::FileNameNotAllowedError,
271-
"Path for creating a directory must contain a parent and child component",
272-
)),
273-
}
274-
}
275-
276-
fn transform_to_ftp_error(error: ApiError) -> Error {
277-
match error {
278-
ReqwestError(err) => {
279-
warn!("Cought reqwest error {}", err);
280-
Error::new(ErrorKind::LocalError, "Internal Server Error")
281-
}
282-
ResponseMalformed(err) => {
283-
warn!("Filesystemservice error response: {}", err);
284-
Error::new(ErrorKind::PermanentDirectoryNotAvailable, err)
285-
}
286-
}
287-
}
288-
289-
// IDEA: check if rclone does try to update the root folder
290-
fn path_contains_rclone_modification_date(path: &Path) -> Option<(NaiveDateTime, PathBuf)> {
291-
let mut components: Vec<Component> = path.components().collect();
292-
293-
// needs to be at least / and date<whitespace>
294-
if components.len() < 2 {
295-
return None;
296-
}
297-
298-
// does exist
299-
let mut timestamp_component = components[1].as_os_str().to_str()?.to_owned();
300-
301-
#[allow(clippy::unwrap_used)]
302-
// if root path does not end with whitespace
303-
if timestamp_component.is_empty() || timestamp_component.pop().unwrap() != ' ' {
304-
return None;
305-
}
306-
307-
// the rest of the root folder needs to be in this format
308-
// yyyymmddhhmmss
309-
let parsed_time = NaiveDateTime::parse_from_str(&timestamp_component, "%Y%m%d%H%M%S").ok()?;
310-
311-
// remove the timestamp component
312-
components.remove(1);
313-
314-
Some((parsed_time, components.iter().collect()))
315-
}
316-
317-
#[cfg(test)]
318-
mod tests {
319-
use super::path_contains_rclone_modification_date;
320-
use chrono::NaiveDateTime;
321-
use std::{path::PathBuf, str::FromStr};
322-
323-
#[test]
324-
fn timestamp_parsing_works() {
325-
let result = NaiveDateTime::parse_from_str("20221003093709", "%Y%m%d%H%M%S").unwrap();
326-
let resulting_string = result.to_string();
327-
assert_eq!("2022-10-03 09:37:09", resulting_string)
328-
}
329-
330-
#[test]
331-
fn path_contains_rclone_modification_date_works() {
332-
let path = PathBuf::from_str("/20221003093709 /Home/School").unwrap();
333-
let option = path_contains_rclone_modification_date(&path);
334-
335-
match option {
336-
Some(result) => {
337-
assert_eq!(
338-
NaiveDateTime::parse_from_str("20221003093709", "%Y%m%d%H%M%S").unwrap(),
339-
result.0
340-
);
341-
assert_eq!(PathBuf::from_str("/Home/School").unwrap(), result.1);
342-
}
343-
None => panic!("Expected some value here."),
344-
}
345-
}
346-
347-
#[test]
348-
fn path_contains_rclone_modification_date_fails_without_whitespace() {
349-
let path = PathBuf::from_str("/20221003093709/Home/School").unwrap();
350-
let option = path_contains_rclone_modification_date(&path);
351-
assert!(option.is_none())
352-
}
353-
354-
#[test]
355-
fn path_contains_rclone_modification_date_fails_with_wrong_timestamp_format() {
356-
let path = PathBuf::from_str("/202210030937 /Home/School").unwrap();
357-
let option = path_contains_rclone_modification_date(&path);
358-
assert!(option.is_none())
359-
}
360-
361-
#[test]
362-
fn path_contains_rclone_modification_date_fails_with_wrong_timestamp() {
363-
let path = PathBuf::from_str("/20221003093790 /Home/School").unwrap();
364-
let option = path_contains_rclone_modification_date(&path);
365-
assert!(option.is_none())
366-
}
367-
}

server/src/backend/utils.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,68 @@
1-
use libunftp::storage::{Error, ErrorKind::FileNameNotAllowedError, Result};
1+
use chrono::NaiveDateTime;
2+
use filefighter_api::ffs_api::ApiError::{self, ReqwestError, ResponseMalformed};
3+
use libunftp::storage::{
4+
Error,
5+
ErrorKind::{self, FileNameNotAllowedError},
6+
Result,
7+
};
28
use std::path::{Component, Path, PathBuf};
3-
use tracing::debug;
9+
use tracing::{debug, warn};
10+
11+
pub fn get_parent_and_name(path: &Path) -> Result<(PathBuf, &str)> {
12+
match (path.parent(), path.file_name()) {
13+
(Some(parent), Some(name)) => Ok((
14+
parent.to_path_buf(),
15+
name.to_str()
16+
.ok_or_else(|| Error::new(ErrorKind::LocalError, "Filename was not valid utf-8"))?,
17+
)),
18+
(_, _) => Err(Error::new(
19+
ErrorKind::FileNameNotAllowedError,
20+
"Path for creating a directory must contain a parent and child component",
21+
)),
22+
}
23+
}
24+
25+
pub fn transform_to_ftp_error(error: ApiError) -> Error {
26+
match error {
27+
ReqwestError(err) => {
28+
warn!("Cought reqwest error {}", err);
29+
Error::new(ErrorKind::LocalError, "Internal Server Error")
30+
}
31+
ResponseMalformed(err) => {
32+
warn!("Filesystemservice error response: {}", err);
33+
Error::new(ErrorKind::PermanentDirectoryNotAvailable, err)
34+
}
35+
}
36+
}
37+
38+
// IDEA: check if rclone does try to update the root folder
39+
pub fn path_contains_rclone_modification_date(path: &Path) -> Option<(NaiveDateTime, PathBuf)> {
40+
let mut components: Vec<Component> = path.components().collect();
41+
42+
// needs to be at least / and date<whitespace>
43+
if components.len() < 2 {
44+
return None;
45+
}
46+
47+
// does exist
48+
#[allow(clippy::unwrap_used)]
49+
let mut timestamp_component = components.get(1).unwrap().as_os_str().to_str()?.to_owned();
50+
51+
#[allow(clippy::unwrap_used)]
52+
// if root path does not end with whitespace
53+
if timestamp_component.is_empty() || timestamp_component.pop().unwrap() != ' ' {
54+
return None;
55+
}
56+
57+
// the rest of the root folder needs to be in this format
58+
// yyyymmddhhmmss
59+
let parsed_time = NaiveDateTime::parse_from_str(&timestamp_component, "%Y%m%d%H%M%S").ok()?;
60+
61+
// remove the timestamp component
62+
components.remove(1);
63+
64+
Some((parsed_time, components.iter().collect()))
65+
}
466

567
/// Normalizing (without disk access) and validating Path
668
///

0 commit comments

Comments
 (0)