Skip to content

Commit f1929ef

Browse files
authored
Merge pull request #632 from swimos/example_app_join_value
Join value example app
2 parents fc2c56d + 9262fe1 commit f1929ef

File tree

5 files changed

+192
-0
lines changed

5 files changed

+192
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ members = [
3737
"example_apps/tutorial_app",
3838
"example_apps/tutorial_app/model",
3939
"example_apps/tutorial_app/generator",
40+
"example_apps/join_value",
4041
]
4142

4243
exclude = [

example_apps/join_value/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "join_value"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
swimos = { path = "../../swimos", features = ["server", "agent"] }
8+
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
9+
example-util = { path = "../example_util" }
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use std::collections::HashMap;
2+
use swimos::agent::agent_lifecycle::utility::HandlerContext;
3+
use swimos::agent::event_handler::{EventHandler, HandlerActionExt};
4+
use swimos::agent::lanes::{CommandLane, JoinValueLane};
5+
use swimos::agent::projections;
6+
use swimos::agent::{lifecycle, AgentLaneModel};
7+
8+
#[derive(AgentLaneModel)]
9+
#[projections]
10+
pub struct BuildingAgent {
11+
lights: JoinValueLane<u64, bool>,
12+
register_room: CommandLane<u64>,
13+
}
14+
15+
#[derive(Clone)]
16+
pub struct BuildingLifecycle;
17+
18+
#[lifecycle(BuildingAgent)]
19+
impl BuildingLifecycle {
20+
#[on_start]
21+
pub fn on_start(
22+
&self,
23+
context: HandlerContext<BuildingAgent>,
24+
) -> impl EventHandler<BuildingAgent> {
25+
context
26+
.get_agent_uri()
27+
.and_then(move |uri| context.effect(move || println!("Starting agent at: {}", uri)))
28+
}
29+
30+
#[on_stop]
31+
pub fn on_stop(
32+
&self,
33+
context: HandlerContext<BuildingAgent>,
34+
) -> impl EventHandler<BuildingAgent> {
35+
context
36+
.get_agent_uri()
37+
.and_then(move |uri| context.effect(move || println!("Stopping agent at: {}", uri)))
38+
}
39+
40+
#[on_command(register_room)]
41+
pub fn register_room(
42+
&self,
43+
context: HandlerContext<BuildingAgent>,
44+
room_id: &u64,
45+
) -> impl EventHandler<BuildingAgent> {
46+
let room_id = *room_id;
47+
context
48+
.get_parameter("name")
49+
.and_then(move |building_name: Option<String>| {
50+
let building_name = building_name.expect("Missing building name URI parameter");
51+
context.add_downlink(
52+
BuildingAgent::LIGHTS,
53+
room_id,
54+
None,
55+
format!("/rooms/{building_name}/{room_id}").as_str(),
56+
"lights",
57+
)
58+
})
59+
.followed_by(context.effect(move || println!("Registered room: {room_id}")))
60+
}
61+
62+
#[on_update(lights)]
63+
fn lights(
64+
&self,
65+
context: HandlerContext<BuildingAgent>,
66+
_map: &HashMap<u64, bool>,
67+
key: u64,
68+
prev: Option<bool>,
69+
new_value: &bool,
70+
) -> impl EventHandler<BuildingAgent> {
71+
let new_value = *new_value;
72+
context.effect(move || println!("Light {key} changed from {prev:?} to {new_value}"))
73+
}
74+
}

example_apps/join_value/src/main.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2015-2023 Swim Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use std::{error::Error, time::Duration};
16+
17+
use crate::{
18+
building::{BuildingAgent, BuildingLifecycle},
19+
room::{RoomAgent, RoomLifecycle},
20+
};
21+
use example_util::{example_logging, manage_handle};
22+
use swimos::{
23+
agent::agent_model::AgentModel, route::RoutePattern, server::Server, server::ServerBuilder,
24+
};
25+
26+
mod building;
27+
mod room;
28+
29+
#[tokio::main]
30+
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
31+
example_logging()?;
32+
33+
let building_route = RoutePattern::parse_str("/buildings/:name")?;
34+
let building_agent =
35+
AgentModel::new(BuildingAgent::default, BuildingLifecycle.into_lifecycle());
36+
37+
let room_route = RoutePattern::parse_str("/rooms/:building/:room")?;
38+
let room_agent = AgentModel::new(RoomAgent::default, RoomLifecycle.into_lifecycle());
39+
40+
let server = ServerBuilder::with_plane_name("Building Plane")
41+
.add_route(building_route, building_agent)
42+
.add_route(room_route, room_agent)
43+
.update_config(|config| {
44+
config.agent_runtime.inactive_timeout = Duration::from_secs(5 * 60);
45+
})
46+
.build()
47+
.await?;
48+
49+
let (task, handle) = server.run();
50+
let shutdown = manage_handle(handle);
51+
let (_, result) = tokio::join!(shutdown, task);
52+
53+
result?;
54+
println!("Server stopped successfully.");
55+
Ok(())
56+
}

example_apps/join_value/src/room.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use std::str::FromStr;
2+
use swimos::agent::agent_lifecycle::utility::HandlerContext;
3+
use swimos::agent::event_handler::{EventHandler, HandlerActionExt};
4+
use swimos::agent::lanes::ValueLane;
5+
use swimos::agent::projections;
6+
use swimos::agent::{lifecycle, AgentLaneModel};
7+
8+
#[derive(AgentLaneModel)]
9+
#[projections]
10+
pub struct RoomAgent {
11+
lights: ValueLane<bool>,
12+
}
13+
14+
#[derive(Clone)]
15+
pub struct RoomLifecycle;
16+
17+
#[lifecycle(RoomAgent)]
18+
impl RoomLifecycle {
19+
#[on_start]
20+
pub fn on_start(&self, context: HandlerContext<RoomAgent>) -> impl EventHandler<RoomAgent> {
21+
context
22+
.get_agent_uri()
23+
.and_then(move |uri| context.effect(move || println!("Starting agent at: {}", uri)))
24+
.followed_by(context.get_parameter("building").and_then(
25+
move |building_name: Option<String>| {
26+
context
27+
.get_parameter("room")
28+
.and_then(move |room_id: Option<String>| {
29+
let building_name =
30+
building_name.expect("Missing building URI parameter");
31+
let room_id_str = room_id.expect("Missing room ID URI parameter");
32+
let room_id = u64::from_str(room_id_str.as_str())
33+
.expect("Expected a u64 room ID");
34+
35+
context.send_command(
36+
None,
37+
format!("/buildings/{building_name}"),
38+
"register_room".to_string(),
39+
room_id,
40+
)
41+
})
42+
},
43+
))
44+
}
45+
46+
#[on_stop]
47+
pub fn on_stop(&self, context: HandlerContext<RoomAgent>) -> impl EventHandler<RoomAgent> {
48+
context
49+
.get_agent_uri()
50+
.and_then(move |uri| context.effect(move || println!("Starting agent at: {}", uri)))
51+
}
52+
}

0 commit comments

Comments
 (0)