Implement ping pong example.

This commit is contained in:
Alejandro Cabeza Romero 2024-12-20 17:25:30 +01:00
parent 4160cdd859
commit 79a22e9bc2
No known key found for this signature in database
GPG Key ID: DA3D14AE478030FD
7 changed files with 184 additions and 0 deletions

View File

@ -3,6 +3,7 @@ resolver = "2"
members = [
"overwatch-rs",
"overwatch-derive",
"examples/ping_pong",
]
[profile.release-opt]

View File

@ -0,0 +1,10 @@
[package]
name = "ping_pong"
version = "0.1.0"
edition = "2021"
[dependencies]
overwatch-rs = { path = "../../overwatch-rs" }
overwatch-derive = { path = "../../overwatch-derive" }
async-trait = "0.1.83"
tokio = { version = "1", features = ["macros"] }

View File

@ -0,0 +1,17 @@
# PingPong
This example project demonstrates how to set up a basic Overwatch application in Rust.
### Behaviour
This project demonstrates a simple communication pattern between two services.
1. Every second, the `Ping` service sends a message to the `Pong` service.
2. The `Pong` service receives the message and prints it to the console. Afterwards, it sends a message back to the `Ping` service.
3. The `Ping` service receives the message and prints it to the console.
### Features
- **Services**: Shows how to define and register services within an Overwatch application.
- **Message Passing**: Demonstrates communication between services using the relay.
### About
This project serves as a barebones template to get started with the Overwatch library.
It provides the foundational structure for creating more complex applications.

View File

@ -0,0 +1,26 @@
// Crate
use overwatch_derive::Services;
use overwatch_rs::overwatch::OverwatchRunner;
use overwatch_rs::services::handle::ServiceHandle;
// Internal
use crate::service_ping::PingService;
use crate::service_pong::PongService;
mod service_ping;
mod service_pong;
mod messages;
#[derive(Services)]
struct PingPong {
ping: ServiceHandle<PingService>,
pong: ServiceHandle<PongService>,
}
fn main() {
let ping_pong_settings = PingPongServiceSettings {
ping: (),
pong: (),
};
let ping_pong = OverwatchRunner::<PingPong>::run(ping_pong_settings, None).expect("OverwatchRunner failed");
ping_pong.wait_finished();
}

View File

@ -0,0 +1,15 @@
use overwatch_rs::services::relay::RelayMessage;
#[derive(Debug)]
pub enum PingMessage {
Pong
}
impl RelayMessage for PingMessage {}
#[derive(Debug)]
pub enum PongMessage {
Ping
}
impl RelayMessage for PongMessage {}

View File

@ -0,0 +1,68 @@
// Crates
use std::time::Duration;
use tokio::time::sleep;
use overwatch_rs::DynError;
use overwatch_rs::services::{ServiceCore, ServiceData, ServiceId};
use overwatch_rs::services::handle::ServiceStateHandle;
use overwatch_rs::services::state::{NoOperator, NoState};
// Internal
use crate::messages::{PingMessage, PongMessage};
use crate::service_pong::PongService;
pub struct PingService {
service_state_handle: ServiceStateHandle<Self>
}
impl ServiceData for PingService {
const SERVICE_ID: ServiceId = "ping";
type Settings = ();
type State = NoState<Self::Settings>;
type StateOperator = NoOperator<Self::State>;
type Message = PingMessage;
}
#[async_trait::async_trait]
impl ServiceCore for PingService {
fn init(service_state_handle: ServiceStateHandle<Self>) -> Result<Self, DynError> {
Ok(Self {
service_state_handle
})
}
async fn run(self) -> Result<(), DynError> {
let Self {
service_state_handle
} = self;
let mut inbound_relay = service_state_handle.inbound_relay;
let pong_outbound_relay = service_state_handle.overwatch_handle.relay::<PongService>().connect().await?;
let mut pong_count = 0;
loop {
tokio::select! {
_ = sleep(Duration::from_secs(1)) => {
println!("Sending Ping");
pong_outbound_relay.send(PongMessage::Ping).await.unwrap();
}
Some(message) = inbound_relay.recv() => {
match message {
PingMessage::Pong => {
println!("Received Pong");
pong_count += 1;
}
}
}
true = async {
pong_count >= 5
} => {
println!("Received {} Pongs. Exiting...", pong_count);
break;
}
}
}
service_state_handle.overwatch_handle.shutdown().await;
Ok(())
}
}

View File

@ -0,0 +1,47 @@
// Crates
use overwatch_rs::DynError;
use overwatch_rs::services::{ServiceCore, ServiceData, ServiceId};
use overwatch_rs::services::handle::ServiceStateHandle;
use overwatch_rs::services::state::{NoOperator, NoState};
use crate::messages::{PingMessage, PongMessage};
use crate::service_ping::PingService;
pub struct PongService {
service_state_handle: ServiceStateHandle<Self>
}
impl ServiceData for PongService {
const SERVICE_ID: ServiceId = "";
type Settings = ();
type State = NoState<Self::Settings>;
type StateOperator = NoOperator<Self::State>;
type Message = PongMessage;
}
#[async_trait::async_trait]
impl ServiceCore for PongService {
fn init(service_state_handle: ServiceStateHandle<Self>) -> Result<Self, DynError> {
Ok(Self {
service_state_handle
})
}
async fn run(self) -> Result<(), DynError> {
let Self {
service_state_handle
} = self;
let mut inbound_relay = service_state_handle.inbound_relay;
let ping_outbound_relay = service_state_handle.overwatch_handle.relay::<PingService>().connect().await?;
while let Some(message) = inbound_relay.recv().await {
match message {
PongMessage::Ping => {
println!("Received Ping. Sending Pong.");
ping_outbound_relay.send(PingMessage::Pong).await.unwrap();
}
}
}
Ok(())
}
}