-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support concurrent authenticated accounts (account switcher) (#578)
* Sketch AccountSwitcher. * Guard against adding an account multiple times. * Use generics for AccountSwitcher, move to sdk. * Bump unicode-width. * Begin utoipa upgrade in server. * Update comments for openapi paths. * Remove unused utoipa config. * Fix bug with address of NetworkAccount::new_unauthenticated().
- Loading branch information
Showing
10 changed files
with
182 additions
and
64 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
use crate::{ | ||
account::{Account, LocalAccount}, | ||
prelude::Address, | ||
}; | ||
|
||
/// Account switcher for local accounts. | ||
pub type LocalAccountSwitcher = AccountSwitcher< | ||
<LocalAccount as Account>::Error, | ||
<LocalAccount as Account>::NetworkResult, | ||
LocalAccount, | ||
>; | ||
|
||
/// Collection of accounts with a currently selected account. | ||
/// | ||
/// Allows multiple accounts to be authenticated concurrently | ||
/// so that integrations are able to operate on multiple accounts | ||
/// provided they are authenticated. | ||
pub struct AccountSwitcher<E, R, A: Account<Error = E, NetworkResult = R>> { | ||
accounts: Vec<A>, | ||
selected: Option<Address>, | ||
} | ||
|
||
impl<E, R, A: Account<Error = E, NetworkResult = R>> | ||
AccountSwitcher<E, R, A> | ||
{ | ||
/// Create an account switcher. | ||
pub fn new() -> Self { | ||
Self { | ||
accounts: Default::default(), | ||
selected: None, | ||
} | ||
} | ||
|
||
/// Number of accounts. | ||
pub fn len(&self) -> usize { | ||
self.accounts.len() | ||
} | ||
|
||
/// Add an account if it does not already exist and make | ||
/// it the selected account. | ||
/// | ||
/// If the account already exists it is selected. | ||
pub fn new_account(&mut self, account: A) -> bool { | ||
let address = *account.address(); | ||
if self.add_account(account) { | ||
self.selected = Some(address); | ||
true | ||
} else { | ||
self.selected = Some(address); | ||
false | ||
} | ||
} | ||
|
||
/// Add an account to the collection if it does not already exist. | ||
pub fn add_account(&mut self, account: A) -> bool { | ||
if self.position(account.address()).is_none() { | ||
self.accounts.push(account); | ||
true | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
/// Remove an account from the collection if it exists. | ||
pub fn remove_account(&mut self, address: &Address) -> bool { | ||
if let Some(position) = self.position(address) { | ||
self.accounts.remove(position); | ||
if self.selected == Some(*address) { | ||
self.selected = None; | ||
} | ||
true | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
/// Switch selected account. | ||
/// | ||
/// If no account exists for the given address no change | ||
/// is made to the current selection. | ||
pub fn switch_account(&mut self, address: &Address) -> bool { | ||
if self.position(address).is_some() { | ||
self.selected = Some(*address); | ||
true | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
/// Selected account. | ||
pub fn selected_account(&self) -> Option<&A> { | ||
if let Some(address) = &self.selected { | ||
if let Some(index) = self.position(address) { | ||
self.accounts.get(index) | ||
} else { | ||
None | ||
} | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
/// Mutable selected account. | ||
pub fn selected_account_mut(&mut self) -> Option<&mut A> { | ||
if let Some(address) = &self.selected { | ||
if let Some(index) = self.position(address) { | ||
self.accounts.get_mut(index) | ||
} else { | ||
None | ||
} | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
fn position(&self, address: &Address) -> Option<usize> { | ||
self.accounts.iter().position(|a| a.address() == address) | ||
} | ||
} |
This file contains 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
This file contains 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
This file contains 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
Oops, something went wrong.