mirror of
https://github.com/Astatin3/markdown.git
synced 2026-06-09 00:28:05 -06:00
Make the thing
This commit is contained in:
+18
@@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "markdown"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
notify = "6.1.1"
|
||||||
|
blocking = "1.6.1"
|
||||||
|
failure = "0.1.8"
|
||||||
|
hotwatch = "0.5.0"
|
||||||
|
time = "0.3.36"
|
||||||
|
rocket = { version = "0.5.1", features = ["json"] }
|
||||||
|
serde = { version = "1.0.204", features = ["derive"] }
|
||||||
|
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "markdown"
|
||||||
|
path = "src/main.rs"
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>File Content</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.6.1/github-markdown-dark.min.css" integrity="sha512-mzPe5Bxap921sKCNI3lXEi5FxCue4M1Ei65ZVFi1UdCMnr4+BFOpBuWnfpJ8WLBxvyhf7z45Jsa5jWiseE57rg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0">
|
||||||
|
|
||||||
|
<pre id="content" class="markdown-body"></pre>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import markdownit from 'https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/+esm'
|
||||||
|
import mdk from 'https://cdn.jsdelivr.net/npm/markdown-it-katex@2.0.3/+esm'
|
||||||
|
|
||||||
|
const md = markdownit({
|
||||||
|
html: true,
|
||||||
|
linkify: true,
|
||||||
|
typographer: true
|
||||||
|
})
|
||||||
|
md.use(mdk)
|
||||||
|
|
||||||
|
const content = document.getElementById('content');
|
||||||
|
|
||||||
|
fetch('/content')
|
||||||
|
.then(response => response.text())
|
||||||
|
.then(data => content.innerHTML = md.render(data));
|
||||||
|
|
||||||
|
const evtSource = new EventSource("/events");
|
||||||
|
evtSource.onmessage = function(event) {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log(data);
|
||||||
|
content.innerHTML = md.render(data.content);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
use core::time::Duration;
|
||||||
|
use std::{env, process};
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use hotwatch::{Hotwatch};
|
||||||
|
use rocket::{State, Shutdown};
|
||||||
|
use rocket::fs::NamedFile;
|
||||||
|
use rocket::response::stream::{Event as SSEvent, EventStream};
|
||||||
|
use rocket::serde::Serialize;
|
||||||
|
use rocket::tokio::sync::broadcast::{channel, Sender};
|
||||||
|
use rocket::tokio::select;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use time::Error;
|
||||||
|
|
||||||
|
#[macro_use] extern crate rocket;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
struct FileChange {
|
||||||
|
content: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
async fn index() -> NamedFile {
|
||||||
|
NamedFile::open("index.html").await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/content")]
|
||||||
|
async fn content(file_content: &State<Arc<Mutex<String>>>) -> String {
|
||||||
|
file_content.lock().unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/events")]
|
||||||
|
async fn events(queue: &State<Sender<FileChange>>, mut end: Shutdown) -> EventStream![] {
|
||||||
|
let mut rx = queue.subscribe();
|
||||||
|
EventStream! {
|
||||||
|
loop {
|
||||||
|
let msg = select! {
|
||||||
|
msg = rx.recv() => match msg {
|
||||||
|
Ok(msg) => msg,
|
||||||
|
Err(_) => break,
|
||||||
|
},
|
||||||
|
_ = &mut end => break,
|
||||||
|
};
|
||||||
|
yield SSEvent::json(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[launch]
|
||||||
|
fn rocket() -> _ {
|
||||||
|
let file_path = Path::new("/tmp/file.md");
|
||||||
|
|
||||||
|
let file_content = Arc::new(Mutex::new(std::fs::read_to_string(file_path).unwrap()));
|
||||||
|
let file_content_clone = Arc::clone(&file_content);
|
||||||
|
|
||||||
|
let (tx, _) = channel::<FileChange>(1024);
|
||||||
|
let tx_clone = tx.clone();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let mut watch = Hotwatch::new().unwrap();
|
||||||
|
watch.watch(file_path, move |_| {
|
||||||
|
|
||||||
|
let content = std::fs::read_to_string(file_path).unwrap();
|
||||||
|
|
||||||
|
*file_content_clone.lock().unwrap() = content.clone();
|
||||||
|
let _ = tx_clone.send(FileChange { content });
|
||||||
|
|
||||||
|
std::thread::sleep(Duration::from_secs(1));
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
loop { // IDK how to sleep forever
|
||||||
|
std::thread::sleep(Duration::from_secs(9223372036854775807));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rocket::build()
|
||||||
|
.manage(tx)
|
||||||
|
.manage(file_content)
|
||||||
|
.mount("/", routes![index, content, events])
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user