blob: fc5b6d659b5f3128929f270d593c66c7882063ef [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! This program serves a single instance ("default") of `fuchsia.examples.services.BankAccount`
//! initialized with a bank account owner's name (first arg in CML) and an initial balance in cents
//! (second arg in CML).
use {
anyhow::{Context, Result},
fidl_fuchsia_examples_services as fexamples,
fuchsia_component::server::ServiceFs,
futures::lock::Mutex,
futures::prelude::*,
log::*,
std::{env, sync::Arc},
};
struct Account {
/// Account owner's name.
name: String,
/// Account balance in cents.
balance: i64,
}
#[fuchsia::component]
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!("starting bank account provider with name={} and balance={}", &name, &balance);
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!("failed to serve BankAccount request: {}", err),
}
}
})
.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!("balance of account {} is now ${}", &account.name, &account.balance);
responder.send(success).context("failed to send debit reply")?;
}
fexamples::ReadWriteAccountRequest::Credit { amount, responder } => {
account.balance += amount;
info!("balance of account {} is now ${}", &account.name, &account.balance);
responder.send().context("failed to send credit reply")?;
}
}
}
}
}
Ok(())
}