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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
//! Events emitted over the server-sent events channel to
//! notify connected clients that changes have been made.
use serde::{Deserialize, Serialize};
use web3_address::ethereum::Address;
use crate::{
commit::CommitProof,
events::{Event, WriteEvent},
vault::{secret::SecretId, Header, Summary, VaultId},
Error, Result,
};
/// Encapsulates a collection of change events.
///
/// Used so that we can group multiple changes into a
/// single notification to connected clients.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ChangeNotification {
/// The owner address.
address: Address,
/// The public key of the caller.
public_key: Vec<u8>,
/// The vault identifier.
vault_id: VaultId,
/// The commit proof.
proof: CommitProof,
/// Collection of change events.
changes: Vec<ChangeEvent>,
}
impl ChangeNotification {
/// Create a new change notification.
pub fn new(
address: &Address,
public_key: &[u8],
vault_id: &VaultId,
proof: CommitProof,
changes: Vec<ChangeEvent>,
) -> Self {
Self {
address: *address,
public_key: public_key.to_vec(),
vault_id: *vault_id,
proof,
changes,
}
}
/// Address of the owner that made the changes.
pub fn address(&self) -> &Address {
&self.address
}
/// The public key that made the change.
pub fn public_key(&self) -> &[u8] {
&self.public_key
}
/// The identifier of the vault that was modified.
pub fn vault_id(&self) -> &VaultId {
&self.vault_id
}
/// The commit proof after the change.
pub fn proof(&self) -> &CommitProof {
&self.proof
}
/// The collection of change events.
pub fn changes(&self) -> &[ChangeEvent] {
&self.changes
}
}
/// Server notifications sent over the server sent events stream.
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
pub enum ChangeEvent {
/// Event emitted when a vault is created.
CreateVault(Summary),
/// Event emitted when a vault is updated.
///
/// This occurs when the passphrase for a vault
/// has been changed.
UpdateVault,
/// Event emitted when a vault is deleted.
DeleteVault,
/// Event emitted when a vault name is set.
SetVaultName(String),
/// Event emitted when vault meta data is set.
SetVaultMeta,
/// Event emitted when a secret is created.
CreateSecret(SecretId),
/// Event emitted when a secret is updated.
UpdateSecret(SecretId),
/// Event emitted when a secret is deleted.
DeleteSecret(SecretId),
}
impl ChangeEvent {
/// Convert from a sync event.
pub async fn from_sync_event(event: &Event<'_>) -> Option<Self> {
match event {
Event::Write(_, event) => match event {
WriteEvent::CreateVault(vault) => {
let summary = Header::read_summary_slice(vault)
.await
.expect("failed to read summary from vault");
Some(ChangeEvent::CreateVault(summary))
}
WriteEvent::DeleteVault => Some(ChangeEvent::DeleteVault),
WriteEvent::SetVaultName(name) => {
Some(ChangeEvent::SetVaultName(name.to_string()))
}
WriteEvent::SetVaultMeta(_) => {
Some(ChangeEvent::SetVaultMeta)
}
WriteEvent::CreateSecret(secret_id, _) => {
Some(ChangeEvent::CreateSecret(*secret_id))
}
WriteEvent::UpdateSecret(secret_id, _) => {
Some(ChangeEvent::UpdateSecret(*secret_id))
}
WriteEvent::DeleteSecret(secret_id) => {
Some(ChangeEvent::DeleteSecret(*secret_id))
}
_ => None,
},
_ => None,
}
}
/// Convert from a write operation.
pub async fn try_from_write_event(
event: &WriteEvent<'_>,
) -> Result<Self> {
match event {
WriteEvent::CreateVault(vault) => {
let summary =
Header::read_summary_slice(vault.as_ref()).await?;
Ok(ChangeEvent::CreateVault(summary))
}
WriteEvent::DeleteVault => Ok(ChangeEvent::DeleteVault),
WriteEvent::SetVaultName(name) => {
Ok(ChangeEvent::SetVaultName(name.to_string()))
}
WriteEvent::SetVaultMeta(_) => Ok(ChangeEvent::SetVaultMeta),
WriteEvent::CreateSecret(secret_id, _) => {
Ok(ChangeEvent::CreateSecret(*secret_id))
}
WriteEvent::UpdateSecret(secret_id, _) => {
Ok(ChangeEvent::UpdateSecret(*secret_id))
}
WriteEvent::DeleteSecret(secret_id) => {
Ok(ChangeEvent::DeleteSecret(*secret_id))
}
_ => Err(Error::NoChangeEvent),
}
}
}
/// Action corresponding to a change event.
#[derive(Debug, Hash, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ChangeAction {
/// Pull updates from a remote node.
Pull(VaultId),
/// Vaults was created on a remote node and the
/// local node has fetched the vault summary
/// and added it to it's local state.
Create(Summary),
/// Vault was removed on a remote node and
/// the local node has removed it from it's
/// local cache.
///
/// UI implementations should close an open
/// vault if the removed vault is open and
/// update the list of vaults.
Remove(VaultId),
}