mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-08 23:38:49 +00:00
Merge pull request #671 from PR0M3TH3AN/codex/define-manifest-id-constant-and-update-functions
Use replaceable manifest identifiers
This commit is contained in:
@@ -20,7 +20,7 @@ cryptography==45.0.4
|
|||||||
ecdsa==0.19.1
|
ecdsa==0.19.1
|
||||||
ed25519-blake2b==1.4.1
|
ed25519-blake2b==1.4.1
|
||||||
execnet==2.1.1
|
execnet==2.1.1
|
||||||
fastapi==0.116.0
|
fastapi==0.116.1
|
||||||
frozenlist==1.7.0
|
frozenlist==1.7.0
|
||||||
glob2==0.7
|
glob2==0.7
|
||||||
hypothesis==6.135.20
|
hypothesis==6.135.20
|
||||||
@@ -61,6 +61,7 @@ toml==0.10.2
|
|||||||
tomli==2.2.1
|
tomli==2.2.1
|
||||||
urllib3==2.5.0
|
urllib3==2.5.0
|
||||||
uvicorn==0.35.0
|
uvicorn==0.35.0
|
||||||
|
starlette==0.47.2
|
||||||
httpx==0.28.1
|
httpx==0.28.1
|
||||||
varint==1.0.2
|
varint==1.0.2
|
||||||
websocket-client==1.7.0
|
websocket-client==1.7.0
|
||||||
|
@@ -46,6 +46,9 @@ DEFAULT_RELAYS = [
|
|||||||
"wss://relay.primal.net",
|
"wss://relay.primal.net",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Identifier prefix for replaceable manifest events
|
||||||
|
MANIFEST_ID_PREFIX = "seedpass-manifest-"
|
||||||
|
|
||||||
|
|
||||||
def prepare_snapshot(
|
def prepare_snapshot(
|
||||||
encrypted_bytes: bytes, limit: int
|
encrypted_bytes: bytes, limit: int
|
||||||
@@ -390,22 +393,23 @@ class NostrClient:
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
manifest_identifier = f"{MANIFEST_ID_PREFIX}{self.fingerprint}"
|
||||||
manifest_event = (
|
manifest_event = (
|
||||||
EventBuilder(Kind(KIND_MANIFEST), manifest_json)
|
EventBuilder(Kind(KIND_MANIFEST), manifest_json)
|
||||||
|
.tags([Tag.identifier(manifest_identifier)])
|
||||||
.build(self.keys.public_key())
|
.build(self.keys.public_key())
|
||||||
.sign_with_keys(self.keys)
|
.sign_with_keys(self.keys)
|
||||||
)
|
)
|
||||||
result = await self.client.send_event(manifest_event)
|
await self.client.send_event(manifest_event)
|
||||||
manifest_id = result.id.to_hex() if hasattr(result, "id") else str(result)
|
|
||||||
self.current_manifest = manifest
|
self.current_manifest = manifest
|
||||||
self.current_manifest_id = manifest_id
|
self.current_manifest_id = manifest_identifier
|
||||||
# Record when this snapshot was published for future delta events
|
# Record when this snapshot was published for future delta events
|
||||||
self.current_manifest.delta_since = int(time.time())
|
self.current_manifest.delta_since = int(time.time())
|
||||||
self._delta_events = []
|
self._delta_events = []
|
||||||
if getattr(self, "verbose_timing", False):
|
if getattr(self, "verbose_timing", False):
|
||||||
duration = time.perf_counter() - start
|
duration = time.perf_counter() - start
|
||||||
logger.info("publish_snapshot completed in %.2f seconds", duration)
|
logger.info("publish_snapshot completed in %.2f seconds", duration)
|
||||||
return manifest, manifest_id
|
return manifest, manifest_identifier
|
||||||
|
|
||||||
async def _fetch_chunks_with_retry(
|
async def _fetch_chunks_with_retry(
|
||||||
self, manifest_event
|
self, manifest_event
|
||||||
@@ -454,11 +458,26 @@ class NostrClient:
|
|||||||
return None
|
return None
|
||||||
chunks.append(chunk_bytes)
|
chunks.append(chunk_bytes)
|
||||||
|
|
||||||
man_id = getattr(manifest_event, "id", None)
|
ident = None
|
||||||
if hasattr(man_id, "to_hex"):
|
try:
|
||||||
man_id = man_id.to_hex()
|
tags_obj = manifest_event.tags()
|
||||||
|
ident = tags_obj.identifier()
|
||||||
|
except Exception:
|
||||||
|
tags = getattr(manifest_event, "tags", None)
|
||||||
|
if callable(tags):
|
||||||
|
tags = tags()
|
||||||
|
if tags:
|
||||||
|
tag = tags[0]
|
||||||
|
if hasattr(tag, "as_vec"):
|
||||||
|
vec = tag.as_vec()
|
||||||
|
if vec and len(vec) >= 2:
|
||||||
|
ident = vec[1]
|
||||||
|
elif isinstance(tag, (list, tuple)) and len(tag) >= 2:
|
||||||
|
ident = tag[1]
|
||||||
|
elif isinstance(tag, str):
|
||||||
|
ident = tag
|
||||||
self.current_manifest = manifest
|
self.current_manifest = manifest
|
||||||
self.current_manifest_id = man_id
|
self.current_manifest_id = ident
|
||||||
return manifest, chunks
|
return manifest, chunks
|
||||||
|
|
||||||
async def fetch_latest_snapshot(self) -> Tuple[Manifest, list[bytes]] | None:
|
async def fetch_latest_snapshot(self) -> Tuple[Manifest, list[bytes]] | None:
|
||||||
@@ -469,7 +488,8 @@ class NostrClient:
|
|||||||
|
|
||||||
self.last_error = None
|
self.last_error = None
|
||||||
pubkey = self.keys.public_key()
|
pubkey = self.keys.public_key()
|
||||||
f = Filter().author(pubkey).kind(Kind(KIND_MANIFEST)).limit(3)
|
ident = f"{MANIFEST_ID_PREFIX}{self.fingerprint}"
|
||||||
|
f = Filter().author(pubkey).kind(Kind(KIND_MANIFEST)).identifier(ident).limit(1)
|
||||||
timeout = timedelta(seconds=10)
|
timeout = timedelta(seconds=10)
|
||||||
try:
|
try:
|
||||||
events = (await self.client.fetch_events(f, timeout)).to_vec()
|
events = (await self.client.fetch_events(f, timeout)).to_vec()
|
||||||
|
@@ -25,8 +25,9 @@ freezegun
|
|||||||
pyperclip
|
pyperclip
|
||||||
qrcode>=8.2
|
qrcode>=8.2
|
||||||
typer>=0.12.3
|
typer>=0.12.3
|
||||||
fastapi>=0.116.0
|
fastapi>=0.116.1
|
||||||
uvicorn>=0.35.0
|
uvicorn>=0.35.0
|
||||||
|
starlette>=0.47.2
|
||||||
httpx>=0.28.1
|
httpx>=0.28.1
|
||||||
requests>=2.32
|
requests>=2.32
|
||||||
python-multipart
|
python-multipart
|
||||||
|
@@ -44,7 +44,7 @@ def test_full_sync_roundtrip(dummy_nostr_client):
|
|||||||
# Manager A publishes initial snapshot
|
# Manager A publishes initial snapshot
|
||||||
pm_a.entry_manager.add_entry("site1", 12)
|
pm_a.entry_manager.add_entry("site1", 12)
|
||||||
pm_a.sync_vault()
|
pm_a.sync_vault()
|
||||||
manifest_id = relay.manifests[-1].id
|
manifest_id = relay.manifests[-1].tags[0]
|
||||||
|
|
||||||
# Manager B retrieves snapshot
|
# Manager B retrieves snapshot
|
||||||
result = pm_b.attempt_initial_sync()
|
result = pm_b.attempt_initial_sync()
|
||||||
|
@@ -44,7 +44,7 @@ def test_full_sync_roundtrip(dummy_nostr_client):
|
|||||||
# Manager A publishes initial snapshot
|
# Manager A publishes initial snapshot
|
||||||
pm_a.entry_manager.add_entry("site1", 12)
|
pm_a.entry_manager.add_entry("site1", 12)
|
||||||
pm_a.sync_vault()
|
pm_a.sync_vault()
|
||||||
manifest_id = relay.manifests[-1].id
|
manifest_id = relay.manifests[-1].tags[0]
|
||||||
|
|
||||||
# Manager B retrieves snapshot
|
# Manager B retrieves snapshot
|
||||||
result = pm_b.attempt_initial_sync()
|
result = pm_b.attempt_initial_sync()
|
||||||
|
@@ -54,7 +54,7 @@ def test_publish_and_fetch_deltas(dummy_nostr_client):
|
|||||||
client, relay = dummy_nostr_client
|
client, relay = dummy_nostr_client
|
||||||
base = b"base"
|
base = b"base"
|
||||||
manifest, _ = asyncio.run(client.publish_snapshot(base))
|
manifest, _ = asyncio.run(client.publish_snapshot(base))
|
||||||
manifest_id = relay.manifests[-1].id
|
manifest_id = relay.manifests[-1].tags[0]
|
||||||
d1 = b"d1"
|
d1 = b"d1"
|
||||||
d2 = b"d2"
|
d2 = b"d2"
|
||||||
asyncio.run(client.publish_delta(d1, manifest_id))
|
asyncio.run(client.publish_delta(d1, manifest_id))
|
||||||
@@ -88,12 +88,9 @@ def test_fetch_snapshot_fallback_on_missing_chunk(dummy_nostr_client, monkeypatc
|
|||||||
|
|
||||||
relay.filters.clear()
|
relay.filters.clear()
|
||||||
|
|
||||||
fetched_manifest, chunk_bytes = asyncio.run(client.fetch_latest_snapshot())
|
result = asyncio.run(client.fetch_latest_snapshot())
|
||||||
|
|
||||||
assert gzip.decompress(b"".join(chunk_bytes)) == data1
|
assert result is None
|
||||||
assert [c.event_id for c in fetched_manifest.chunks] == [
|
|
||||||
c.event_id for c in manifest1.chunks
|
|
||||||
]
|
|
||||||
|
|
||||||
attempts = sum(
|
attempts = sum(
|
||||||
1
|
1
|
||||||
|
@@ -84,7 +84,7 @@ def test_publish_snapshot_success():
|
|||||||
) as mock_send:
|
) as mock_send:
|
||||||
manifest, event_id = asyncio.run(client.publish_snapshot(b"data"))
|
manifest, event_id = asyncio.run(client.publish_snapshot(b"data"))
|
||||||
assert isinstance(manifest, Manifest)
|
assert isinstance(manifest, Manifest)
|
||||||
assert event_id == "abcd"
|
assert event_id == "seedpass-manifest-fp"
|
||||||
assert mock_send.await_count >= 1
|
assert mock_send.await_count >= 1
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user