add inspect to python api

This commit is contained in:
Christien Rioux 2024-03-13 22:34:44 -04:00
parent 1e681790e6
commit cfce0a35b4
10 changed files with 303 additions and 1 deletions

View File

@ -390,6 +390,15 @@ impl RoutingTable {
for b in &c.network.routing_table.bootstrap { for b in &c.network.routing_table.bootstrap {
cache_validity_key.append(&mut b.as_bytes().to_vec()); cache_validity_key.append(&mut b.as_bytes().to_vec());
} }
cache_validity_key.append(
&mut c
.network
.network_key_password
.clone()
.unwrap_or_default()
.as_bytes()
.to_vec(),
);
}; };
// Deserialize bucket map and all entries from the table store // Deserialize bucket map and all entries from the table store

View File

@ -354,6 +354,18 @@ impl JsonRequestProcessor {
), ),
} }
} }
RoutingContextRequestOp::InspectDhtRecord {
key,
subkeys,
scope,
} => RoutingContextResponseOp::InspectDhtRecord {
result: to_json_api_result(
routing_context
.inspect_dht_record(key, subkeys, scope)
.await
.map(Box::new),
),
},
}; };
RoutingContextResponse { RoutingContextResponse {
rc_id: rcr.rc_id, rc_id: rcr.rc_id,

View File

@ -85,7 +85,14 @@ pub enum RoutingContextRequestOp {
key: TypedKey, key: TypedKey,
subkeys: ValueSubkeyRangeSet, subkeys: ValueSubkeyRangeSet,
}, },
InspectDhtRecord {
#[schemars(with = "String")]
key: TypedKey,
subkeys: ValueSubkeyRangeSet,
scope: DHTReportScope,
},
} }
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "rc_op")] #[serde(tag = "rc_op")]
pub enum RoutingContextResponseOp { pub enum RoutingContextResponseOp {
@ -146,4 +153,8 @@ pub enum RoutingContextResponseOp {
#[serde(flatten)] #[serde(flatten)]
result: ApiResult<bool>, result: ApiResult<bool>,
}, },
InspectDhtRecord {
#[serde(flatten)]
result: ApiResult<Box<DHTRecordReport>>,
},
} }

View File

@ -202,3 +202,28 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
# Clean up # Clean up
await rc.close_dht_record(key) await rc.close_dht_record(key)
await rc.delete_dht_record(key) await rc.delete_dht_record(key)
@pytest.mark.asyncio
async def test_inspect_dht_record(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context()
async with rc:
rec = await rc.create_dht_record(veilid.DHTSchema.dflt(2))
vd = await rc.set_dht_value(rec.key, 0, b"BLAH BLAH BLAH")
assert vd == None
rr = await rc.inspect_dht_record(rec.key, [], veilid.DHTReportScope.LOCAL)
print("rr: {}", rr.__dict__)
assert rr.subkeys == [[0,1]]
assert rr.local_seqs == [0, 0xFFFFFFFF]
assert rr.network_seqs == []
rr2 = await rc.inspect_dht_record(rec.key, [], veilid.DHTReportScope.SYNC_GET)
print("rr2: {}", rr2.__dict__)
assert rr2.subkeys == [[0,1]]
assert rr2.local_seqs == [0, 0xFFFFFFFF]
assert rr2.network_seqs == [0, 0xFFFFFFFF]
await rc.close_dht_record(rec.key)
await rc.delete_dht_record(rec.key)

View File

@ -97,6 +97,16 @@ class RoutingContext(ABC):
) -> bool: ) -> bool:
pass pass
@abstractmethod
async def inspect_dht_record(
self,
key: types.TypedKey,
subkeys: list[tuple[types.ValueSubkey, types.ValueSubkey]],
scope: types.DHTReportScope,
) -> types.DHTRecordReport:
pass
class TableDbTransaction(ABC): class TableDbTransaction(ABC):
async def __aenter__(self) -> Self: async def __aenter__(self) -> Self:

View File

@ -23,6 +23,8 @@ from .types import (
CryptoKeyDistance, CryptoKeyDistance,
CryptoKind, CryptoKind,
DHTRecordDescriptor, DHTRecordDescriptor,
DHTRecordReport,
DHTReportScope,
DHTSchema, DHTSchema,
HashDigest, HashDigest,
KeyPair, KeyPair,
@ -681,6 +683,28 @@ class _JsonRoutingContext(RoutingContext):
) )
) )
async def inspect_dht_record(
self,
key: TypedKey,
subkeys: list[tuple[ValueSubkey, ValueSubkey]],
scope: DHTReportScope,
) -> DHTRecordReport:
return DHTRecordReport.from_json(
raise_api_result(
await self.api.send_ndjson_request(
Operation.ROUTING_CONTEXT,
validate=validate_rc_op,
rc_id=self.rc_id,
rc_op=RoutingContextOperation.INSPECT_DHT_RECORD,
key=key,
subkeys=subkeys,
scope=scope,
)
)
)
###################################################### ######################################################

View File

@ -48,6 +48,7 @@ class RoutingContextOperation(StrEnum):
SET_DHT_VALUE = "SetDhtValue" SET_DHT_VALUE = "SetDhtValue"
WATCH_DHT_VALUES = "WatchDhtValues" WATCH_DHT_VALUES = "WatchDhtValues"
CANCEL_DHT_WATCH = "CancelDhtWatch" CANCEL_DHT_WATCH = "CancelDhtWatch"
INSPECT_DHT_RECORD = "InspectDhtRecord"
class TableDbOperation(StrEnum): class TableDbOperation(StrEnum):

View File

@ -923,6 +923,44 @@
] ]
} }
} }
},
{
"type": "object",
"anyOf": [
{
"type": "object",
"required": [
"value"
],
"properties": {
"value": {
"$ref": "#/definitions/DHTRecordReport"
}
}
},
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"$ref": "#/definitions/VeilidAPIError"
}
}
}
],
"required": [
"rc_op"
],
"properties": {
"rc_op": {
"type": "string",
"enum": [
"InspectDhtRecord"
]
}
}
} }
], ],
"required": [ "required": [
@ -2717,6 +2755,56 @@
} }
} }
}, },
"DHTRecordReport": {
"description": "DHT Record Report",
"type": "object",
"required": [
"local_seqs",
"network_seqs",
"subkeys"
],
"properties": {
"local_seqs": {
"description": "The sequence numbers of each subkey requested from a locally stored DHT Record",
"type": "array",
"items": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"network_seqs": {
"description": "The sequence numbers of each subkey requested from the DHT over the network",
"type": "array",
"items": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"subkeys": {
"description": "The actual subkey range within the schema being reported on This may be a subset of the requested range if it exceeds the schema limits or has more than 512 subkeys",
"type": "array",
"items": {
"type": "array",
"items": [
{
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
{
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
],
"maxItems": 2,
"minItems": 2
}
}
}
},
"DHTSchema": { "DHTSchema": {
"description": "Enum over all the supported DHT Schemas", "description": "Enum over all the supported DHT Schemas",
"oneOf": [ "oneOf": [

View File

@ -547,6 +547,49 @@
} }
} }
} }
},
{
"type": "object",
"required": [
"key",
"rc_op",
"scope",
"subkeys"
],
"properties": {
"key": {
"type": "string"
},
"rc_op": {
"type": "string",
"enum": [
"InspectDhtRecord"
]
},
"scope": {
"$ref": "#/definitions/DHTReportScope"
},
"subkeys": {
"type": "array",
"items": {
"type": "array",
"items": [
{
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
{
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
],
"maxItems": 2,
"minItems": 2
}
}
}
} }
], ],
"required": [ "required": [
@ -1525,6 +1568,46 @@
} }
}, },
"definitions": { "definitions": {
"DHTReportScope": {
"description": "DHT Record Report Scope",
"oneOf": [
{
"description": "Return only the local copy sequence numbers Useful for seeing what subkeys you have locally and which ones have not been retrieved",
"type": "string",
"enum": [
"Local"
]
},
{
"description": "Return the local sequence numbers and the network sequence numbers with GetValue fanout parameters Provides an independent view of both the local sequence numbers and the network sequence numbers for nodes that would be reached as if the local copy did not exist locally. Useful for determining if the current local copy should be updated from the network.",
"type": "string",
"enum": [
"SyncGet"
]
},
{
"description": "Return the local sequence numbers and the network sequence numbers with SetValue fanout parameters Provides an independent view of both the local sequence numbers and the network sequence numbers for nodes that would be reached as if the local copy did not exist locally. Useful for determining if the unchanged local copy should be pushed to the network.",
"type": "string",
"enum": [
"SyncSet"
]
},
{
"description": "Return the local sequence numbers and the network sequence numbers with GetValue fanout parameters Provides an view of both the local sequence numbers and the network sequence numbers for nodes that would be reached as if a GetValue operation were being performed, including accepting newer values from the network. Useful for determining which subkeys would change with a GetValue operation",
"type": "string",
"enum": [
"UpdateGet"
]
},
{
"description": "Return the local sequence numbers and the network sequence numbers with SetValue fanout parameters Provides an view of both the local sequence numbers and the network sequence numbers for nodes that would be reached as if a SetValue operation were being performed, including accepting newer values from the network. This simulates a SetValue with the initial sequence number incremented by 1, like a real SetValue would when updating. Useful for determine which subkeys would change on an SetValue operation",
"type": "string",
"enum": [
"UpdateSet"
]
}
]
},
"DHTSchema": { "DHTSchema": {
"description": "Enum over all the supported DHT Schemas", "description": "Enum over all the supported DHT Schemas",
"oneOf": [ "oneOf": [

View File

@ -85,6 +85,14 @@ class SafetySelectionKind(StrEnum):
SAFE = "Safe" SAFE = "Safe"
class DHTReportScope(StrEnum):
LOCAL = "Local"
SYNC_GET = "SyncGet"
SYNC_SET = "SyncSet"
UPDATE_GET = "UpdateGet"
UPDATE_SET = "UpdateSet"
#################################################################### ####################################################################
@ -353,7 +361,7 @@ class DHTRecordDescriptor:
self.schema = schema self.schema = schema
def __repr__(self) -> str: def __repr__(self) -> str:
return f"<{self.__class__.__name__}(key={self.key!r})>" return f"<{self.__class__.__name__}(key={self.key!r}, owner={self.owner!r}, owner_secret={self.owner_secret!r}, schema={self.schema!r})>"
@classmethod @classmethod
def from_json(cls, j: dict) -> Self: def from_json(cls, j: dict) -> Self:
@ -368,6 +376,37 @@ class DHTRecordDescriptor:
return self.__dict__ return self.__dict__
class DHTRecordReport:
subkeys: list[tuple[ValueSubkey, ValueSubkey]]
local_seqs: list[ValueSeqNum]
network_seqs: list[ValueSeqNum]
def __init__(
self,
subkeys: list[tuple[ValueSubkey, ValueSubkey]],
local_seqs: list[ValueSeqNum],
network_seqs: list[ValueSeqNum],
):
self.subkeys = subkeys
self.local_seqs = local_seqs
self.network_seqs = network_seqs
def __repr__(self) -> str:
return f"<{self.__class__.__name__}(subkeys={self.subkeys!r}, local_seqs={self.local_seqs!r}, network_seqs={self.network_seqs!r})>"
@classmethod
def from_json(cls, j: dict) -> Self:
return cls(
[[p[0], p[1]] for p in j["subkeys"]],
[ValueSeqNum(s) for s in j["local_seqs"]],
[ValueSeqNum(s) for s in j["network_seqs"]],
)
def to_json(self) -> dict:
return self.__dict__
@total_ordering @total_ordering
class ValueData: class ValueData:
seq: ValueSeqNum seq: ValueSeqNum