taba_cli/tui/worker/
mod.rs1use std::sync::mpsc::{Receiver, Sender};
5use std::sync::{Arc, Mutex};
6use std::thread;
7
8use taba_client::{Call, Client, Error, Reply};
9
10use crate::tui::api::ApiCall;
11use crate::tui::msg::Msg;
12
13pub trait Backend: Send + Sync {
15 fn call(&self, call: &Call) -> Result<Reply, Error>;
16}
17
18impl Backend for Client {
19 fn call(&self, call: &Call) -> Result<Reply, Error> {
20 Client::call(self, call)
21 }
22}
23
24pub struct SwitchBackend {
27 current: std::sync::RwLock<Arc<dyn Backend>>,
28}
29
30impl SwitchBackend {
31 pub fn new(first: Arc<dyn Backend>) -> SwitchBackend {
32 SwitchBackend {
33 current: std::sync::RwLock::new(first),
34 }
35 }
36
37 pub fn switch(&self, next: Arc<dyn Backend>) {
38 *self.current.write().unwrap_or_else(|e| e.into_inner()) = next;
39 }
40}
41
42impl Backend for SwitchBackend {
43 fn call(&self, call: &Call) -> Result<Reply, Error> {
44 let backend = Arc::clone(&self.current.read().unwrap_or_else(|e| e.into_inner()));
45 backend.call(call)
46 }
47}
48
49pub const THREADS: usize = 4;
51
52struct Job {
53 id: u64,
54 generation: u64,
55 call: ApiCall,
56}
57
58pub struct Workers {
59 jobs: Sender<Job>,
60}
61
62impl Workers {
63 pub fn start(backend: Arc<dyn Backend>, results: Sender<Msg>, threads: usize) -> Workers {
65 let (jobs, queue) = std::sync::mpsc::channel::<Job>();
66 let queue: Arc<Mutex<Receiver<Job>>> = Arc::new(Mutex::new(queue));
67 for _ in 0..threads.max(1) {
68 let queue = Arc::clone(&queue);
69 let backend = Arc::clone(&backend);
70 let results = results.clone();
71 thread::spawn(move || loop {
72 let job = match queue.lock() {
74 Ok(guard) => guard.recv(),
75 Err(_) => return,
76 };
77 let Ok(job) = job else { return };
78 let result = backend.call(&job.call.to_call());
79 let reply = Msg::Reply {
80 id: job.id,
81 generation: job.generation,
82 call: job.call,
83 result,
84 };
85 if results.send(reply).is_err() {
86 return;
87 }
88 });
89 }
90 Workers { jobs }
91 }
92
93 pub fn submit(&self, id: u64, generation: u64, call: ApiCall) {
94 let _ = self.jobs.send(Job {
95 id,
96 generation,
97 call,
98 });
99 }
100}
101
102#[cfg(test)]
103mod tests;