aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2021-01-16 21:38:22 -0500
committerChristine Dodrill <me@christine.website>2021-01-16 21:38:22 -0500
commit4bcc848bb178d9e4372ba13b750d620cabc2a9ac (patch)
treee2a97a5a03c934de6307b3d543d5f4b249675ce7
parent17af42bc698237d1560b8add144641ae3950b469 (diff)
downloadxesite-4bcc848bb178d9e4372ba13b750d620cabc2a9ac.tar.xz
xesite-4bcc848bb178d9e4372ba13b750d620cabc2a9ac.zip
move poking services into app boot after systemd notify
Signed-off-by: Christine Dodrill <me@christine.website>
-rw-r--r--Cargo.lock67
-rw-r--r--Cargo.toml2
-rw-r--r--lib/cfcache/Cargo.toml20
-rw-r--r--lib/cfcache/examples/purge.rs15
-rw-r--r--lib/cfcache/src/lib.rs64
-rw-r--r--lib/mi/src/lib.rs12
-rw-r--r--src/app/mod.rs1
-rw-r--r--src/app/poke.rs86
-rw-r--r--src/main.rs37
9 files changed, 286 insertions, 18 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 653e2d8..0c95748 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -213,6 +213,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]]
+name = "cfcache"
+version = "0.1.0"
+dependencies = [
+ "eyre",
+ "kankyo",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "tracing-futures",
+]
+
+[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1068,13 +1083,36 @@ dependencies = [
"kernel32-sys",
"libc",
"log",
- "miow",
+ "miow 0.2.2",
"net2",
"slab",
"winapi 0.2.8",
]
[[package]]
+name = "mio-named-pipes"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
+dependencies = [
+ "log",
+ "mio",
+ "miow 0.3.6",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "mio-uds"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
+dependencies = [
+ "iovec",
+ "libc",
+ "mio",
+]
+
+[[package]]
name = "miow"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1087,6 +1125,16 @@ dependencies = [
]
[[package]]
+name = "miow"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
+dependencies = [
+ "socket2",
+ "winapi 0.3.9",
+]
+
+[[package]]
name = "multipart"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1914,6 +1962,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074"
[[package]]
+name = "signal-hook-registry"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "sitemap"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2069,12 +2126,17 @@ dependencies = [
"futures-core",
"iovec",
"lazy_static",
+ "libc",
"memchr",
"mio",
+ "mio-named-pipes",
+ "mio-uds",
"num_cpus",
"pin-project-lite 0.1.11",
+ "signal-hook-registry",
"slab",
"tokio-macros",
+ "winapi 0.3.9",
]
[[package]]
@@ -2603,6 +2665,7 @@ checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
name = "xesite"
version = "2.2.0"
dependencies = [
+ "cfcache",
"chrono",
"color-eyre",
"comrak",
@@ -2621,7 +2684,7 @@ dependencies = [
"pfacts",
"pretty_env_logger",
"prometheus",
- "rand 0.7.3",
+ "rand 0.8.1",
"reqwest",
"ructe",
"sdnotify",
diff --git a/Cargo.toml b/Cargo.toml
index f398181..03afd0c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,6 +21,7 @@ log = "0.4"
mime = "0.3.0"
prometheus = { version = "0.10", default-features = false, features = ["process"] }
rand = "0"
+reqwest = { version = "0.10", features = ["json"] }
sdnotify = { version = "0.1", default-features = false }
serde_dhall = "0.8.0"
serde = { version = "1", features = ["derive"] }
@@ -37,6 +38,7 @@ url = "2"
uuid = { version = "0.8", features = ["serde", "v4"] }
# workspace dependencies
+cfcache = { path = "./lib/cfcache" }
go_vanity = { path = "./lib/go_vanity" }
jsonfeed = { path = "./lib/jsonfeed" }
mi = { path = "./lib/mi" }
diff --git a/lib/cfcache/Cargo.toml b/lib/cfcache/Cargo.toml
new file mode 100644
index 0000000..85060c2
--- /dev/null
+++ b/lib/cfcache/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "cfcache"
+version = "0.1.0"
+authors = ["Christine Dodrill <me@christine.website>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+reqwest = { version = "0.10", features = ["json"] }
+serde_json = "1.0"
+serde = { version = "1", features = ["derive"] }
+thiserror = "1"
+tracing = "0.1"
+tracing-futures = "0.2"
+
+[dev-dependencies]
+eyre = "0.6.5"
+kankyo = "0.3"
+tokio = { version = "0.2", features = ["full"] }
diff --git a/lib/cfcache/examples/purge.rs b/lib/cfcache/examples/purge.rs
new file mode 100644
index 0000000..22c81a4
--- /dev/null
+++ b/lib/cfcache/examples/purge.rs
@@ -0,0 +1,15 @@
+use eyre::Result;
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ kankyo::init()?;
+
+ let key = std::env::var("CF_TOKEN")?;
+ let zone_id = std::env::var("CF_ZONE_ID")?;
+
+ let cli = cfcache::Client::new(key, zone_id)?;
+ cli.purge(vec!["https://christine.website/.within/health".to_string()])
+ .await?;
+
+ Ok(())
+}
diff --git a/lib/cfcache/src/lib.rs b/lib/cfcache/src/lib.rs
new file mode 100644
index 0000000..baf6775
--- /dev/null
+++ b/lib/cfcache/src/lib.rs
@@ -0,0 +1,64 @@
+use reqwest::header;
+use tracing::instrument;
+
+pub type Result<T = ()> = std::result::Result<T, Error>;
+
+#[derive(thiserror::Error, Debug)]
+pub enum Error {
+ #[error("json error: {0}")]
+ Json(#[from] serde_json::Error),
+
+ #[error("request error: {0}")]
+ Request(#[from] reqwest::Error),
+
+ #[error("invalid header value: {0}")]
+ InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
+}
+
+pub struct Client {
+ zone_id: String,
+ cli: reqwest::Client,
+}
+
+static USER_AGENT: &str = concat!(
+ "xesite ",
+ env!("CARGO_PKG_NAME"),
+ "/",
+ env!("CARGO_PKG_VERSION")
+);
+
+impl Client {
+ pub fn new(api_key: String, zone_id: String) -> Result<Self> {
+ let mut headers = header::HeaderMap::new();
+ headers.insert(
+ header::AUTHORIZATION,
+ header::HeaderValue::from_str(&format!("Bearer {}", api_key))?,
+ );
+
+ let cli = reqwest::Client::builder()
+ .user_agent(USER_AGENT)
+ .default_headers(headers)
+ .build()?;
+
+ Ok(Self { zone_id, cli })
+ }
+
+ #[instrument(skip(self), err)]
+ pub async fn purge(&self, urls: Vec<String>) -> Result {
+ #[derive(serde::Serialize)]
+ struct Files {
+ files: Vec<String>,
+ }
+
+ self.cli
+ .post(&format!(
+ "https://api.cloudflare.com/client/v4/zones/{}/purge_cache",
+ self.zone_id
+ ))
+ .json(&Files { files: urls })
+ .send()
+ .await?
+ .error_for_status()?;
+ Ok(())
+ }
+}
diff --git a/lib/mi/src/lib.rs b/lib/mi/src/lib.rs
index ec9d459..0e19bec 100644
--- a/lib/mi/src/lib.rs
+++ b/lib/mi/src/lib.rs
@@ -34,7 +34,7 @@ impl Client {
})
}
- #[instrument(skip(self))]
+ #[instrument(skip(self), err)]
pub async fn mentioners(&self, url: String) -> Result<Vec<WebMention>> {
Ok(self
.cli
@@ -46,6 +46,16 @@ impl Client {
.json()
.await?)
}
+
+ #[instrument(skip(self), err)]
+ pub async fn refresh(&self) -> Result<()> {
+ self.cli
+ .post("https://mi.within.website/api/blog/refresh")
+ .send()
+ .await?
+ .error_for_status()?;
+ Ok(())
+ }
}
#[derive(Debug, Deserialize, Eq, PartialEq, Clone)]
diff --git a/src/app/mod.rs b/src/app/mod.rs
index e763792..6c01b2f 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -5,6 +5,7 @@ use std::{fs, path::PathBuf};
use tracing::{error, instrument};
pub mod markdown;
+pub mod poke;
#[derive(Clone, Deserialize)]
pub struct Config {
diff --git a/src/app/poke.rs b/src/app/poke.rs
new file mode 100644
index 0000000..dd6f9fe
--- /dev/null
+++ b/src/app/poke.rs
@@ -0,0 +1,86 @@
+use color_eyre::eyre::Result;
+use std::{env, time::Duration};
+use tokio::time::delay_for;
+
+#[instrument(err)]
+pub async fn the_cloud() -> Result<()> {
+ info!("waiting for things to settle");
+ delay_for(Duration::from_secs(10)).await;
+
+ info!("purging cloudflare cache");
+ cloudflare().await?;
+
+ info!("waiting for the cloudflare cache to purge globally");
+ delay_for(Duration::from_secs(45)).await;
+
+ info!("poking mi");
+ mi().await?;
+
+ info!("poking bing");
+ bing().await?;
+
+ info!("poking google");
+ google().await?;
+
+ Ok(())
+}
+
+#[instrument(err)]
+async fn bing() -> Result<()> {
+ let cli = reqwest::Client::new();
+ cli.get("https://www.bing.com/ping")
+ .query(&[("sitemap", "https://christine.website/sitemap.xml")])
+ .header("User-Agent", crate::APPLICATION_NAME)
+ .send()
+ .await?
+ .error_for_status()?;
+
+ Ok(())
+}
+
+#[instrument(err)]
+async fn google() -> Result<()> {
+ let cli = reqwest::Client::new();
+ cli.get("https://www.google.com/ping")
+ .query(&[("sitemap", "https://christine.website/sitemap.xml")])
+ .header("User-Agent", crate::APPLICATION_NAME)
+ .send()
+ .await?
+ .error_for_status()?;
+
+ Ok(())
+}
+
+#[instrument(err)]
+async fn cloudflare() -> Result<()> {
+ let cli = cfcache::Client::new(env::var("CF_TOKEN")?, env::var("CF_ZONE_ID")?)?;
+ cli.purge(
+ vec![
+ "https://christine.website/sitemap.xml",
+ "https://christine.website",
+ "https://christine.website/blog",
+ "https://christine.website/blog.atom",
+ "https://christine.website/blog.json",
+ "https://christine.website/blog.rss",
+ "https://christine.website/gallery",
+ "https://christine.website/talks",
+ "https://christine.website/resume",
+ "https://christine.website/signalboost",
+ "https://christine.website/feeds",
+ ]
+ .into_iter()
+ .map(|i| i.to_string())
+ .collect(),
+ )
+ .await?;
+
+ Ok(())
+}
+
+#[instrument(err)]
+async fn mi() -> Result<()> {
+ let cli = mi::Client::new(env::var("MI_TOKEN")?, crate::APPLICATION_NAME.to_string())?;
+ cli.refresh().await?;
+
+ Ok(())
+}
diff --git a/src/main.rs b/src/main.rs
index 285bb93..91cd12b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -39,21 +39,6 @@ async fn main() -> Result<()> {
.await?,
);
- match sdnotify::SdNotify::from_env() {
- Ok(ref mut n) => {
- n.notify_ready().map_err(|why| {
- error!("can't signal readiness to systemd: {}", why);
- why
- })?;
- n.set_status(format!("hosting {} posts", state.clone().everything.len()))
- .map_err(|why| {
- error!("can't signal status to systemd: {}", why);
- why
- })?;
- }
- Err(why) => error!("not running under systemd with Type=notify: {}", why),
- }
-
let healthcheck = warp::get().and(warp::path(".within").and(warp::path("health")).map(|| "OK"));
let base = warp::path!("blog" / ..);
@@ -222,6 +207,28 @@ async fn main() -> Result<()> {
.with(warp::log(APPLICATION_NAME))
.recover(handlers::rejection);
+ match sdnotify::SdNotify::from_env() {
+ Ok(ref mut n) => {
+ // shitty heuristic for detecting if we're running in prod
+ tokio::spawn(async {
+ if let Err(why) = app::poke::the_cloud().await {
+ error!("Unable to poke the cloud: {}", why);
+ }
+ });
+
+ n.notify_ready().map_err(|why| {
+ error!("can't signal readiness to systemd: {}", why);
+ why
+ })?;
+ n.set_status(format!("hosting {} posts", state.clone().everything.len()))
+ .map_err(|why| {
+ error!("can't signal status to systemd: {}", why);
+ why
+ })?;
+ }
+ Err(why) => error!("not running under systemd with Type=notify: {}", why),
+ }
+
warp::serve(site)
.run((
[0, 0, 0, 0],