Cadre d'acteur pour la rouille
Any type) Pour utiliser actix , ajoutez-le à votre Cargo.toml :
[ dependencies ]
actix = " 0.13 " Afin d'utiliser Actix, vous devez d'abord créer un System .
fn main ( ) {
let system = actix :: System :: new ( ) ;
system . run ( ) ;
} Actix utilise le runtime Tokio. System::new() crée une nouvelle boucle d'événements. System.run() démarre la boucle d'événement Tokio et se terminera une fois que l'acteur System reçoit le message SystemExit .
Afin de définir un acteur, vous devez définir une structure et lui faire mettre en œuvre le trait Actor .
use actix :: { Actor , Context , System } ;
struct MyActor ;
impl Actor for MyActor {
type Context = Context < Self > ;
fn started ( & mut self , _ctx : & mut Self :: Context ) {
println ! ( "I am alive!" ) ;
System :: current ( ) . stop ( ) ; // <- stop system
}
}
fn main ( ) {
let system = System :: new ( ) ;
let _addr = system . block_on ( async { MyActor . start ( ) } ) ;
system . run ( ) . unwrap ( ) ;
} La frai d'un nouvel acteur est réalisée via les méthodes start et create du trait d'acteur. Il fournit plusieurs façons différentes de créer des acteurs; Pour plus de détails, vérifiez les documents. Vous pouvez implémenter les méthodes started , stopping et stopped du trait d'acteur. started est appelé lorsque l'acteur commence et stopping lorsque l'acteur termine. Vérifiez les documents API pour plus d'informations sur le cycle de vie de l'acteur.
Un acteur communique avec un autre acteur en envoyant des messages. Dans Actix, tous les messages sont tapés. Définissons un message Sum simple avec deux paramètres usize et un acteur qui acceptera ce message et renverra la somme de ces deux nombres. Ici, nous utilisons l'attribut #[actix::main] comme un moyen plus facile de démarrer notre System et de conduire notre fonction principale afin que nous puissions facilement .await pour les réponses renvoyées de l' Actor .
use actix :: prelude :: * ;
// this is our Message
// we have to define the response type (rtype)
# [ derive ( Message ) ]
# [ rtype ( usize ) ]
struct Sum ( usize , usize ) ;
// Actor definition
struct Calculator ;
impl Actor for Calculator {
type Context = Context < Self > ;
}
// now we need to implement `Handler` on `Calculator` for the `Sum` message.
impl Handler < Sum > for Calculator {
type Result = usize ; // <- Message response type
fn handle ( & mut self , msg : Sum , _ctx : & mut Context < Self > ) -> Self :: Result {
msg . 0 + msg . 1
}
}
# [ actix :: main ] // <- starts the system and block until future resolves
async fn main ( ) {
let addr = Calculator . start ( ) ;
let res = addr . send ( Sum ( 10 , 5 ) ) . await ; // <- send message and get future for result
match res {
Ok ( result ) => println ! ( "SUM: {}" , result ) ,
_ => println ! ( "Communication to the actor has failed" ) ,
}
} Toutes les communications avec les acteurs passent par un objet Addr . Vous pouvez do_send un message sans attendre de réponse, ou vous pouvez send un acteur à un acteur un message spécifique. Le trait Message définit le type de résultat pour un message.
Vous avez peut-être remarqué que les méthodes des traits d' Actor et Handler s'acceptent &mut self sont donc invités à stocker quoi que ce soit dans un acteur et à le muter chaque fois que cela est nécessaire.
Les objets d'adresse nécessitent un type d'acteur, mais si nous voulons simplement envoyer un message spécifique à un acteur qui peut gérer le message, nous pouvons utiliser l'interface Recipient . Créons un nouvel acteur qui utilise Recipient .
use actix :: prelude :: * ;
use std :: time :: Duration ;
# [ derive ( Message ) ]
# [ rtype ( result = "()" ) ]
struct Ping {
pub id : usize ,
}
// Actor definition
struct Game {
counter : usize ,
name : String ,
recipient : Recipient < Ping > ,
}
impl Actor for Game {
type Context = Context < Game > ;
}
// simple message handler for Ping message
impl Handler < Ping > for Game {
type Result = ( ) ;
fn handle ( & mut self , msg : Ping , ctx : & mut Context < Self > ) {
self . counter += 1 ;
if self . counter > 10 {
System :: current ( ) . stop ( ) ;
} else {
println ! ( "[{0}] Ping received {1}" , self . name , msg . id ) ;
// wait 100 nanoseconds
ctx . run_later ( Duration :: new ( 0 , 100 ) , move |act , _| {
act . recipient . do_send ( Ping { id : msg . id + 1 } ) ;
} ) ;
}
}
}
fn main ( ) {
let system = System :: new ( ) ;
system . block_on ( async {
// To create a cyclic game link, we need to use a different constructor
// method to get access to its recipient before it starts.
let _game = Game :: create ( |ctx| {
// now we can get an address of the first actor and create the second actor
let addr = ctx . address ( ) ;
let addr2 = Game {
counter : 0 ,
name : String :: from ( "Game 2" ) ,
recipient : addr . recipient ( ) ,
}
. start ( ) ;
// let's start pings
addr2 . do_send ( Ping { id : 10 } ) ;
// now we can finally create first actor
Game {
counter : 0 ,
name : String :: from ( "Game 1" ) ,
recipient : addr2 . recipient ( ) ,
}
} ) ;
} ) ;
// let the actors all run until they've shut themselves down
system . run ( ) . unwrap ( ) ;
}Voir cet exemple de chat qui montre une utilisation plus complète dans un service client / serveur de réseautage.
Toutes les contributions sont les bienvenues, si vous avez une demande de fonctionnalité, n'hésitez pas à ouvrir un problème!
Ce projet est sous licence sous l'un ou l'autre des
à votre option.
La contribution au repo Actix est organisée en vertu des termes de l'alliance contributive. L'équipe Actix promet d'intervenir pour maintenir ce code de conduite.