Last active
March 5, 2024 06:36
-
-
Save fulmicoton/022e70942c5a34d5533558adb1b93a18 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
syntax = "proto3"; | |
package bank; | |
service Bank { | |
rpc ApplyTransaction(TransactionRequest) returns (TransactionReply) {} | |
} | |
message TransactionRequest { | |
string from_account = 1; | |
string to_account = 2; | |
uint64 amount = 3; | |
} | |
message TransactionReply { | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use tokio::sync::Mutex; | |
use tonic::transport::Server; | |
use tracing::info; | |
tonic::include_proto!("bank"); | |
#[derive(Default)] | |
pub struct MyBank { | |
accounts: Mutex<HashMap<String, u64>>, | |
} | |
async fn set_account(account_lock: &mut HashMap<String, u64>, account: &str, new_amount: u64) { | |
info!("SET ACCOUNT: {} -> {}", account, new_amount); | |
account_lock.insert(account.to_string(), new_amount); | |
} | |
#[tonic::async_trait] | |
impl bank_server::Bank for MyBank { | |
async fn apply_transaction( | |
&self, | |
tonic_request: tonic::Request<TransactionRequest>, | |
) -> Result<tonic::Response<TransactionReply>, tonic::Status> { | |
let TransactionRequest { | |
from_account, | |
to_account, | |
amount, | |
} = tonic_request.into_inner(); | |
if from_account == to_account { | |
// We choose to return an error here. | |
return Err(tonic::Status::invalid_argument("from and to accounts are the same")); | |
} | |
let mut accounts_lock = self.accounts.lock().await; | |
// We check this won't overflow first, the borrow checker prevents us | |
// from holding 2 mutable reference items at the same time but whatever. | |
let Some(&to_amount) = accounts_lock.get(&to_account) else { | |
return Err(tonic::Status::invalid_argument("to account does not exist")); | |
}; | |
let Some(new_to_amount) = to_amount.checked_add(amount) else { | |
return Err(tonic::Status::invalid_argument("to account would overflow")); | |
}; | |
let Some(&from_amount) = accounts_lock.get(&from_account) else { | |
return Err(tonic::Status::invalid_argument("from account does not exist")); | |
}; | |
let Some(new_from_amount) = from_amount.checked_sub(amount) else { | |
return Err(tonic::Status::invalid_argument("insufficient founds")); | |
}; | |
// All clear! Let's run the transaction. | |
set_account(&mut accounts_lock, &to_account, new_to_amount).await; | |
set_account(&mut accounts_lock, &from_account, new_from_amount).await; | |
Ok(tonic::Response::new(TransactionReply {})) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment