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}