use capsec::SendCap;
use capsec::prelude::*;
#[derive(Clone)]
struct ServerCaps {
fs_read: SendCap<FsRead>,
fs_write: SendCap<FsWrite>,
net: SendCap<NetConnect>,
env: SendCap<EnvRead>,
}
fn handle_sync_request(caps: &ServerCaps) -> Result<String, CapSecError> {
let config_svc = ConfigService::new("/tmp/capsec-demo/config", caps.fs_read.as_cap());
let storage = FileStorage::new(caps.fs_read.as_cap(), caps.fs_write.as_cap());
let api = ApiClient::new("api.example.com", caps.net.as_cap());
sync_workflow(&config_svc, &storage, &api)
}
fn handle_status_request(caps: &ServerCaps) -> String {
let config_svc = ConfigService::new("/tmp/capsec-demo/config", caps.fs_read.as_cap());
let env_cap = caps.env.as_cap();
status_check(&config_svc, &env_cap)
}
fn sync_workflow(
config: &ConfigService,
storage: &FileStorage,
api: &ApiClient,
) -> Result<String, CapSecError> {
let settings = config.get("sync").unwrap_or_else(|| "interval=60".into());
let remote_data = api.get("/data/latest");
storage.save("/tmp/capsec-demo/synced.json", &remote_data)?;
Ok(format!(
"Synced {} bytes with settings: {settings}",
remote_data.len()
))
}
fn status_check(config: &ConfigService, env_cap: &impl CapProvider<EnvRead>) -> String {
let version = capsec::env::var("APP_VERSION", env_cap).unwrap_or_else(|_| "dev".into());
let config_ok = config.get("app").is_some();
let db_ok = config.get("database").is_some();
format!(
"Status: version={version} config={} database={}",
if config_ok { "ok" } else { "missing" },
if db_ok { "ok" } else { "missing" },
)
}
struct ConfigService {
cap: Cap<FsRead>,
base_dir: String,
}
impl ConfigService {
fn new(base_dir: impl Into<String>, cap: Cap<FsRead>) -> Self {
Self {
cap,
base_dir: base_dir.into(),
}
}
fn get(&self, key: &str) -> Option<String> {
let path = format!("{}/{}.toml", self.base_dir, key);
capsec::fs::read_to_string(&path, &self.cap).ok()
}
}
#[allow(dead_code)] struct FileStorage {
read_cap: Cap<FsRead>,
write_cap: Cap<FsWrite>,
}
#[allow(dead_code)]
impl FileStorage {
fn new(read_cap: Cap<FsRead>, write_cap: Cap<FsWrite>) -> Self {
Self {
read_cap,
write_cap,
}
}
fn load(&self, name: &str) -> Result<Vec<u8>, CapSecError> {
capsec::fs::read(name, &self.read_cap)
}
fn save(&self, name: &str, data: &str) -> Result<(), CapSecError> {
capsec::fs::write(name, data.as_bytes(), &self.write_cap)
}
}
#[allow(dead_code)] struct ApiClient {
cap: Cap<NetConnect>,
base_url: String,
}
impl ApiClient {
fn new(base_url: impl Into<String>, cap: Cap<NetConnect>) -> Self {
Self {
cap,
base_url: base_url.into(),
}
}
fn get(&self, path: &str) -> String {
format!(
"{{\"source\":\"{}{}\",\"data\":\"...\"}}",
self.base_url, path
)
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let root = capsec::root();
let caps = ServerCaps {
fs_read: root.grant::<FsRead>().make_send(),
fs_write: root.grant::<FsWrite>().make_send(),
net: root.grant::<NetConnect>().make_send(),
env: root.grant::<EnvRead>().make_send(),
};
println!("── Sync Request ──");
match handle_sync_request(&caps) {
Ok(result) => println!("{result}"),
Err(e) => println!("Sync failed (expected in demo): {e}"),
}
println!();
println!("── Status Request ──");
let status = handle_status_request(&caps);
println!("{status}");
println!();
println!("The three layers:");
println!(" 1. main() created ServerCaps with SendCap fields (thread-safe)");
println!(" 2. Handlers extracted caps and built domain wrappers");
println!(" 3. Core logic used domain wrappers only — zero capsec imports");
Ok(())
}