mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-12-25 15:29:32 -05:00
getvalue
This commit is contained in:
parent
76b8d569dc
commit
43a2c0b699
@ -20,9 +20,8 @@ impl StorageManager {
|
|||||||
rpc_processor: RPCProcessor,
|
rpc_processor: RPCProcessor,
|
||||||
key: TypedKey,
|
key: TypedKey,
|
||||||
subkey: ValueSubkey,
|
subkey: ValueSubkey,
|
||||||
last_value: Option<SignedValueData>,
|
|
||||||
last_descriptor: Option<SignedValueDescriptor>,
|
|
||||||
safety_selection: SafetySelection,
|
safety_selection: SafetySelection,
|
||||||
|
last_subkey_result: SubkeyResult,
|
||||||
) -> Result<SubkeyResult, VeilidAPIError> {
|
) -> Result<SubkeyResult, VeilidAPIError> {
|
||||||
let routing_table = rpc_processor.routing_table();
|
let routing_table = rpc_processor.routing_table();
|
||||||
|
|
||||||
@ -38,15 +37,15 @@ impl StorageManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Make do-get-value answer context
|
// Make do-get-value answer context
|
||||||
let schema = if let Some(d) = &last_descriptor {
|
let schema = if let Some(d) = &last_subkey_result.descriptor {
|
||||||
Some(d.schema()?)
|
Some(d.schema()?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let context = Arc::new(Mutex::new(DoGetValueContext {
|
let context = Arc::new(Mutex::new(DoGetValueContext {
|
||||||
value: last_value,
|
value: last_subkey_result.value,
|
||||||
value_count: 0,
|
value_count: 0,
|
||||||
descriptor: last_descriptor.clone(),
|
descriptor: last_subkey_result.descriptor.clone(),
|
||||||
schema,
|
schema,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -54,7 +53,7 @@ impl StorageManager {
|
|||||||
let call_routine = |next_node: NodeRef| {
|
let call_routine = |next_node: NodeRef| {
|
||||||
let rpc_processor = rpc_processor.clone();
|
let rpc_processor = rpc_processor.clone();
|
||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
let last_descriptor = last_descriptor.clone();
|
let last_descriptor = last_subkey_result.descriptor.clone();
|
||||||
async move {
|
async move {
|
||||||
let vres = rpc_processor
|
let vres = rpc_processor
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -57,8 +57,8 @@ impl StorageManager {
|
|||||||
flush_record_stores_task: TickTask::new(FLUSH_RECORD_STORES_INTERVAL_SECS),
|
flush_record_stores_task: TickTask::new(FLUSH_RECORD_STORES_INTERVAL_SECS),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn new_inner() -> StorageManagerInner {
|
fn new_inner(unlocked_inner: Arc<StorageManagerUnlockedInner>) -> StorageManagerInner {
|
||||||
StorageManagerInner::default()
|
StorageManagerInner::new(unlocked_inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_limits_from_config(config: VeilidConfig) -> RecordStoreLimits {
|
fn local_limits_from_config(config: VeilidConfig) -> RecordStoreLimits {
|
||||||
@ -96,15 +96,16 @@ impl StorageManager {
|
|||||||
table_store: TableStore,
|
table_store: TableStore,
|
||||||
block_store: BlockStore,
|
block_store: BlockStore,
|
||||||
) -> StorageManager {
|
) -> StorageManager {
|
||||||
|
let unlocked_inner = Arc::new(Self::new_unlocked_inner(
|
||||||
|
config,
|
||||||
|
crypto,
|
||||||
|
protected_store,
|
||||||
|
table_store,
|
||||||
|
block_store,
|
||||||
|
));
|
||||||
let this = StorageManager {
|
let this = StorageManager {
|
||||||
unlocked_inner: Arc::new(Self::new_unlocked_inner(
|
unlocked_inner: unlocked_inner.clone(),
|
||||||
config,
|
inner: Arc::new(AsyncMutex::new(Self::new_inner(unlocked_inner))),
|
||||||
crypto,
|
|
||||||
protected_store,
|
|
||||||
table_store,
|
|
||||||
block_store,
|
|
||||||
)),
|
|
||||||
inner: Arc::new(AsyncMutex::new(Self::new_inner())),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setup_tasks();
|
this.setup_tasks();
|
||||||
@ -169,7 +170,7 @@ impl StorageManager {
|
|||||||
self.cancel_tasks().await;
|
self.cancel_tasks().await;
|
||||||
|
|
||||||
// Release the storage manager
|
// Release the storage manager
|
||||||
*inner = Self::new_inner();
|
*inner = Self::new_inner(self.unlocked_inner.clone());
|
||||||
|
|
||||||
debug!("finished storage manager shutdown");
|
debug!("finished storage manager shutdown");
|
||||||
}
|
}
|
||||||
@ -179,22 +180,6 @@ impl StorageManager {
|
|||||||
inner.rpc_processor = opt_rpc_processor
|
inner.rpc_processor = opt_rpc_processor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ]
|
|
||||||
fn get_key<D>(vcrypto: CryptoSystemVersion, record: &Record<D>) -> TypedKey
|
|
||||||
where
|
|
||||||
D: Clone + RkyvArchive + RkyvSerialize<RkyvSerializer>,
|
|
||||||
for<'t> <D as RkyvArchive>::Archived: CheckBytes<RkyvDefaultValidator<'t>>,
|
|
||||||
<D as RkyvArchive>::Archived: RkyvDeserialize<D, SharedDeserializeMap>,
|
|
||||||
{
|
|
||||||
let compiled = record.descriptor().schema_data();
|
|
||||||
let mut hash_data = Vec::<u8>::with_capacity(PUBLIC_KEY_LENGTH + 4 + compiled.len());
|
|
||||||
hash_data.extend_from_slice(&vcrypto.kind().0);
|
|
||||||
hash_data.extend_from_slice(&record.owner().bytes);
|
|
||||||
hash_data.extend_from_slice(compiled);
|
|
||||||
let hash = vcrypto.generate_hash(&hash_data);
|
|
||||||
TypedKey::new(vcrypto.kind(), hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn lock(&self) -> Result<AsyncMutexGuardArc<StorageManagerInner>, VeilidAPIError> {
|
async fn lock(&self) -> Result<AsyncMutexGuardArc<StorageManagerInner>, VeilidAPIError> {
|
||||||
let inner = asyncmutex_lock_arc!(&self.inner);
|
let inner = asyncmutex_lock_arc!(&self.inner);
|
||||||
if !inner.initialized {
|
if !inner.initialized {
|
||||||
@ -203,6 +188,7 @@ impl StorageManager {
|
|||||||
Ok(inner)
|
Ok(inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a local record from scratch with a new owner key, open it, and return the opened descriptor
|
||||||
pub async fn create_record(
|
pub async fn create_record(
|
||||||
&self,
|
&self,
|
||||||
kind: CryptoKind,
|
kind: CryptoKind,
|
||||||
@ -211,59 +197,32 @@ impl StorageManager {
|
|||||||
) -> Result<DHTRecordDescriptor, VeilidAPIError> {
|
) -> Result<DHTRecordDescriptor, VeilidAPIError> {
|
||||||
let mut inner = self.lock().await?;
|
let mut inner = self.lock().await?;
|
||||||
|
|
||||||
// Get cryptosystem
|
// Create a new owned local record from scratch
|
||||||
let Some(vcrypto) = self.unlocked_inner.crypto.get(kind) else {
|
let (key, owner) = inner
|
||||||
apibail_generic!("unsupported cryptosystem");
|
.create_new_owned_local_record(kind, schema, safety_selection)
|
||||||
};
|
.await?;
|
||||||
|
|
||||||
// Get local record store
|
// Now that the record is made we should always succeed to open the existing record
|
||||||
let Some(local_record_store) = inner.local_record_store.as_mut() else {
|
// The initial writer is the owner of the record
|
||||||
apibail_not_initialized!();
|
inner
|
||||||
};
|
.open_existing_record(key, Some(owner), safety_selection)
|
||||||
|
.map(|r| r.unwrap())
|
||||||
// Compile the dht schema
|
|
||||||
let schema_data = schema.compile();
|
|
||||||
|
|
||||||
// New values require a new owner key
|
|
||||||
let owner = vcrypto.generate_keypair();
|
|
||||||
|
|
||||||
// Make a signed value descriptor for this dht value
|
|
||||||
let signed_value_descriptor = SignedValueDescriptor::make_signature(
|
|
||||||
owner.key,
|
|
||||||
schema_data,
|
|
||||||
vcrypto.clone(),
|
|
||||||
owner.secret,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Add new local value record
|
|
||||||
let cur_ts = get_aligned_timestamp();
|
|
||||||
let local_record_detail = LocalRecordDetail { safety_selection };
|
|
||||||
let record =
|
|
||||||
Record::<LocalRecordDetail>::new(cur_ts, signed_value_descriptor, local_record_detail)?;
|
|
||||||
|
|
||||||
let dht_key = Self::get_key(vcrypto.clone(), &record);
|
|
||||||
local_record_store.new_record(dht_key, record).await?;
|
|
||||||
|
|
||||||
// Open the record
|
|
||||||
self.open_record_common(inner, dht_key, Some(owner), safety_selection)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn open_record_common(
|
/// Open an existing local record if it exists,
|
||||||
|
/// and if it doesnt exist locally, try to pull it from the network and
|
||||||
|
/// open it and return the opened descriptor
|
||||||
|
pub async fn open_record(
|
||||||
&self,
|
&self,
|
||||||
mut inner: AsyncMutexGuardArc<StorageManagerInner>,
|
|
||||||
key: TypedKey,
|
key: TypedKey,
|
||||||
writer: Option<KeyPair>,
|
writer: Option<KeyPair>,
|
||||||
safety_selection: SafetySelection,
|
safety_selection: SafetySelection,
|
||||||
) -> Result<DHTRecordDescriptor, VeilidAPIError> {
|
) -> Result<DHTRecordDescriptor, VeilidAPIError> {
|
||||||
// Ensure the record is closed
|
let mut inner = self.lock().await?;
|
||||||
if inner.opened_records.contains_key(&key) {
|
|
||||||
apibail_generic!("record is already open and should be closed first");
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if we have a local record already or not
|
// See if we have a local record already or not
|
||||||
if let Some(res) = inner.open_record_check_existing(key, writer, safety_selection) {
|
if let Some(res) = inner.open_existing_record(key, writer, safety_selection)? {
|
||||||
return res;
|
return Ok(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No record yet, try to get it from the network
|
// No record yet, try to get it from the network
|
||||||
@ -280,86 +239,38 @@ impl StorageManager {
|
|||||||
// No last descriptor, no last value
|
// No last descriptor, no last value
|
||||||
// Use the safety selection we opened the record with
|
// Use the safety selection we opened the record with
|
||||||
let subkey: ValueSubkey = 0;
|
let subkey: ValueSubkey = 0;
|
||||||
let result = self
|
let subkey_result = self
|
||||||
.do_get_value(rpc_processor, key, subkey, None, None, safety_selection)
|
.do_get_value(
|
||||||
|
rpc_processor,
|
||||||
|
key,
|
||||||
|
subkey,
|
||||||
|
safety_selection,
|
||||||
|
SubkeyResult::default(),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// If we got nothing back, the key wasn't found
|
// If we got nothing back, the key wasn't found
|
||||||
if result.value.is_none() && result.descriptor.is_none() {
|
if subkey_result.value.is_none() && subkey_result.descriptor.is_none() {
|
||||||
// No result
|
// No result
|
||||||
apibail_key_not_found!(key);
|
apibail_key_not_found!(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Must have descriptor
|
|
||||||
let Some(signed_value_descriptor) = result.descriptor else {
|
|
||||||
// No descriptor for new record, can't store this
|
|
||||||
apibail_generic!("no descriptor");
|
|
||||||
};
|
|
||||||
|
|
||||||
let owner = signed_value_descriptor.owner().clone();
|
|
||||||
// If the writer we chose is also the owner, we have the owner secret
|
|
||||||
// Otherwise this is just another subkey writer
|
|
||||||
let owner_secret = if let Some(writer) = writer {
|
|
||||||
if writer.key == owner {
|
|
||||||
Some(writer.secret)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let schema = signed_value_descriptor.schema()?;
|
|
||||||
|
|
||||||
// Reopen inner to store value we just got
|
// Reopen inner to store value we just got
|
||||||
let mut inner = self.lock().await?;
|
let mut inner = self.lock().await?;
|
||||||
|
|
||||||
// Get local record store
|
// Open the new record
|
||||||
let Some(local_record_store) = inner.local_record_store.as_mut() else {
|
|
||||||
apibail_not_initialized!();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make and store a new record for this descriptor
|
|
||||||
let record = Record::<LocalRecordDetail>::new(
|
|
||||||
get_aligned_timestamp(),
|
|
||||||
signed_value_descriptor,
|
|
||||||
LocalRecordDetail { safety_selection },
|
|
||||||
)?;
|
|
||||||
local_record_store.new_record(key, record).await?;
|
|
||||||
|
|
||||||
// If we got a subkey with the getvalue, it has already been validated against the schema, so store it
|
|
||||||
if let Some(signed_value_data) = result.value {
|
|
||||||
// Write subkey to local store
|
|
||||||
local_record_store
|
|
||||||
.set_subkey(key, subkey, signed_value_data)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write open record
|
|
||||||
inner
|
inner
|
||||||
.opened_records
|
.open_new_record(key, writer, subkey, subkey_result, safety_selection)
|
||||||
.insert(key, OpenedRecord::new(writer, safety_selection));
|
|
||||||
|
|
||||||
// Make DHT Record Descriptor to return
|
|
||||||
let descriptor = DHTRecordDescriptor::new(key, owner, owner_secret, schema);
|
|
||||||
Ok(descriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn open_record(
|
|
||||||
&self,
|
|
||||||
key: TypedKey,
|
|
||||||
writer: Option<KeyPair>,
|
|
||||||
safety_selection: SafetySelection,
|
|
||||||
) -> Result<DHTRecordDescriptor, VeilidAPIError> {
|
|
||||||
let inner = self.lock().await?;
|
|
||||||
self.open_record_common(inner, key, writer, safety_selection)
|
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Close an opened local record
|
||||||
pub async fn close_record(&self, key: TypedKey) -> Result<(), VeilidAPIError> {
|
pub async fn close_record(&self, key: TypedKey) -> Result<(), VeilidAPIError> {
|
||||||
let mut inner = self.lock().await?;
|
let mut inner = self.lock().await?;
|
||||||
inner.close_record(key)
|
inner.close_record(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Delete a local record
|
||||||
pub async fn delete_record(&self, key: TypedKey) -> Result<(), VeilidAPIError> {
|
pub async fn delete_record(&self, key: TypedKey) -> Result<(), VeilidAPIError> {
|
||||||
let mut inner = self.lock().await?;
|
let mut inner = self.lock().await?;
|
||||||
|
|
||||||
@ -376,6 +287,8 @@ impl StorageManager {
|
|||||||
local_record_store.delete_record(key).await
|
local_record_store.delete_record(key).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the value of a subkey from an opened local record
|
||||||
|
/// may refresh the record, and will if it is forced to or the subkey is not available locally yet
|
||||||
pub async fn get_value(
|
pub async fn get_value(
|
||||||
&self,
|
&self,
|
||||||
key: TypedKey,
|
key: TypedKey,
|
||||||
@ -383,23 +296,23 @@ impl StorageManager {
|
|||||||
force_refresh: bool,
|
force_refresh: bool,
|
||||||
) -> Result<Option<ValueData>, VeilidAPIError> {
|
) -> Result<Option<ValueData>, VeilidAPIError> {
|
||||||
let mut inner = self.lock().await?;
|
let mut inner = self.lock().await?;
|
||||||
|
|
||||||
// Get rpc processor and drop mutex so we don't block while getting the value from the network
|
|
||||||
let Some(opened_record) = inner.opened_records.remove(&key) else {
|
let Some(opened_record) = inner.opened_records.remove(&key) else {
|
||||||
apibail_generic!("record not open");
|
apibail_generic!("record not open");
|
||||||
};
|
};
|
||||||
|
|
||||||
// See if the requested subkey is our local record store
|
// See if the requested subkey is our local record store
|
||||||
let SubkeyResult { value, descriptor } = inner.handle_get_local_value(key, subkey, true)?;
|
let last_subkey_result = inner.handle_get_local_value(key, subkey, true)?;
|
||||||
|
|
||||||
// Return the existing value if we have one unless we are forcing a refresh
|
// Return the existing value if we have one unless we are forcing a refresh
|
||||||
if !force_refresh {
|
if !force_refresh {
|
||||||
if let Some(value) = value {
|
if let Some(last_subkey_result_value) = last_subkey_result.value {
|
||||||
return Ok(Some(value.into_value_data()));
|
return Ok(Some(last_subkey_result_value.into_value_data()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh if we can
|
// Refresh if we can
|
||||||
|
|
||||||
|
// Get rpc processor and drop mutex so we don't block while getting the value from the network
|
||||||
let Some(rpc_processor) = inner.rpc_processor.clone() else {
|
let Some(rpc_processor) = inner.rpc_processor.clone() else {
|
||||||
// Offline, try again later
|
// Offline, try again later
|
||||||
apibail_try_again!();
|
apibail_try_again!();
|
||||||
@ -410,32 +323,34 @@ impl StorageManager {
|
|||||||
|
|
||||||
// May have last descriptor / value
|
// May have last descriptor / value
|
||||||
// Use the safety selection we opened the record with
|
// Use the safety selection we opened the record with
|
||||||
let opt_last_seq = value.as_ref().map(|v| v.value_data().seq());
|
let opt_last_seq = last_subkey_result
|
||||||
let result = self
|
.value
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| v.value_data().seq());
|
||||||
|
let subkey_result = self
|
||||||
.do_get_value(
|
.do_get_value(
|
||||||
rpc_processor,
|
rpc_processor,
|
||||||
key,
|
key,
|
||||||
subkey,
|
subkey,
|
||||||
value,
|
|
||||||
descriptor,
|
|
||||||
opened_record.safety_selection(),
|
opened_record.safety_selection(),
|
||||||
|
last_subkey_result,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// See if we got a value back
|
// See if we got a value back
|
||||||
let Some(result_value) = result.value else {
|
let Some(subkey_result_value) = subkey_result.value else {
|
||||||
// If we got nothing back then we also had nothing beforehand, return nothing
|
// If we got nothing back then we also had nothing beforehand, return nothing
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we got a new value back then write it to the opened record
|
// If we got a new value back then write it to the opened record
|
||||||
if Some(result_value.value_data().seq()) != opt_last_seq {
|
if Some(subkey_result_value.value_data().seq()) != opt_last_seq {
|
||||||
let mut inner = self.lock().await?;
|
let mut inner = self.lock().await?;
|
||||||
inner
|
inner
|
||||||
.handle_set_local_value(key, subkey, result_value.clone())
|
.handle_set_local_value(key, subkey, subkey_result_value.clone())
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
Ok(Some(result_value.into_value_data()))
|
Ok(Some(subkey_result_value.into_value_data()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_value(
|
pub async fn set_value(
|
||||||
|
@ -31,6 +31,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The result of the do_get_value_operation
|
/// The result of the do_get_value_operation
|
||||||
|
#[derive(Default, Debug)]
|
||||||
pub struct SubkeyResult {
|
pub struct SubkeyResult {
|
||||||
/// The subkey value if we got one
|
/// The subkey value if we got one
|
||||||
pub value: Option<SignedValueData>,
|
pub value: Option<SignedValueData>,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Locked structure for storage manager
|
/// Locked structure for storage manager
|
||||||
#[derive(Default)]
|
|
||||||
pub(super) struct StorageManagerInner {
|
pub(super) struct StorageManagerInner {
|
||||||
|
unlocked_inner: Arc<StorageManagerUnlockedInner>,
|
||||||
/// If we are started up
|
/// If we are started up
|
||||||
pub initialized: bool,
|
pub initialized: bool,
|
||||||
/// Records that have been 'opened' and are not yet closed
|
/// Records that have been 'opened' and are not yet closed
|
||||||
@ -18,15 +18,74 @@ pub(super) struct StorageManagerInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StorageManagerInner {
|
impl StorageManagerInner {
|
||||||
pub fn open_record_check_existing(
|
pub fn new(unlocked_inner: Arc<StorageManagerUnlockedInner>) -> Self {
|
||||||
|
Self {
|
||||||
|
unlocked_inner,
|
||||||
|
initialized: false,
|
||||||
|
opened_records: Default::default(),
|
||||||
|
local_record_store: Default::default(),
|
||||||
|
remote_record_store: Default::default(),
|
||||||
|
rpc_processor: Default::default(),
|
||||||
|
tick_future: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_new_owned_local_record(
|
||||||
|
&mut self,
|
||||||
|
kind: CryptoKind,
|
||||||
|
schema: DHTSchema,
|
||||||
|
safety_selection: SafetySelection,
|
||||||
|
) -> Result<(TypedKey, KeyPair), VeilidAPIError> {
|
||||||
|
// Get cryptosystem
|
||||||
|
let Some(vcrypto) = self.unlocked_inner.crypto.get(kind) else {
|
||||||
|
apibail_generic!("unsupported cryptosystem");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get local record store
|
||||||
|
let Some(local_record_store) = self.local_record_store.as_mut() else {
|
||||||
|
apibail_not_initialized!();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compile the dht schema
|
||||||
|
let schema_data = schema.compile();
|
||||||
|
|
||||||
|
// New values require a new owner key
|
||||||
|
let owner = vcrypto.generate_keypair();
|
||||||
|
|
||||||
|
// Make a signed value descriptor for this dht value
|
||||||
|
let signed_value_descriptor = SignedValueDescriptor::make_signature(
|
||||||
|
owner.key,
|
||||||
|
schema_data,
|
||||||
|
vcrypto.clone(),
|
||||||
|
owner.secret,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Add new local value record
|
||||||
|
let cur_ts = get_aligned_timestamp();
|
||||||
|
let local_record_detail = LocalRecordDetail { safety_selection };
|
||||||
|
let record =
|
||||||
|
Record::<LocalRecordDetail>::new(cur_ts, signed_value_descriptor, local_record_detail)?;
|
||||||
|
|
||||||
|
let dht_key = Self::get_key(vcrypto.clone(), &record);
|
||||||
|
local_record_store.new_record(dht_key, record).await?;
|
||||||
|
|
||||||
|
Ok((dht_key, owner))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_existing_record(
|
||||||
&mut self,
|
&mut self,
|
||||||
key: TypedKey,
|
key: TypedKey,
|
||||||
writer: Option<KeyPair>,
|
writer: Option<KeyPair>,
|
||||||
safety_selection: SafetySelection,
|
safety_selection: SafetySelection,
|
||||||
) -> Option<Result<DHTRecordDescriptor, VeilidAPIError>> {
|
) -> Result<Option<DHTRecordDescriptor>, VeilidAPIError> {
|
||||||
|
// Ensure the record is closed
|
||||||
|
if self.opened_records.contains_key(&key) {
|
||||||
|
apibail_generic!("record is already open and should be closed first");
|
||||||
|
}
|
||||||
|
|
||||||
// Get local record store
|
// Get local record store
|
||||||
let Some(local_record_store) = self.local_record_store.as_mut() else {
|
let Some(local_record_store) = self.local_record_store.as_mut() else {
|
||||||
return Some(Err(VeilidAPIError::not_initialized()));
|
apibail_not_initialized!();
|
||||||
};
|
};
|
||||||
|
|
||||||
// See if we have a local record already or not
|
// See if we have a local record already or not
|
||||||
@ -40,7 +99,7 @@ impl StorageManagerInner {
|
|||||||
(r.owner().clone(), r.schema())
|
(r.owner().clone(), r.schema())
|
||||||
};
|
};
|
||||||
let Some((owner, schema)) = local_record_store.with_record_mut(key, cb) else {
|
let Some((owner, schema)) = local_record_store.with_record_mut(key, cb) else {
|
||||||
return None;
|
return Ok(None);
|
||||||
};
|
};
|
||||||
// Had local record
|
// Had local record
|
||||||
|
|
||||||
@ -62,17 +121,43 @@ impl StorageManagerInner {
|
|||||||
|
|
||||||
// Make DHT Record Descriptor to return
|
// Make DHT Record Descriptor to return
|
||||||
let descriptor = DHTRecordDescriptor::new(key, owner, owner_secret, schema);
|
let descriptor = DHTRecordDescriptor::new(key, owner, owner_secret, schema);
|
||||||
Some(Ok(descriptor))
|
Ok(Some(descriptor))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_local_record(
|
pub async fn open_new_record(
|
||||||
&mut self,
|
&mut self,
|
||||||
key: TypedKey,
|
key: TypedKey,
|
||||||
|
writer: Option<KeyPair>,
|
||||||
subkey: ValueSubkey,
|
subkey: ValueSubkey,
|
||||||
signed_value_descriptor: SignedValueDescriptor,
|
subkey_result: SubkeyResult,
|
||||||
signed_value_data: Option<SignedValueData>,
|
|
||||||
safety_selection: SafetySelection,
|
safety_selection: SafetySelection,
|
||||||
) -> Result<(), VeilidAPIError> {
|
) -> Result<DHTRecordDescriptor, VeilidAPIError> {
|
||||||
|
// Ensure the record is closed
|
||||||
|
if self.opened_records.contains_key(&key) {
|
||||||
|
panic!("new record should never be opened at this point");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must have descriptor
|
||||||
|
let Some(signed_value_descriptor) = subkey_result.descriptor else {
|
||||||
|
// No descriptor for new record, can't store this
|
||||||
|
apibail_generic!("no descriptor");
|
||||||
|
};
|
||||||
|
// Get owner
|
||||||
|
let owner = signed_value_descriptor.owner().clone();
|
||||||
|
|
||||||
|
// If the writer we chose is also the owner, we have the owner secret
|
||||||
|
// Otherwise this is just another subkey writer
|
||||||
|
let owner_secret = if let Some(writer) = writer {
|
||||||
|
if writer.key == owner {
|
||||||
|
Some(writer.secret)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let schema = signed_value_descriptor.schema()?;
|
||||||
|
|
||||||
// Get local record store
|
// Get local record store
|
||||||
let Some(local_record_store) = self.local_record_store.as_mut() else {
|
let Some(local_record_store) = self.local_record_store.as_mut() else {
|
||||||
apibail_not_initialized!();
|
apibail_not_initialized!();
|
||||||
@ -87,17 +172,20 @@ impl StorageManagerInner {
|
|||||||
local_record_store.new_record(key, record).await?;
|
local_record_store.new_record(key, record).await?;
|
||||||
|
|
||||||
// If we got a subkey with the getvalue, it has already been validated against the schema, so store it
|
// If we got a subkey with the getvalue, it has already been validated against the schema, so store it
|
||||||
if let Some(signed_value_data) = signed_value_data {
|
if let Some(signed_value_data) = subkey_result.value {
|
||||||
// Write subkey to local store
|
// Write subkey to local store
|
||||||
local_record_store
|
local_record_store
|
||||||
.set_subkey(key, subkey, signed_value_data)
|
.set_subkey(key, subkey, signed_value_data)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write open record
|
// Write open record
|
||||||
self.opened_records
|
self.opened_records
|
||||||
.insert(key, OpenedRecord::new(writer, safety_selection));
|
.insert(key, OpenedRecord::new(writer, safety_selection));
|
||||||
|
|
||||||
Ok(())
|
// Make DHT Record Descriptor to return
|
||||||
|
let descriptor = DHTRecordDescriptor::new(key, owner, owner_secret, schema);
|
||||||
|
Ok(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_record(&mut self, key: TypedKey) -> Result<(), VeilidAPIError> {
|
pub fn close_record(&mut self, key: TypedKey) -> Result<(), VeilidAPIError> {
|
||||||
@ -184,4 +272,20 @@ impl StorageManagerInner {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ]
|
||||||
|
fn get_key<D>(vcrypto: CryptoSystemVersion, record: &Record<D>) -> TypedKey
|
||||||
|
where
|
||||||
|
D: Clone + RkyvArchive + RkyvSerialize<RkyvSerializer>,
|
||||||
|
for<'t> <D as RkyvArchive>::Archived: CheckBytes<RkyvDefaultValidator<'t>>,
|
||||||
|
<D as RkyvArchive>::Archived: RkyvDeserialize<D, SharedDeserializeMap>,
|
||||||
|
{
|
||||||
|
let compiled = record.descriptor().schema_data();
|
||||||
|
let mut hash_data = Vec::<u8>::with_capacity(PUBLIC_KEY_LENGTH + 4 + compiled.len());
|
||||||
|
hash_data.extend_from_slice(&vcrypto.kind().0);
|
||||||
|
hash_data.extend_from_slice(&record.owner().bytes);
|
||||||
|
hash_data.extend_from_slice(compiled);
|
||||||
|
let hash = vcrypto.generate_hash(&hash_data);
|
||||||
|
TypedKey::new(vcrypto.kind(), hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user