Actor
Actor is trait that processing some methods to set up necessary conditions before the whole programs starts/ends. it basically categorizes:
- Preparations Beforehand method
new
,open_actor
andclose_actor
are provided to serve that purpose. First of all, you can define a struct according to your requirement, eg:
#![allow(unused)] fn main() { #[dyer::actor] struct MyActor { start_uris: Vec<String> ... } }
the struct MyActor
should contain appropirate fields which initialized by the method new
.
#![allow(unused)] fn main() { #[dyer::async_trait] impl Actor<_, _> for MyActor { async fn new() -> Self { Self { start_uris: vec!["https://example.domain/path/to/site1".to_string(), "https://example.domain/path/to/site2".to_string() ] //other fields ... } } // other method of Actor ... } }
before the whole program starts, the method open_actor
gets called. preparation should be done here! but wait, what should we do here? let's extend the example above a little bit.
all start uris are stored by lines in a file
uris.txt
#![allow(unused)] fn main() { #[dyer::actor] pub struct MyActor { start_uris: Vec<String> } #[dyer::async_trait] impl Actor<_, _> for MyActor { async fn new() -> Self { use std::io::Read; let mut file = std::fs::File::open("path/to/uris.txt").unwrap(); let buf = std::io::BufReader::new(file); let uris = buf.lines().map(|line| { line.unwrap() }).collect::<Vec<String>>(); Self { start_uris: uris } } async fn open_actor(&mut self, _app: &mut App<_>) { self.start_uris.for_each(|uri| { Task::get(uri) .parser(..) .body(Body::empty(), "myactor_identifier".into()) .unwrap() }); } // other method of Actor ... } }
Analogously you can do some staff with close_actor
when program ends.
- Assignments Entry The program cannot starts without
Task
,entry_task
serve as a way to add tasks to the lists. It expects a vector ofTask
when the function ends,
#![allow(unused)] fn main() { #[dyer::async_trait] impl Actor<_, _> for MyActor { async fn entry_task(&mut self) -> Result<Vec<Task>, Box<dyn Error>> { self.start_uris.map(|uri| { Task::get(uri) .parser(..) .body(Body::empty(), "myactor_identifier".into()) .unwrap() }).collect::<_>() } // other method of Actor ... } }
As for entry_affix
, it is commonly not necessary unless modification is required for that Task
,
But what is that? before we answer that let's take a look at the structure of Task,
#![allow(unused)] fn main() { pub struct Task { /// main infomation that represents a `Task` pub(crate) inner: InnerTask, /// Formdata, files or other request parameters stored here pub(crate) body: Body, ... } pub struct InnerTask { pub uri: Uri, /// request's vesoin pub method: Method, /// additional headers if necessary pub headers: HeaderMap<HeaderValue>, ... } }
it is obvious to see that a Task
almost contains infomation to make a request.
But when does entry_affix
play its role? Here are some scenarios that you may use it.
- Headers Modification (eg. Cookies, User-Agents, Tokens, and etc.)
- javascript simulation
- FFI and others
Here we focus on the first one(most used) and an example is given at section Actor.