Compare commits

...

4 Commits

Author SHA1 Message Date
mossfet ec9d5cd874 Merge pull request 'hot reloading support' (#6) from hot-reloading into main
Reviewed-on: #6
2023-07-04 14:26:42 +00:00
Fries 33f0b6a5e9 don't panic on parsing error with running watcher
this means the watcher doesn't stop working if someone makes an edit to
names.json that results in a parser error. it will just print out the
error and keep the old configuration. if you restart the program and the
file still has an error, the program won't start.
2023-07-03 22:41:32 -07:00
Fries 93bd3540e8 use async mutex
looks like the best way to do the state thing after all is global so i
should use async mutexes so stuff doesn't block.
2023-07-03 22:14:10 -07:00
Fries a672135793 add cursed hot reloading support
im sorry if you have to look at the sites.rs file.
2023-07-03 16:23:14 -07:00
11 changed files with 217 additions and 28 deletions

110
Cargo.lock generated
View File

@ -425,12 +425,33 @@ dependencies = [
"version_check",
]
[[package]]
name = "filetime"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.2.16",
"windows-sys 0.48.0",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
dependencies = [
"libc",
]
[[package]]
name = "futures"
version = "0.3.28"
@ -659,6 +680,26 @@ version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"
[[package]]
name = "inotify"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
dependencies = [
"bitflags 1.3.2",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
dependencies = [
"libc",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -697,6 +738,26 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "kqueue"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98"
dependencies = [
"kqueue-sys",
"libc",
]
[[package]]
name = "kqueue-sys"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587"
dependencies = [
"bitflags 1.3.2",
"libc",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -768,6 +829,7 @@ dependencies = [
"askama",
"askama_rocket",
"log",
"notify",
"rocket",
"rust-embed",
"serde",
@ -814,6 +876,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.48.0",
]
@ -848,6 +911,23 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "notify"
version = "6.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5738a2795d57ea20abec2d6d76c6081186709c0024187cd5977265eda6598b51"
dependencies = [
"bitflags 1.3.2",
"filetime",
"fsevent-sys",
"inotify",
"kqueue",
"libc",
"mio",
"walkdir",
"windows-sys 0.45.0",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@ -915,7 +995,7 @@ dependencies = [
"libc",
"redox_syscall 0.3.5",
"smallvec",
"windows-targets",
"windows-targets 0.48.1",
]
[[package]]
@ -1787,7 +1867,7 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets",
"windows-targets 0.48.1",
]
[[package]]
@ -1805,13 +1885,37 @@ dependencies = [
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
"windows-targets 0.48.1",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]

View File

@ -5,6 +5,7 @@ members = ["cli", "shared"]
name = "meowy-webring"
version = "0.1.0"
edition = "2021"
rust-version = "1.70"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -45,3 +46,8 @@ path = "./shared"
[dependencies.simple_logger]
version = "4"
default-features = false
[dependencies.notify]
version = "6"
default-features = false
features = ["macos_fsevent"]

View File

@ -19,7 +19,7 @@ pub(crate) fn print(
if let Some(filter) = filter {
names.retain(|f| &f.url == filter);
if names.len() == 0 {
if names.is_empty() {
return Err(Error {
status: ErrorStatus::NotFoundError,
data: "this url was not found in names.json".into(),
@ -50,8 +50,8 @@ fn filter_site(
json_printing(site)?;
return Ok(());
}
return Ok(printing(separator, site, group));
printing(separator, site, group);
Ok(())
}
fn json_printing(site: &Site) -> Result<(), Error> {

View File

@ -11,7 +11,7 @@ pub(crate) fn remove(path: &Path, url: &String, separator: &String) -> Result<()
if &site.url == url {
println!(
"removing {} from names.json",
site_string(&site, PrintOptions::All, separator)
site_string(site, PrintOptions::All, separator)
);
}
&site.url != url

View File

@ -24,5 +24,5 @@ pub(super) fn site_string(site: &Site, options: PrintOptions, separator: &String
}
}
return string;
string
}

View File

@ -26,6 +26,11 @@ pub fn get_names_path() -> Result<PathBuf, Error> {
return get_file_from_directory(directory.data_dir(), "names.json");
}
pub fn get_names_project_path() -> Result<PathBuf, Error> {
let directory = get_project_dir()?;
return Ok(directory.data_dir().to_path_buf());
}
fn create_directory(path: &Path) -> Result<(), Error> {
match std::fs::create_dir_all(path) {
Ok(_) => {

View File

@ -5,7 +5,8 @@ pub enum ErrorStatus {
DirectoriesError,
LoggerInitializationError,
NotFoundError,
AlreadyExistsError
AlreadyExistsError,
GenericError
}
pub struct Error {

View File

@ -1,4 +1,6 @@
use shared::{directories, names};
use crate::watcher::hot_reloading;
use rocket::tokio;
use sites::init_names;
#[macro_use]
extern crate rocket;
@ -6,16 +8,15 @@ extern crate rocket;
mod assets;
mod links;
mod routes;
mod sites;
mod watcher;
#[launch]
fn rocket() -> _ {
let names_path = directories::get_names_path().unwrap();
println!("names.json path: {}", names_path.display());
let names_file = names::read_names_file(&names_path).unwrap();
let names = names::load_names(names_file).unwrap();
async fn rocket() -> _ {
init_names().unwrap();
tokio::task::spawn_blocking(hot_reloading);
rocket::build()
.manage(names)
.mount(
"/",
routes![routes::index, routes::previous, routes::next, routes::name],

View File

@ -1,12 +1,14 @@
use crate::{links::{next_url, previous_url}, assets::ErrorTemplate};
use crate::{
assets::ErrorTemplate,
links::{next_url, previous_url},
sites::get_global_names,
};
use rocket::{
http::Status,
response::Redirect,
serde::{json::Json, Serialize},
State,
};
use shared::names::Site;
const NOT_FOUND_ERROR: ErrorTemplate = ErrorTemplate {
error: "Not Found",
@ -26,27 +28,25 @@ pub fn index() -> &'static str {
}
#[get("/previous?<source_url>")]
pub fn previous(source_url: String, names: &State<Vec<Site>>) -> Result<Redirect, Status> {
let names = names.inner();
match previous_url(&source_url, names) {
pub async fn previous(source_url: String) -> Result<Redirect, Status> {
match previous_url(&source_url, &get_global_names().await) {
Some(url) => Ok(Redirect::to(format!("https://{}", url))),
None => Err(Status::NotFound),
}
}
#[get("/next?<source_url>")]
pub fn next(source_url: String, names: &State<Vec<Site>>) -> Result<Redirect, Status> {
let names = names.inner();
match next_url(&source_url, names) {
pub async fn next(source_url: String) -> Result<Redirect, Status> {
match next_url(&source_url, &get_global_names().await) {
Some(url) => Ok(Redirect::to(format!("https://{}", url))),
None => Err(Status::NotFound),
}
}
#[get("/name?<source_url>")]
pub fn name(source_url: String, names: &State<Vec<Site>>) -> Result<Json<JsonResponse>, Status> {
let previous_site_name = previous_url(&source_url, names);
let next_site_name = next_url(&source_url, names);
pub async fn name(source_url: String) -> Result<Json<JsonResponse>, Status> {
let previous_site_name = previous_url(&source_url, &get_global_names().await);
let next_site_name = next_url(&source_url, &get_global_names().await);
if previous_site_name.is_none() && next_site_name.is_none() {
return Err(Status::NotFound);

40
src/sites.rs Normal file
View File

@ -0,0 +1,40 @@
use rocket::tokio::sync::Mutex;
use shared::{
directories,
errors::{Error, ErrorStatus},
names::{self, Site},
};
use std::sync::OnceLock;
pub async fn get_global_names() -> Vec<Site> {
NAMES.get().unwrap().lock().await.clone()
}
pub fn set_names() {
match get_names() {
Ok(names) => *NAMES.get().unwrap().blocking_lock() = names,
Err(err) => println!("{:?}", err),
}
}
static NAMES: OnceLock<Mutex<Vec<Site>>> = OnceLock::new();
pub fn init_names() -> Result<(), Error> {
println!(
"names.json path: {}",
directories::get_names_path().unwrap().display()
);
match NAMES.set(Mutex::new(get_names().unwrap())) {
Ok(_) => Ok(()),
Err(_) => Err(Error {
status: ErrorStatus::GenericError,
data: "an error has occured while trying to get the names.json file".into(),
}),
}
}
fn get_names() -> Result<Vec<Site>, Error> {
let names_path = directories::get_names_path()?;
let names_file = names::read_names_file(&names_path)?;
names::load_names(names_file)
}

32
src/watcher.rs Normal file
View File

@ -0,0 +1,32 @@
use notify::{
event::{DataChange, ModifyKind},
EventKind, Result, Watcher,
};
use shared::directories;
use crate::sites;
pub(crate) fn hot_reloading() {
let (tx, rx) = std::sync::mpsc::channel();
let names_path = directories::get_names_project_path().unwrap();
let mut watcher = notify::recommended_watcher(tx).unwrap();
watcher
.watch(&names_path, notify::RecursiveMode::NonRecursive)
.unwrap();
for res in rx {
watch(res);
}
}
fn watch(res: Result<notify::Event>) {
match res {
Ok(event) => {
if event.kind == EventKind::Modify(ModifyKind::Data(DataChange::Any)) {
sites::set_names();
}
}
Err(err) => println!("Error: {}", err),
}
}