1//! Times importing a generated page into a copy of a section, then typing one character
2//! into it until durable and queued: `save_probe SECTION PARAGRAPHS`.
3
4use notebook::session::Section;
5use onestore::{
6 document::{Format, Layout},
7 op::{Edit, Op, PageOp},
8 page::{
9 Outline, Page, PageObject, PageParagraph, Paragraph, ParagraphContent, TextObject,
10 text::new_id,
11 },
12};
13use std::time::{Duration, Instant};
14
15fn main() -> Result<(), Box<dyn std::error::Error>> {
16 let mut args = std::env::args().skip(1);
17 let (Some(source), Some(count)) = (args.next(), args.next()) else {
18 return Err("usage: save_probe SECTION PARAGRAPHS".into());
19 };
20 let count: usize = count.parse()?;
21 let directory = tempfile::tempdir()?;
22 let file = directory.path().join("probe.one");
23 std::fs::write(&file, std::fs::read(source)?)?;
24 let section = Section::open(&file, directory.path().join("cache"), || {})?;
25 let words = [
26 "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog",
27 ];
28 let paragraph = |i: usize| -> Result<PageParagraph, Box<dyn std::error::Error>> {
29 let text: Vec<&str> = (0..1 + i % 17).map(|j| words[(i * 7 + j) % 8]).collect();
30 Ok(PageParagraph {
31 id: new_id()?,
32 parent: None,
33 level: 1,
34 style: None,
35 format: Format::default(),
36 content: ParagraphContent::Text(TextObject {
37 id: new_id()?,
38 date_field: None,
39 text: Paragraph::new(text.join(" "), Format::default()),
40 tags: Vec::new(),
41 }),
42 lists: Vec::new(),
43 tags: Vec::new(),
44 media: Default::default(),
45 collapsed: false,
46 })
47 };
48 let imported = Page {
49 title: "Probe".into(),
50 identity: None,
51 created: None,
52 margin_origin: [0.0; 2],
53 rtl: false,
54 color: None,
55 rule_lines: None,
56 objects: vec![PageObject::Outline(Outline {
57 id: new_id()?,
58 title: false,
59 min_width: None,
60 layout: Layout {
61 x: Some(36.0),
62 y: Some(86.4),
63 ..Layout::default()
64 },
65 indents: Vec::new(),
66 paragraphs: (0..count).map(paragraph).collect::<Result<_, _>>()?,
67 unsupported: Vec::new(),
68 })],
69 definitions: Default::default(),
70 };
71 let start = Instant::now();
72 let space = section.import_page(&imported, "Probe")?;
73 println!("import {count}: {:?}", start.elapsed());
74 let text = section
75 .page(space)?
76 .objects
77 .iter()
78 .find_map(|object| match object {
79 PageObject::Outline(outline) if outline.paragraphs.len() == count => {
80 outline.paragraphs[count / 2].text().map(|text| text.id)
81 }
82 _ => None,
83 })
84 .ok_or("the imported outline is missing")?;
85 let typed = |word: &str| Edit {
86 at: 133_000_000_000_000_000,
87 ops: vec![Op::Page {
88 space,
89 op: PageOp::Text {
90 text,
91 range: 0..0,
92 with: word.into(),
93 },
94 }],
95 };
96 let start = Instant::now();
97 section.replica().apply("Probe", typed("x"))?;
98 println!("typed, durable: {:?}", start.elapsed());
99 let start = Instant::now();
100 section.apply("Probe", typed("y"))?;
101 println!("typed, queued: {:?}", start.elapsed());
102 let deadline = start + Duration::from_secs(600);
103 while Instant::now() < deadline {
104 if section.replica().pending()?.len() == 2 {
105 println!("queued edit durable: {:?}", start.elapsed());
106 break;
107 }
108 std::thread::sleep(Duration::from_millis(1));
109 }
110 section.close()?;
111 Ok(())
112}