···1[package]
2name = "allegedly"
3-description = "public ledger tools and services (for the PLC)"
4license = "MIT OR Apache-2.0"
5version = "0.1.0"
6edition = "2024"
···11async-compression = { version = "0.4.30", features = ["futures-io", "tokio", "gzip"] }
12chrono = { version = "0.4.42", features = ["serde"] }
13clap = { version = "4.5.47", features = ["derive", "env"] }
14-env_logger = "0.11.8"
15futures = "0.3.31"
16log = "0.4.28"
017reqwest = { version = "0.12.23", features = ["stream"] }
18reqwest-middleware = "0.4.2"
19reqwest-retry = "0.7.0"
···24tokio-postgres = { version = "0.7.13", features = ["with-chrono-0_4", "with-serde_json-1"] }
25tokio-stream = { version = "0.1.17", features = ["io-util"] }
26tokio-util = { version = "0.7.16", features = ["compat"] }
0
···1[package]
2name = "allegedly"
3+description = "public ledger server tools and services (for the PLC)"
4license = "MIT OR Apache-2.0"
5version = "0.1.0"
6edition = "2024"
···11async-compression = { version = "0.4.30", features = ["futures-io", "tokio", "gzip"] }
12chrono = { version = "0.4.42", features = ["serde"] }
13clap = { version = "4.5.47", features = ["derive", "env"] }
014futures = "0.3.31"
15log = "0.4.28"
16+poem = { version = "3.1.12", features = ["compression"] }
17reqwest = { version = "0.12.23", features = ["stream"] }
18reqwest-middleware = "0.4.2"
19reqwest-retry = "0.7.0"
···24tokio-postgres = { version = "0.7.13", features = ["with-chrono-0_4", "with-serde_json-1"] }
25tokio-stream = { version = "0.1.17", features = ["io-util"] }
26tokio-util = { version = "0.7.16", features = ["compat"] }
27+tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
+9-1
readme.md
···1# Allegedly
23-Some [public ledger](https://github.com/did-method-plc/did-method-plc) tools and services
45Allegedly can
67- Tail PLC ops to stdout: `allegedly tail | jq`
8- Export PLC ops to weekly gzipped bundles: `allegdly bundle --dest ./some-folder`
9- Dump bundled ops to stdout FAST: `allegedly backfill --source-workers 6 | pv -l > /ops-unordered.jsonl`
000000001011(add `--help` to any command for more info about it)
12
···1# Allegedly
23+Some [public ledger](https://github.com/did-method-plc/did-method-plc) server tools and services
45Allegedly can
67- Tail PLC ops to stdout: `allegedly tail | jq`
8- Export PLC ops to weekly gzipped bundles: `allegdly bundle --dest ./some-folder`
9- Dump bundled ops to stdout FAST: `allegedly backfill --source-workers 6 | pv -l > /ops-unordered.jsonl`
10+- Wrap the reference PLC server and run it as a mirror:
11+12+ ```bash
13+ allegedly mirror \
14+ --bind 0.0.0.0:8000 \
15+ --wrap http://127.0.0.1:3000 \
16+ --wrap-pg "postgresql://postgres:postgres@localhost:5432/postgres"
17+ ```
1819(add `--help` to any command for more info about it)
20
+50-5
src/bin/allegedly.rs
···1use allegedly::{
2 Db, Dt, ExportPage, FolderSource, HttpSource, PageBoundaryState, backfill, backfill_to_pg,
3- bin_init, pages_to_pg, pages_to_weeks, poll_upstream,
4};
5-use clap::{Parser, Subcommand};
6use reqwest::Url;
7-use std::{path::PathBuf, time::Instant};
8use tokio::sync::{mpsc, oneshot};
910#[derive(Debug, Parser)]
···71 #[arg(long, action)]
72 clobber: bool,
73 },
000000000000074 /// Poll an upstream PLC server and log new ops to stdout
75 Tail {
76 /// Begin tailing from a specific timestamp for replay or wait-until
···121122#[tokio::main]
123async fn main() {
124- bin_init("main");
125-126 let args = Cli::parse();
000127128 let t0 = Instant::now();
129 match args.command {
···205 log::trace!("ensuring output directory exists");
206 std::fs::create_dir_all(&dest).unwrap();
207 pages_to_weeks(rx, dest, clobber).await.unwrap();
0000000000000000000000000000000208 }
209 Commands::Tail { after } => {
210 let mut url = args.upstream;
···1use allegedly::{
2 Db, Dt, ExportPage, FolderSource, HttpSource, PageBoundaryState, backfill, backfill_to_pg,
3+ bin_init, pages_to_pg, pages_to_weeks, poll_upstream, serve,
4};
5+use clap::{CommandFactory, Parser, Subcommand};
6use reqwest::Url;
7+use std::{net::SocketAddr, path::PathBuf, time::Instant};
8use tokio::sync::{mpsc, oneshot};
910#[derive(Debug, Parser)]
···71 #[arg(long, action)]
72 clobber: bool,
73 },
74+ /// Wrap a did-method-plc server, syncing upstream and blocking op submits
75+ Mirror {
76+ /// the wrapped did-method-plc server
77+ #[arg(long, env)]
78+ wrap: Url,
79+ /// the wrapped did-method-plc server's database (write access required)
80+ #[arg(long, env)]
81+ wrap_pg: Url,
82+ /// wrapping server listen address
83+ #[arg(short, long, env)]
84+ #[clap(default_value = "127.0.0.1:8000")]
85+ bind: SocketAddr,
86+ },
87 /// Poll an upstream PLC server and log new ops to stdout
88 Tail {
89 /// Begin tailing from a specific timestamp for replay or wait-until
···134135#[tokio::main]
136async fn main() {
00137 let args = Cli::parse();
138+ let matches = Cli::command().get_matches();
139+ let name = matches.subcommand().map(|(name, _)| name).unwrap_or("???");
140+ bin_init(name);
141142 let t0 = Instant::now();
143 match args.command {
···219 log::trace!("ensuring output directory exists");
220 std::fs::create_dir_all(&dest).unwrap();
221 pages_to_weeks(rx, dest, clobber).await.unwrap();
222+ }
223+ Commands::Mirror {
224+ wrap,
225+ wrap_pg,
226+ bind,
227+ } => {
228+ let db = Db::new(wrap_pg.as_str()).await.unwrap();
229+ let latest = db
230+ .get_latest()
231+ .await
232+ .unwrap()
233+ .expect("there to be at least one op in the db. did you backfill?");
234+235+ let (tx, rx) = mpsc::channel(2);
236+ // upstream poller
237+ tokio::task::spawn(async move {
238+ log::info!("starting poll reader...");
239+ let mut url = args.upstream;
240+ url.set_path("/export");
241+ tokio::task::spawn(
242+ async move { poll_upstream(Some(latest), url, tx).await.unwrap() },
243+ );
244+ });
245+ // db writer
246+ let poll_db = db.clone();
247+ tokio::task::spawn(async move {
248+ log::info!("starting db writer...");
249+ pages_to_pg(poll_db, rx).await.unwrap();
250+ });
251+252+ serve(wrap, bind).await.unwrap();
253 }
254 Commands::Tail { after } => {
255 let mut url = args.upstream;