evergreen/osrf/app.rs
1use crate::osrf::client;
2use crate::osrf::method;
3use crate::EgError;
4use crate::EgResult;
5use std::any::Any;
6
7/*
8* Server spawns a worker thread
9* Worker thread calls an ApplicationWorkerFactory function to
10 generate an ApplicationWorker.
11* app_worker.worker_start() is called allowing the worker to
12 perform any other startup routines.
13* Worker waits for inbound method calls.
14* Inbound method call arrives
15* app_worker.start_session() is called on CONNECT or any stateless request.
16* Called method is looked up in the app_worker's methods().
17* method handler function is called to handle the request.
18* If a DISCONNECT is received OR its a stateless API call,
19 worker.end_session() is called after the API call completes.
20* Once all requests are complete in the current session,
21 the Worker goes back to sleep to wait for more requests.
22* Just before the thread ends/joins, app_worker.worker_end() is called.
23*/
24
25/// Function that generates ApplicationWorker implementers.
26///
27/// This type of function may be cloned and passed through the thread
28/// boundary, but the ApplicationWorker's it generates are not
29/// guaranteed to be thread-Send-able, hence the factory approach.
30pub type ApplicationWorkerFactory = fn() -> Box<dyn ApplicationWorker>;
31
32pub trait ApplicationWorker: Any {
33 /// Required for downcasting into the local ApplicationWorker implementation type.
34 fn as_any_mut(&mut self) -> &mut dyn Any;
35
36 /// Called just after a new worker is spawned.
37 fn worker_start(&mut self, client: client::Client) -> EgResult<()>;
38
39 /// Called for stateful sessions on CONNECT and for each request
40 /// in a stateless session.
41 fn start_session(&mut self) -> EgResult<()>;
42
43 /// Called for stateful sessions on DISCONNECT or keepliave timeout --
44 /// Also called for stateless sessions (one-offs) after the request
45 /// completes.
46 fn end_session(&mut self) -> EgResult<()>;
47
48 /// Called if the client sent a CONNECT but failed to send a DISCONNECT
49 /// before the keepliave timeout expired.
50 fn keepalive_timeout(&mut self) -> EgResult<()>;
51
52 /// Called on the worker when a MethodCall invocation exits with an Err.
53 fn api_call_error(&mut self, api_name: &str, error: EgError);
54
55 /// Called every time our worker wakes up to check for signals,
56 /// timeouts, etc.
57 ///
58 /// This method is only called when no other actions occur as a
59 /// result of a worker thread waking up. It's not called if there
60 /// is a shutdown signal, keepliave timeout, API request, etc.
61 ///
62 /// * `connected` - True if we are in the middle of a stateful conversation.
63 fn worker_idle_wake(&mut self, connected: bool) -> EgResult<()>;
64
65 /// Called after all work is done and the thread is going away.
66 ///
67 /// Offers a chance to clean up any resources.
68 fn worker_end(&mut self) -> EgResult<()>;
69}
70
71pub trait Application {
72 /// Application service name, e.g. opensrf.settings
73 fn name(&self) -> &str;
74
75 /// Called when a service first starts, just after connecting to OpenSRF.
76 fn init(&mut self, client: client::Client) -> EgResult<()>;
77
78 /// Tell the server what methods this application implements.
79 ///
80 /// Called after self.init(), but before workers are spawned.
81 fn register_methods(&self, client: client::Client) -> EgResult<Vec<method::MethodDef>>;
82
83 /// Returns a function pointer (ApplicationWorkerFactory) that returns
84 /// new ApplicationWorker's when called.
85 ///
86 /// Dynamic trait objects cannot be passed to threads, but functions
87 /// that generate them can.
88 fn worker_factory(&self) -> fn() -> Box<dyn ApplicationWorker>;
89}