Skip to content

Commit a9c9774

Browse files
authored
Merge branch 'main' into docs
2 parents 1c93490 + b8ea375 commit a9c9774

7 files changed

Lines changed: 74 additions & 36 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "koi-net"
3-
version = "1.3.0-beta.9"
3+
version = "1.3.2"
44
description = "Implementation of KOI-net protocol in Python"
55
maintainers = [
66
{ name = "Luke Miller", email = "luke@block.science" }

src/koi_net/components/cache.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from pathlib import Path
44
from dataclasses import dataclass
55

6+
from pydantic import ValidationError
67
from rid_lib.core import RID, RIDType
78
from rid_lib.ext import Bundle
89
from rid_lib.ext.utils import b64_encode, b64_decode
@@ -50,7 +51,16 @@ def read(self, rid: RID) -> Bundle | None:
5051
mode="r",
5152
encoding="utf-8"
5253
) as f:
53-
return Bundle.model_validate_json(f.read())
54+
file_content = f.read()
55+
56+
if file_content == "":
57+
return None
58+
59+
try:
60+
return Bundle.model_validate_json(file_content)
61+
except ValidationError:
62+
return None
63+
5464
except FileNotFoundError:
5565
return None
5666

src/koi_net/components/knowledge_handlers/forget_node_handler.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
from dataclasses import dataclass
22

3-
from rid_lib.types import KoiNetNode
3+
from rid_lib.types import KoiNetEdge, KoiNetNode
44

55
from koi_net.protocol.edge import EdgeProfile
66
from koi_net.protocol.knowledge_object import KnowledgeObject
77
from koi_net.protocol.event import EventType
88
from ..interfaces import KnowledgeHandler, HandlerType
99
from ..kobj_queue import KobjQueue
10-
from ..graph import NetworkGraph
1110
from ..cache import Cache
1211

1312

1413
@dataclass
1514
class ForgetNodeHandler(KnowledgeHandler):
1615
cache: Cache
17-
graph: NetworkGraph
1816
kobj_queue: KobjQueue
1917

2018
handler_type = HandlerType.Final
@@ -26,10 +24,11 @@ def handle(self, kobj: KnowledgeObject):
2624
if kobj.normalized_event_type != EventType.FORGET:
2725
return
2826

29-
for edge_rid in self.graph.get_edges():
27+
for edge_rid in self.cache.list_rids(rid_types=[KoiNetEdge]):
3028
edge_bundle = self.cache.read(edge_rid)
3129
if not edge_bundle:
3230
continue
31+
3332
edge_profile = edge_bundle.validate_contents(EdgeProfile)
3433

3534
if kobj.rid in (edge_profile.source, edge_profile.target):

src/koi_net/components/knowledge_handlers/node_contact_handler.py

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from koi_net.exceptions import RequestError
77
from koi_net.config.base import BaseNodeConfig
8+
from koi_net.infra import depends_on
89
from koi_net.protocol.node import NodeProfile, NodeType
910
from koi_net.protocol.edge import EdgeProfile, EdgeStatus, EdgeType, generate_edge_bundle
1011
from koi_net.protocol.knowledge_object import KnowledgeObject
@@ -28,19 +29,12 @@ class NodeContactHandler(KnowledgeHandler):
2829
handler_type = HandlerType.Network
2930
rid_types = (KoiNetNode,)
3031

31-
def handle(self, kobj: KnowledgeObject):
32-
"""Makes contact with providers of RID types of interest.
33-
34-
When an incoming node knowledge object is identified as a provider
35-
of an RID type of interest, this handler will propose a new edge
36-
subscribing to future node events, and fetch existing nodes to catch
37-
up to the current state.
38-
"""
32+
def process_node(self, node_rid: KoiNetNode, node_bundle: Bundle):
3933
# prevents nodes from attempting to form a self loop
40-
if kobj.rid == self.identity.rid:
34+
if node_rid == self.identity.rid:
4135
return
4236

43-
node_profile = kobj.bundle.validate_contents(NodeProfile)
37+
node_profile = node_bundle.validate_contents(NodeProfile)
4438

4539
available_rid_types = list(
4640
set(self.config.koi_net.rid_types_of_interest) &
@@ -51,7 +45,7 @@ def handle(self, kobj: KnowledgeObject):
5145
return
5246

5347
edge_rid = self.graph.get_edge(
54-
source=kobj.rid,
48+
source=node_rid,
5549
target=self.identity.rid,
5650
)
5751

@@ -74,7 +68,7 @@ def handle(self, kobj: KnowledgeObject):
7468
else:
7569
self.log.info(f"Proposing new edge with node provider {available_rid_types}")
7670
edge_bundle = generate_edge_bundle(
77-
source=kobj.rid,
71+
source=node_rid,
7872
target=self.identity.rid,
7973
rid_types=available_rid_types,
8074
edge_type=(
@@ -90,7 +84,7 @@ def handle(self, kobj: KnowledgeObject):
9084
self.log.info("Catching up on network state")
9185
try:
9286
payload = self.request_handler.fetch_rids(
93-
node=kobj.rid,
87+
node=node_rid,
9488
rid_types=available_rid_types
9589
)
9690
except RequestError:
@@ -107,5 +101,25 @@ def handle(self, kobj: KnowledgeObject):
107101

108102
# marked as external since we are handling RIDs from another node
109103
# will fetch remotely instead of checking local cache
110-
self.kobj_queue.push(rid=rid, source=kobj.rid)
104+
self.kobj_queue.push(rid=rid, source=node_rid)
111105
self.log.info("Done")
106+
107+
def handle(self, kobj: KnowledgeObject):
108+
"""Makes contact with providers of RID types of interest.
109+
110+
When an incoming node knowledge object is identified as a provider
111+
of an RID type of interest, this handler will propose a new edge
112+
subscribing to future node events, and fetch existing nodes to catch
113+
up to the current state.
114+
"""
115+
self.process_node(kobj.rid, kobj.bundle)
116+
117+
@depends_on("graph", "kobj_worker")
118+
def start(self):
119+
self.log.info("Starting node contact analysis on cached profiles...")
120+
for rid in self.cache.list_rids(rid_types=(KoiNetNode,)):
121+
bundle = self.cache.read(rid)
122+
if not bundle:
123+
continue
124+
125+
self.process_node(rid, bundle)

src/koi_net/components/sync_manager.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from dataclasses import dataclass
22
from logging import Logger
3+
from rid_lib import RIDType
34
from rid_lib.ext import Cache
45
from rid_lib.types import KoiNetNode
56

7+
from ..config.base import BaseNodeConfig
68
from ..infra import depends_on
79
from ..exceptions import RequestError
810
from .graph import NetworkGraph
@@ -18,25 +20,30 @@ class SyncManager:
1820
log: Logger
1921
graph: NetworkGraph
2022
cache: Cache
23+
config: BaseNodeConfig
2124
request_handler: RequestHandler
2225
kobj_queue: KobjQueue
2326

2427
@depends_on("graph", "kobj_worker")
2528
def start(self):
26-
"""Catches up with node providers on startup."""
27-
28-
node_providers = self.graph.get_neighbors(
29-
direction="in",
30-
allowed_type=KoiNetNode
31-
)
32-
33-
if not node_providers:
34-
return
35-
36-
self.log.debug(f"Catching up with `orn:koi-net.node` providers: {node_providers}")
37-
self.catch_up_with(node_providers, [KoiNetNode])
29+
"""Catches up with providers on startup."""
30+
self.catch_up_with_all(self.config.koi_net.rid_types_of_interest)
3831

39-
def catch_up_with(self, nodes, rid_types):
32+
def catch_up_with_all(self, rid_types: list[RIDType]):
33+
node_providers = []
34+
for rid_type in rid_types:
35+
providers = self.graph.get_neighbors(
36+
direction="in",
37+
allowed_type=rid_type
38+
)
39+
40+
if not node_providers:
41+
continue
42+
43+
self.log.debug(f"Catching up with {rid_type} providers: {node_providers}")
44+
self.catch_up_with(node_providers, [rid_type])
45+
46+
def catch_up_with(self, nodes: list[KoiNetNode], rid_types: list[RIDType]):
4047
"""Catches up with the state of RID types within other nodes."""
4148

4249
for node in nodes:

src/koi_net/core.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from pathlib import Path
23

34
from .infra import LogSystem
@@ -72,7 +73,14 @@ class BaseNode(BaseAssembly):
7273
edge_negotiation_handler: EdgeNegotiationHandler = EdgeNegotiationHandler
7374
secure_profile_handler: SecureProfileHandler = SecureProfileHandler
7475

75-
def __new__(cls, *args, root_dir: Path = Path.cwd(), **kwargs):
76+
def __new__(cls, *args, root_dir: Path | None = None, **kwargs):
77+
if root_dir is None:
78+
if len(sys.argv) > 1:
79+
root_dir = Path(sys.argv[1])
80+
print(f"Root dir was set by CLI to '{root_dir}'")
81+
else:
82+
root_dir = Path.cwd()
83+
7684
cls._log_system()
7785
return super().__new__(cls, *args, root_dir=root_dir, **kwargs)
7886

src/koi_net/infra/container.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from queue import Queue
21
import time
3-
from typing import TYPE_CHECKING, Any
42
import threading
3+
from queue import Queue
4+
from typing import TYPE_CHECKING, Any
55
from pathlib import Path
66
from logging import Logger
77

0 commit comments

Comments
 (0)