use std::sync::atomic::{AtomicU64, Ordering};
use skyzen::durable::DurableObject;
use skyzen::extract::Path;
use skyzen::routing::{CreateRouteNode, Route, Router};
#[cfg(target_arch = "wasm32")]
use skyzen::runtime::CfProperties;
use skyzen::runtime::WorkerContext;
use skyzen::Result as SkyResult;
async fn health() -> &'static str {
"OK"
}
async fn root() -> &'static str {
"Hello from Skyzen running at the edge!"
}
async fn greet(Path(name): Path<String>) -> String {
format!("Hello, {name}!")
}
async fn accept_work(context: WorkerContext) -> SkyResult<&'static str> {
context.wait_until(async {
tracing::info!("post-response work finished after the response was returned");
})?;
Ok("accepted")
}
#[cfg(target_arch = "wasm32")]
async fn where_am_i(cf: CfProperties) -> String {
format!(
"colo={} country={} tls={}",
cf.colo.as_deref().unwrap_or("unknown"),
cf.country.as_deref().unwrap_or("unknown"),
cf.tls_version.as_deref().unwrap_or("unknown"),
)
}
#[cfg(not(target_arch = "wasm32"))]
async fn where_am_i() -> &'static str {
"request.cf is a Cloudflare value and this build is not running on Workers"
}
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
#[skyzen::durable_object]
pub struct Visits {
hits: AtomicU64,
}
impl DurableObject for Visits {
const PERSIST: bool = false;
fn fetch(&self) -> Router {
let hits = self.hits.fetch_add(1, Ordering::Relaxed) + 1;
Route::new(("/hits".at(move || async move { hits.to_string() }),)).build()
}
}
fn durable(error: skyzen::durable::DurableObjectError) -> skyzen::Error {
skyzen::Error::new(error)
}
#[cfg(target_arch = "wasm32")]
async fn visit(
Path(name): Path<String>,
env: skyzen::runtime::wasm::WasmEnv,
) -> SkyResult<skyzen::Response> {
let visits =
skyzen_cloudflare::CfDurableNamespace::from_env(env.as_js(), "VISITS").map_err(durable)?;
visits
.get_by_name(&name)
.map_err(durable)?
.fetch_url("https://visits/hits")
.await
.map_err(durable)
}
#[cfg(not(target_arch = "wasm32"))]
async fn visit(
Path(name): Path<String>,
skyzen::utils::State(visits): skyzen::utils::State<
skyzen::durable::NativeDurableNamespace<Visits>,
>,
) -> SkyResult<skyzen::Response> {
visits
.get_by_name(&name)
.map_err(durable)?
.fetch_url("https://visits/hits")
.await
.map_err(durable)
}
fn build_router() -> Router {
let routes = Route::new((
"/".at(root),
"/health".at(health),
"/hello".route(("/{name}".at(greet),)),
"/readyz".at(|| async { "ready" }),
"/track".at(accept_work),
"/where-am-i".at(where_am_i),
"/visits".route(("/{name}".at(visit),)),
));
#[cfg(not(target_arch = "wasm32"))]
let routes = routes.with(skyzen::utils::State(
skyzen::durable::NativeDurableNamespace::<Visits>::new(),
));
routes.build()
}
#[skyzen::main]
fn worker() -> Router {
build_router()
}
#[cfg(target_arch = "wasm32")]
fn main() {}