1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use {
anyhow::{Context, Result},
fidl_fuchsia_examples_services as fexamples,
fuchsia_component::server::ServiceFs,
futures::lock::Mutex,
futures::prelude::*,
std::{env, sync::Arc},
tracing::*,
};
struct Account {
name: String,
balance: i64,
}
#[fuchsia::main]
async fn main() {
let mut args = env::args().skip(1);
let name = args.next().expect("name arg");
let balance = args.next().expect("balance arg").parse().expect("balance must be a number");
info!(%name, %balance, "starting bank account provider");
let account = Arc::new(Mutex::new(Account { name, balance }));
let mut fs = ServiceFs::new();
fs.dir("svc").add_unified_service(|req: fexamples::BankAccountRequest| req);
fs.take_and_serve_directory_handle().expect("failed to serve outgoing namespace");
fs.for_each_concurrent(None, move |request| {
let account = account.clone();
async move {
match handle_request(account.clone(), request).await {
Ok(()) => {}
Err(err) => error!(%err, "failed to serve BankAccount request"),
}
}
})
.await;
}
async fn handle_request(
account: Arc<Mutex<Account>>,
request: fexamples::BankAccountRequest,
) -> Result<()> {
match request {
fexamples::BankAccountRequest::ReadOnly(mut stream) => {
while let Some(request) =
stream.try_next().await.context("failed to get next read-only request")?
{
let account = account.lock().await;
match request {
fexamples::ReadOnlyAccountRequest::GetOwner { responder } => {
responder.send(&account.name).context("failed to send get_owner reply")?;
}
fexamples::ReadOnlyAccountRequest::GetBalance { responder } => {
responder
.send(account.balance)
.context("failed to send get_balance reply")?;
}
}
}
}
fexamples::BankAccountRequest::ReadWrite(mut stream) => {
while let Some(request) =
stream.try_next().await.context("failed to get next read-write request")?
{
let mut account = account.lock().await;
match request {
fexamples::ReadWriteAccountRequest::GetOwner { responder } => {
responder.send(&account.name).context("failed to send get_owner reply")?;
}
fexamples::ReadWriteAccountRequest::GetBalance { responder } => {
responder
.send(account.balance)
.context("failed to send get_balance reply")?;
}
fexamples::ReadWriteAccountRequest::Debit { amount, responder } => {
let success = if account.balance >= amount {
account.balance -= amount;
true
} else {
false
};
info!(account = %account.name, balance = %account.balance, "balance updated");
responder.send(success).context("failed to send debit reply")?;
}
fexamples::ReadWriteAccountRequest::Credit { amount, responder } => {
account.balance += amount;
info!(account = %account.name, balance = %account.balance, "balance updated");
responder.send().context("failed to send credit reply")?;
}
}
}
}
}
Ok(())
}