text_document/
operation.rs1use std::thread;
4use std::time::Duration;
5
6use crate::Result;
7
8use frontend::AppContext;
9
10type ResultFn<T> = Box<dyn Fn(&AppContext, &str) -> Option<Result<T>> + Send>;
12
13pub(crate) struct OperationState {
15 ctx: AppContext,
16}
17
18impl OperationState {
19 pub fn new(ctx: &AppContext) -> Self {
20 Self { ctx: ctx.clone() }
21 }
22}
23
24pub struct Operation<T> {
34 id: String,
35 state: OperationState,
36 result_fn: ResultFn<T>,
37}
38
39impl<T> Operation<T> {
40 pub(crate) fn new(id: String, ctx: &AppContext, result_fn: ResultFn<T>) -> Self {
41 Self {
42 id,
43 state: OperationState::new(ctx),
44 result_fn,
45 }
46 }
47
48 pub fn id(&self) -> &str {
50 &self.id
51 }
52
53 pub fn progress(&self) -> Option<(f64, String)> {
56 let mgr = self.state.ctx.long_operation_manager.lock();
57 mgr.get_operation_progress(&self.id)
58 .map(|p| (p.percentage as f64, p.message.unwrap_or_default()))
59 }
60
61 pub fn is_done(&self) -> bool {
63 (self.result_fn)(&self.state.ctx, &self.id).is_some()
64 }
65
66 pub fn cancel(&self) {
68 self.state
69 .ctx
70 .long_operation_manager
71 .lock()
72 .cancel_operation(&self.id);
73 }
74
75 pub fn wait(self) -> Result<T> {
78 loop {
79 if let Some(result) = (self.result_fn)(&self.state.ctx, &self.id) {
80 return result;
81 }
82 thread::sleep(Duration::from_millis(50));
83 }
84 }
85
86 pub fn wait_timeout(self, timeout: Duration) -> Option<Result<T>> {
89 let deadline = std::time::Instant::now() + timeout;
90 loop {
91 if let Some(result) = (self.result_fn)(&self.state.ctx, &self.id) {
92 return Some(result);
93 }
94 if std::time::Instant::now() >= deadline {
95 return None;
96 }
97 let remaining = deadline.saturating_duration_since(std::time::Instant::now());
98 thread::sleep(remaining.min(Duration::from_millis(50)));
99 }
100 }
101
102 pub fn try_result(&mut self) -> Option<Result<T>> {
105 (self.result_fn)(&self.state.ctx, &self.id)
106 }
107}
108
109#[derive(Debug, Clone)]
113pub struct MarkdownImportResult {
114 pub block_count: usize,
115}
116
117#[derive(Debug, Clone)]
119pub struct HtmlImportResult {
120 pub block_count: usize,
121}
122
123#[derive(Debug, Clone)]
125pub struct DocxExportResult {
126 pub file_path: String,
127 pub paragraph_count: usize,
128}