| 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 | |
| 4 | use notebook::session::Section; |
| 5 | use 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 | }; |
| 13 | use std::time::{Duration, Instant}; |
| 14 | |
| 15 | fn 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 | } |