Files
npon-server/src/files.rs

206 lines
5.5 KiB
Rust

extern crate notify;
use notify::{
RecursiveMode,
Watcher,
Result,
Event,
};
use std::
{
fs,
path::Path,
path::PathBuf,
sync::mpsc,
};
use crate::
{
ROOT_DIR,
};
#[derive(Copy,Clone)]
enum Mode {
Default,
String,
Name,
Import,
}
pub fn watch_files(file_list: &[PathBuf]) -> u8
{
let (tx, rx) = mpsc::channel::<Result<Event>>(); // Use recommended_watcher() to automatically select the best implementation
// for your platform. The `EventHandler` passed to this constructor can be a
// closure, a `std::sync::mpsc::Sender`, a `crossbeam_channel::Sender`, or
// another type the trait is implemented for.
let mut watcher = notify::recommended_watcher(tx).expect("Watcher start failed"); // Add a path to be watched. All files and directories at that path and
// below will be monitored for changes.
watcher.watch(Path::new("root"), RecursiveMode::Recursive).expect("Path watching failed"); // Block forever, printing out events as they come in
for res in rx
{
match res
{
Ok(event) =>
{
// Ignore access event kinds as they're irrelevant
if ! notify::EventKind::is_access(&event.kind)
&& file_list.contains(&event.paths[0])
{
return 0
}
},
Err(error) =>
{
println!("watch error: {error:?}");
return 1
}
}
}
println!("Watching files...");
2
}
pub fn read_file(file_name: &str, depth: u8) ->
(
Vec<u8>,
Vec<PathBuf>,
)
{
if let Ok(file_contents) = fs::read_to_string(format!("root/{file_name}"))
{
let (bytes, file_list) = encode_npon(file_contents.as_str(), depth);
return (bytes, file_list)
}
(vec![], vec![]) // return
}
/// Push a newline or tab character when there's a \n or \t
/// Otherwise, just push the raw sequence
fn backslash(bytes: &mut Vec<u8>, character: u8)
{
match character
{
110 => // newline
{
bytes.push(14);
},
116 => // tab
{
bytes.push(15);
},
_ => bytes.push(character), // Otherwise just push the character
}
}
fn default_flag(bytes: &mut Vec<u8>, temp_string: &mut Vec<u8>, flag: &mut Mode, index_flag: &mut usize, character: u8, index: usize)
{
match character
{
40 =>
{
temp_string.push(3); // ( for name start
*flag = Mode::Name;
}
123 => bytes.push(5),
125 => bytes.push(6),
58 =>
{
*index_flag = index + 1;
*flag = Mode::Import;
},
39 | 34 =>
{
temp_string.push(7);
*flag = Mode::String;
},
_ => (),
}
}
fn encode_npon(file_contents: &str, depth: u8) ->
(
Vec<u8>,
Vec<PathBuf>,
)
{
let mut bytes: Vec<u8> = vec![];
let mut file_list: Vec<PathBuf> = vec![];
if depth > 63 {
println!("Depth level safety reached (63), recursion error suspected");
return (vec![], file_list);
}
if depth == 0 {
bytes.push(1);
}
let mut index_flag: usize = 0;
let mut flag: Mode = Mode::Default;
let mut backslash_flag: bool = false;
let mut temp_string: Vec<u8> = vec![];
for (index, character) in file_contents.bytes().enumerate()
{
if backslash_flag
{
// Push a newline or tab character when there's a \n or \t
// Otherwise, just push the raw sequence
backslash(&mut bytes, character);
backslash_flag = false;
}
match flag
{
Mode::Default => default_flag(&mut bytes, &mut temp_string, &mut flag, &mut index_flag, character, index),
Mode::String => // in a string
{
match character
{
39 | 34 =>
{
temp_string.push(8);
bytes.append(&mut temp_string);
flag = Mode::Default;
},
92 => backslash_flag = true,
_ => temp_string.push(character),
}
},
Mode::Name => // in a name
{
match character
{
41 =>
{
temp_string.push(4);
bytes.append(&mut temp_string); // ) for name end
temp_string = vec![];
flag = Mode::Default;
},
92 => backslash_flag = true,
_ => temp_string.push(character),
}
},
Mode::Import => // in import
{
if character == 58
{
file_list.push(ROOT_DIR.join(&file_contents[index_flag..index]));
let (new_bytes, mut new_file_list) = read_file
(
&file_contents[index_flag..index],
depth+1
);
file_list.append(&mut new_file_list);
for byte in &new_bytes
{
bytes.push(*byte);
}
flag = Mode::Default;
}
},
}
}
if depth == 0 {
bytes.push(2);
}
(bytes, file_list) // return
}