koi-net 1.2.0b1__tar.gz → 1.2.0b2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of koi-net might be problematic. Click here for more details.
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/PKG-INFO +2 -1
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/pyproject.toml +2 -1
- koi_net-1.2.0b2/src/koi_net/__init__.py +2 -0
- koi_net-1.2.0b2/src/koi_net/assembler.py +82 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/context.py +5 -13
- koi_net-1.2.0b2/src/koi_net/core.py +78 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/effector.py +26 -14
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/handshaker.py +3 -3
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/identity.py +2 -3
- koi_net-1.2.0b2/src/koi_net/interfaces/entrypoint.py +5 -0
- {koi_net-1.2.0b1/src/koi_net → koi_net-1.2.0b2/src/koi_net/interfaces}/worker.py +7 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/lifecycle.py +40 -32
- koi_net-1.2.0b2/src/koi_net/logger.py +176 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/network/error_handler.py +6 -6
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/network/event_queue.py +8 -6
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/network/graph.py +8 -8
- koi_net-1.2.0b2/src/koi_net/network/poll_event_buffer.py +26 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/network/request_handler.py +23 -28
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/network/resolver.py +13 -13
- koi_net-1.2.0b2/src/koi_net/network/response_handler.py +132 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/poller.py +7 -5
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/processor/event_worker.py +14 -18
- koi_net-1.2.0b1/src/koi_net/processor/default_handlers.py → koi_net-1.2.0b2/src/koi_net/processor/handlers.py +26 -25
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/processor/kobj_queue.py +3 -3
- {koi_net-1.2.0b1/src/koi_net → koi_net-1.2.0b2/src/koi_net/processor}/kobj_worker.py +12 -13
- koi_net-1.2.0b1/src/koi_net/processor/knowledge_pipeline.py → koi_net-1.2.0b2/src/koi_net/processor/pipeline.py +24 -27
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/protocol/api_models.py +5 -2
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/protocol/envelope.py +5 -6
- koi_net-1.2.0b2/src/koi_net/protocol/model_map.py +61 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/protocol/secure.py +8 -8
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/secure.py +5 -5
- koi_net-1.2.0b2/src/koi_net/sentry.py +13 -0
- koi_net-1.2.0b2/src/koi_net/server.py +95 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/uv.lock +15 -1
- koi_net-1.2.0b1/src/koi_net/__init__.py +0 -1
- koi_net-1.2.0b1/src/koi_net/behaviors.py +0 -51
- koi_net-1.2.0b1/src/koi_net/core.py +0 -233
- koi_net-1.2.0b1/src/koi_net/models.py +0 -14
- koi_net-1.2.0b1/src/koi_net/network/response_handler.py +0 -67
- koi_net-1.2.0b1/src/koi_net/poll_event_buffer.py +0 -17
- koi_net-1.2.0b1/src/koi_net/server.py +0 -145
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/.github/workflows/publish-to-pypi.yml +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/.gitignore +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/LICENSE +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/README.md +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/examples/coordinator.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/examples/partial.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/koi-net-protocol-openapi.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/requirements.txt +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/bundle.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/bundles_payload.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/edge_profile.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/error_response.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/event.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/events_payload.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/fetch_bundles.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/fetch_manifests.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/fetch_rids.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/manifest.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/manifests_payload.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/node_profile.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/poll_events.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/rids_payload.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/signed_envelope.schema.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/schemas/unsigned_envelope.json +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/cli/__init__.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/cli/commands.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/cli/models.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/config.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/default_actions.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/network/__init__.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/processor/__init__.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/processor/handler.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/processor/knowledge_object.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/protocol/__init__.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/protocol/consts.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/protocol/edge.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/protocol/errors.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/protocol/event.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/protocol/node.py +0 -0
- {koi_net-1.2.0b1 → koi_net-1.2.0b2}/src/koi_net/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: koi-net
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.0b2
|
|
4
4
|
Summary: Implementation of KOI-net protocol in Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/BlockScience/koi-net/
|
|
6
6
|
Author-email: Luke Miller <luke@block.science>
|
|
@@ -36,6 +36,7 @@ Requires-Dist: python-dotenv>=1.1.0
|
|
|
36
36
|
Requires-Dist: rich>=14.1.0
|
|
37
37
|
Requires-Dist: rid-lib>=3.2.7
|
|
38
38
|
Requires-Dist: ruamel-yaml>=0.18.10
|
|
39
|
+
Requires-Dist: structlog>=25.4.0
|
|
39
40
|
Requires-Dist: uvicorn>=0.34.2
|
|
40
41
|
Provides-Extra: dev
|
|
41
42
|
Requires-Dist: build; extra == 'dev'
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "koi-net"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.0b2"
|
|
8
8
|
description = "Implementation of KOI-net protocol in Python"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Luke Miller", email = "luke@block.science"}
|
|
@@ -23,6 +23,7 @@ dependencies = [
|
|
|
23
23
|
"fastapi>=0.115.12",
|
|
24
24
|
"uvicorn>=0.34.2",
|
|
25
25
|
"rich>=14.1.0",
|
|
26
|
+
"structlog>=25.4.0",
|
|
26
27
|
]
|
|
27
28
|
|
|
28
29
|
[project.optional-dependencies]
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
from dataclasses import make_dataclass
|
|
4
|
+
|
|
5
|
+
import structlog
|
|
6
|
+
|
|
7
|
+
from .interfaces.entrypoint import EntryPoint
|
|
8
|
+
|
|
9
|
+
log = structlog.stdlib.get_logger()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BuildOrderer(type):
|
|
13
|
+
def __new__(cls, name: str, bases: tuple, dct: dict[str]):
|
|
14
|
+
"""Sets `cls._build_order` from component order in class definition."""
|
|
15
|
+
cls = super().__new__(cls, name, bases, dct)
|
|
16
|
+
|
|
17
|
+
if "_build_order" not in dct:
|
|
18
|
+
components = {}
|
|
19
|
+
# adds components from base classes (including cls)
|
|
20
|
+
for base in reversed(inspect.getmro(cls)[:-1]):
|
|
21
|
+
for k, v in vars(base).items():
|
|
22
|
+
# excludes built in and private attributes
|
|
23
|
+
if not k.startswith("_"):
|
|
24
|
+
components[k] = v
|
|
25
|
+
|
|
26
|
+
# recipe list constructed from names of non-None components
|
|
27
|
+
cls._build_order = [
|
|
28
|
+
name for name, _type in components.items()
|
|
29
|
+
if _type is not None
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
return cls
|
|
33
|
+
|
|
34
|
+
class NodeContainer(Protocol):
|
|
35
|
+
entrypoint = EntryPoint
|
|
36
|
+
|
|
37
|
+
class NodeAssembler(metaclass=BuildOrderer):
|
|
38
|
+
def __new__(self) -> NodeContainer:
|
|
39
|
+
return self._build()
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def _build(cls) -> NodeContainer:
|
|
43
|
+
components = {}
|
|
44
|
+
for comp_name in cls._build_order:
|
|
45
|
+
comp_factory = getattr(cls, comp_name, None)
|
|
46
|
+
|
|
47
|
+
if comp_factory is None:
|
|
48
|
+
raise Exception(f"Couldn't find factory for component '{comp_name}'")
|
|
49
|
+
|
|
50
|
+
sig = inspect.signature(comp_factory)
|
|
51
|
+
|
|
52
|
+
required_comps = []
|
|
53
|
+
for name, param in sig.parameters.items():
|
|
54
|
+
required_comps.append((name, param.annotation))
|
|
55
|
+
|
|
56
|
+
if len(required_comps) == 0:
|
|
57
|
+
s = comp_name
|
|
58
|
+
else:
|
|
59
|
+
s = f"{comp_name} -> {', '.join([name for name, _type in required_comps])}"
|
|
60
|
+
|
|
61
|
+
print(s.replace("graph", "_graph"), end=";\n")
|
|
62
|
+
|
|
63
|
+
dependencies = {}
|
|
64
|
+
for req_comp_name, req_comp_type in required_comps:
|
|
65
|
+
if req_comp_name not in components:
|
|
66
|
+
raise Exception(f"Couldn't find required component '{req_comp_name}'")
|
|
67
|
+
|
|
68
|
+
dependencies[req_comp_name] = components[req_comp_name]
|
|
69
|
+
|
|
70
|
+
components[comp_name] = comp_factory(**dependencies)
|
|
71
|
+
|
|
72
|
+
NodeContainer = make_dataclass(
|
|
73
|
+
cls_name="NodeContainer",
|
|
74
|
+
fields=[
|
|
75
|
+
(name, type(component))
|
|
76
|
+
for name, component
|
|
77
|
+
in components.items()
|
|
78
|
+
],
|
|
79
|
+
frozen=True
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return NodeContainer(**components)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from rid_lib.ext import Cache
|
|
2
2
|
|
|
3
|
+
from koi_net.effector import Effector
|
|
3
4
|
from koi_net.network.resolver import NetworkResolver
|
|
4
5
|
from .config import NodeConfig
|
|
5
6
|
from .network.graph import NetworkGraph
|
|
@@ -9,18 +10,6 @@ from .identity import NodeIdentity
|
|
|
9
10
|
from .processor.kobj_queue import KobjQueue
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
class ActionContext:
|
|
13
|
-
"""Provides action handlers access to other subsystems."""
|
|
14
|
-
|
|
15
|
-
identity: NodeIdentity
|
|
16
|
-
|
|
17
|
-
def __init__(
|
|
18
|
-
self,
|
|
19
|
-
identity: NodeIdentity,
|
|
20
|
-
):
|
|
21
|
-
self.identity = identity
|
|
22
|
-
|
|
23
|
-
|
|
24
13
|
class HandlerContext:
|
|
25
14
|
"""Provides knowledge handlers access to other subsystems."""
|
|
26
15
|
|
|
@@ -32,6 +21,7 @@ class HandlerContext:
|
|
|
32
21
|
graph: NetworkGraph
|
|
33
22
|
request_handler: RequestHandler
|
|
34
23
|
resolver: NetworkResolver
|
|
24
|
+
effector: Effector
|
|
35
25
|
|
|
36
26
|
def __init__(
|
|
37
27
|
self,
|
|
@@ -43,6 +33,7 @@ class HandlerContext:
|
|
|
43
33
|
graph: NetworkGraph,
|
|
44
34
|
request_handler: RequestHandler,
|
|
45
35
|
resolver: NetworkResolver,
|
|
36
|
+
effector: Effector
|
|
46
37
|
):
|
|
47
38
|
self.identity = identity
|
|
48
39
|
self.config = config
|
|
@@ -51,4 +42,5 @@ class HandlerContext:
|
|
|
51
42
|
self.kobj_queue = kobj_queue
|
|
52
43
|
self.graph = graph
|
|
53
44
|
self.request_handler = request_handler
|
|
54
|
-
self.resolver = resolver
|
|
45
|
+
self.resolver = resolver
|
|
46
|
+
self.effector = effector
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from rid_lib.ext import Cache
|
|
2
|
+
from .assembler import NodeAssembler
|
|
3
|
+
from .config.base import BaseConfig
|
|
4
|
+
from .context import HandlerContext
|
|
5
|
+
from .effector import Effector
|
|
6
|
+
from .handshaker import Handshaker
|
|
7
|
+
from .identity import NodeIdentity
|
|
8
|
+
from .processor.kobj_worker import KnowledgeProcessingWorker
|
|
9
|
+
from .lifecycle import NodeLifecycle
|
|
10
|
+
from .network.error_handler import ErrorHandler
|
|
11
|
+
from .network.event_queue import EventQueue
|
|
12
|
+
from .network.graph import NetworkGraph
|
|
13
|
+
from .network.request_handler import RequestHandler
|
|
14
|
+
from .network.resolver import NetworkResolver
|
|
15
|
+
from .network.response_handler import ResponseHandler
|
|
16
|
+
from .network.poll_event_buffer import PollEventBuffer
|
|
17
|
+
from .poller import NodePoller
|
|
18
|
+
from .processor.handlers import (
|
|
19
|
+
basic_manifest_handler,
|
|
20
|
+
basic_network_output_filter,
|
|
21
|
+
basic_rid_handler,
|
|
22
|
+
node_contact_handler,
|
|
23
|
+
edge_negotiation_handler,
|
|
24
|
+
forget_edge_on_node_deletion,
|
|
25
|
+
secure_profile_handler
|
|
26
|
+
)
|
|
27
|
+
from .processor.event_worker import EventProcessingWorker
|
|
28
|
+
from .processor.pipeline import KnowledgePipeline
|
|
29
|
+
from .processor.kobj_queue import KobjQueue
|
|
30
|
+
from .secure import Secure
|
|
31
|
+
from .server import NodeServer
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# factory functions for components with non standard initializiation
|
|
35
|
+
|
|
36
|
+
def make_config() -> BaseConfig:
|
|
37
|
+
return BaseConfig.load_from_yaml()
|
|
38
|
+
|
|
39
|
+
def make_cache(config: BaseConfig) -> Cache:
|
|
40
|
+
return Cache(directory_path=config.koi_net.cache_directory_path)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class BaseNode(NodeAssembler):
|
|
44
|
+
config = lambda: None
|
|
45
|
+
kobj_queue = KobjQueue
|
|
46
|
+
event_queue = EventQueue
|
|
47
|
+
poll_event_buf = PollEventBuffer
|
|
48
|
+
knowledge_handlers = lambda: [
|
|
49
|
+
basic_rid_handler,
|
|
50
|
+
basic_manifest_handler,
|
|
51
|
+
secure_profile_handler,
|
|
52
|
+
edge_negotiation_handler,
|
|
53
|
+
node_contact_handler,
|
|
54
|
+
basic_network_output_filter,
|
|
55
|
+
forget_edge_on_node_deletion
|
|
56
|
+
]
|
|
57
|
+
cache = make_cache
|
|
58
|
+
identity = NodeIdentity
|
|
59
|
+
graph = NetworkGraph
|
|
60
|
+
secure = Secure
|
|
61
|
+
handshaker = Handshaker
|
|
62
|
+
error_handler = ErrorHandler
|
|
63
|
+
request_handler = RequestHandler
|
|
64
|
+
response_handler = ResponseHandler
|
|
65
|
+
resolver = NetworkResolver
|
|
66
|
+
effector = Effector
|
|
67
|
+
handler_context = HandlerContext
|
|
68
|
+
pipeline = KnowledgePipeline
|
|
69
|
+
kobj_worker = KnowledgeProcessingWorker
|
|
70
|
+
event_worker = EventProcessingWorker
|
|
71
|
+
lifecycle = NodeLifecycle
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class FullNode(BaseNode):
|
|
75
|
+
entrypoint = NodeServer
|
|
76
|
+
|
|
77
|
+
class PartialNode(BaseNode):
|
|
78
|
+
entrypoint = NodePoller
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import structlog
|
|
2
2
|
from typing import Callable
|
|
3
3
|
from enum import StrEnum
|
|
4
4
|
from rid_lib.ext import Cache, Bundle
|
|
@@ -6,11 +6,23 @@ from rid_lib.core import RID, RIDType
|
|
|
6
6
|
from rid_lib.types import KoiNetNode
|
|
7
7
|
from .network.resolver import NetworkResolver
|
|
8
8
|
from .processor.kobj_queue import KobjQueue
|
|
9
|
-
from .
|
|
9
|
+
from .identity import NodeIdentity
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
log = structlog.stdlib.get_logger()
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
class ActionContext:
|
|
15
|
+
"""Provides action handlers access to other subsystems."""
|
|
16
|
+
|
|
17
|
+
identity: NodeIdentity
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
identity: NodeIdentity,
|
|
22
|
+
):
|
|
23
|
+
self.identity = identity
|
|
24
|
+
|
|
25
|
+
|
|
14
26
|
class BundleSource(StrEnum):
|
|
15
27
|
CACHE = "CACHE"
|
|
16
28
|
ACTION = "ACTION"
|
|
@@ -35,12 +47,12 @@ class Effector:
|
|
|
35
47
|
cache: Cache,
|
|
36
48
|
resolver: NetworkResolver,
|
|
37
49
|
kobj_queue: KobjQueue,
|
|
38
|
-
|
|
50
|
+
identity: NodeIdentity
|
|
39
51
|
):
|
|
40
52
|
self.cache = cache
|
|
41
53
|
self.resolver = resolver
|
|
42
54
|
self.kobj_queue = kobj_queue
|
|
43
|
-
self.action_context =
|
|
55
|
+
self.action_context = ActionContext(identity)
|
|
44
56
|
self._action_table = self.__class__._action_table.copy()
|
|
45
57
|
|
|
46
58
|
@classmethod
|
|
@@ -70,18 +82,18 @@ class Effector:
|
|
|
70
82
|
bundle = self.cache.read(rid)
|
|
71
83
|
|
|
72
84
|
if bundle:
|
|
73
|
-
|
|
85
|
+
log.debug("Cache hit")
|
|
74
86
|
return bundle, BundleSource.CACHE
|
|
75
87
|
else:
|
|
76
|
-
|
|
88
|
+
log.debug("Cache miss")
|
|
77
89
|
return None
|
|
78
90
|
|
|
79
91
|
def _try_action(self, rid: RID) -> tuple[Bundle, BundleSource] | None:
|
|
80
92
|
if type(rid) not in self._action_table:
|
|
81
|
-
|
|
93
|
+
log.debug("No action available")
|
|
82
94
|
return None
|
|
83
95
|
|
|
84
|
-
|
|
96
|
+
log.debug("Action available")
|
|
85
97
|
func = self._action_table[type(rid)]
|
|
86
98
|
bundle = func(
|
|
87
99
|
ctx=self.action_context,
|
|
@@ -89,10 +101,10 @@ class Effector:
|
|
|
89
101
|
)
|
|
90
102
|
|
|
91
103
|
if bundle:
|
|
92
|
-
|
|
104
|
+
log.debug("Action hit")
|
|
93
105
|
return bundle, BundleSource.ACTION
|
|
94
106
|
else:
|
|
95
|
-
|
|
107
|
+
log.debug("Action miss")
|
|
96
108
|
return None
|
|
97
109
|
|
|
98
110
|
|
|
@@ -100,10 +112,10 @@ class Effector:
|
|
|
100
112
|
bundle, source = self.resolver.fetch_remote_bundle(rid)
|
|
101
113
|
|
|
102
114
|
if bundle:
|
|
103
|
-
|
|
115
|
+
log.debug("Network hit")
|
|
104
116
|
return bundle, source
|
|
105
117
|
else:
|
|
106
|
-
|
|
118
|
+
log.debug("Network miss")
|
|
107
119
|
return None
|
|
108
120
|
|
|
109
121
|
|
|
@@ -127,7 +139,7 @@ class Effector:
|
|
|
127
139
|
handle_result: handles resulting bundle with knowledge pipeline when `True`
|
|
128
140
|
"""
|
|
129
141
|
|
|
130
|
-
|
|
142
|
+
log.debug(f"Dereferencing {rid!r}")
|
|
131
143
|
|
|
132
144
|
bundle, source = (
|
|
133
145
|
# if `refresh_cache`, skip try cache
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import structlog
|
|
2
2
|
from rid_lib.ext import Cache
|
|
3
3
|
from rid_lib.types import KoiNetNode
|
|
4
4
|
from koi_net.identity import NodeIdentity
|
|
5
5
|
from koi_net.network.event_queue import EventQueue
|
|
6
6
|
from .protocol.event import Event, EventType
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
log = structlog.stdlib.get_logger()
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class Handshaker:
|
|
@@ -24,7 +24,7 @@ class Handshaker:
|
|
|
24
24
|
Pushes successive `FORGET` and `NEW` events to target node to
|
|
25
25
|
reset the target's cache in case it already knew this node.
|
|
26
26
|
"""
|
|
27
|
-
|
|
27
|
+
log.debug(f"Initiating handshake with {target}")
|
|
28
28
|
self.event_queue.push_event_to(
|
|
29
29
|
Event.from_rid(
|
|
30
30
|
event_type=EventType.FORGET,
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import structlog
|
|
2
2
|
from rid_lib.types.koi_net_node import KoiNetNode
|
|
3
3
|
from .config import NodeConfig
|
|
4
4
|
from .protocol.node import NodeProfile
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
logger = logging.getLogger(__name__)
|
|
6
|
+
log = structlog.stdlib.get_logger()
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
class NodeIdentity:
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import
|
|
1
|
+
import structlog
|
|
2
2
|
from contextlib import contextmanager, asynccontextmanager
|
|
3
3
|
|
|
4
4
|
from rid_lib.ext import Bundle, Cache
|
|
5
5
|
from rid_lib.types import KoiNetNode
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from
|
|
13
|
-
|
|
7
|
+
from .handshaker import Handshaker
|
|
8
|
+
from .network.request_handler import RequestHandler
|
|
9
|
+
from .processor.kobj_worker import KnowledgeProcessingWorker
|
|
10
|
+
from .network.event_queue import EventQueue
|
|
11
|
+
from .processor.event_worker import EventProcessingWorker
|
|
12
|
+
from .protocol.api_models import ErrorResponse
|
|
13
|
+
from .interfaces.worker import STOP_WORKER
|
|
14
14
|
from .config import NodeConfig
|
|
15
15
|
from .processor.kobj_queue import KobjQueue
|
|
16
16
|
from .network.graph import NetworkGraph
|
|
17
17
|
from .identity import NodeIdentity
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
log = structlog.stdlib.get_logger()
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class NodeLifecycle:
|
|
@@ -31,7 +31,7 @@ class NodeLifecycle:
|
|
|
31
31
|
event_worker: EventProcessingWorker
|
|
32
32
|
cache: Cache
|
|
33
33
|
handshaker: Handshaker
|
|
34
|
-
|
|
34
|
+
request_handler: RequestHandler
|
|
35
35
|
|
|
36
36
|
def __init__(
|
|
37
37
|
self,
|
|
@@ -44,7 +44,7 @@ class NodeLifecycle:
|
|
|
44
44
|
event_worker: EventProcessingWorker,
|
|
45
45
|
cache: Cache,
|
|
46
46
|
handshaker: Handshaker,
|
|
47
|
-
|
|
47
|
+
request_handler: RequestHandler
|
|
48
48
|
):
|
|
49
49
|
self.config = config
|
|
50
50
|
self.identity = identity
|
|
@@ -55,32 +55,32 @@ class NodeLifecycle:
|
|
|
55
55
|
self.event_worker = event_worker
|
|
56
56
|
self.cache = cache
|
|
57
57
|
self.handshaker = handshaker
|
|
58
|
-
self.
|
|
58
|
+
self.request_handler = request_handler
|
|
59
59
|
|
|
60
60
|
@contextmanager
|
|
61
61
|
def run(self):
|
|
62
62
|
"""Synchronous context manager for node startup and shutdown."""
|
|
63
63
|
try:
|
|
64
|
-
|
|
64
|
+
log.info("Starting node lifecycle...")
|
|
65
65
|
self.start()
|
|
66
66
|
yield
|
|
67
67
|
except KeyboardInterrupt:
|
|
68
|
-
|
|
68
|
+
log.info("Keyboard interrupt!")
|
|
69
69
|
finally:
|
|
70
|
-
|
|
70
|
+
log.info("Stopping node lifecycle...")
|
|
71
71
|
self.stop()
|
|
72
72
|
|
|
73
73
|
@asynccontextmanager
|
|
74
74
|
async def async_run(self):
|
|
75
75
|
"""Asynchronous context manager for node startup and shutdown."""
|
|
76
76
|
try:
|
|
77
|
-
|
|
77
|
+
log.info("Starting async node lifecycle...")
|
|
78
78
|
self.start()
|
|
79
79
|
yield
|
|
80
80
|
except KeyboardInterrupt:
|
|
81
|
-
|
|
81
|
+
log.info("Keyboard interrupt!")
|
|
82
82
|
finally:
|
|
83
|
-
|
|
83
|
+
log.info("Stopping async node lifecycle...")
|
|
84
84
|
self.stop()
|
|
85
85
|
|
|
86
86
|
def start(self):
|
|
@@ -91,7 +91,7 @@ class NodeLifecycle:
|
|
|
91
91
|
of node bundle. Initiates handshake with first contact if node
|
|
92
92
|
doesn't have any neighbors. Catches up with coordinator state.
|
|
93
93
|
"""
|
|
94
|
-
|
|
94
|
+
log.info("Starting processor worker thread")
|
|
95
95
|
|
|
96
96
|
self.kobj_worker.thread.start()
|
|
97
97
|
self.event_worker.thread.start()
|
|
@@ -104,30 +104,38 @@ class NodeLifecycle:
|
|
|
104
104
|
contents=self.identity.profile.model_dump()
|
|
105
105
|
))
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
log.debug("Waiting for kobj queue to empty")
|
|
108
108
|
self.kobj_queue.q.join()
|
|
109
109
|
|
|
110
|
-
# TODO: FACTOR OUT BEHAVIOR
|
|
111
|
-
|
|
112
110
|
coordinators = self.graph.get_neighbors(direction="in", allowed_type=KoiNetNode)
|
|
113
111
|
|
|
114
|
-
if len(coordinators)
|
|
115
|
-
|
|
112
|
+
if len(coordinators) > 0:
|
|
113
|
+
for coordinator in coordinators:
|
|
114
|
+
payload = self.request_handler.fetch_manifests(
|
|
115
|
+
node=coordinator,
|
|
116
|
+
rid_types=[KoiNetNode]
|
|
117
|
+
)
|
|
118
|
+
if type(payload) is ErrorResponse:
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
for manifest in payload.manifests:
|
|
122
|
+
self.kobj_queue.put_kobj(
|
|
123
|
+
manifest=manifest,
|
|
124
|
+
source=coordinator
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
elif self.config.koi_net.first_contact.rid:
|
|
128
|
+
log.debug(f"I don't have any edges with coordinators, reaching out to first contact {self.config.koi_net.first_contact.rid!r}")
|
|
116
129
|
|
|
117
130
|
self.handshaker.handshake_with(self.config.koi_net.first_contact.rid)
|
|
118
131
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
for coordinator in self.behaviors.identify_coordinators():
|
|
122
|
-
self.behaviors.catch_up_with(coordinator, rid_types=[KoiNetNode])
|
|
123
|
-
|
|
124
132
|
|
|
125
133
|
def stop(self):
|
|
126
134
|
"""Stops a node.
|
|
127
135
|
|
|
128
136
|
Finishes processing knowledge object queue.
|
|
129
137
|
"""
|
|
130
|
-
|
|
138
|
+
log.info(f"Waiting for kobj queue to empty ({self.kobj_queue.q.unfinished_tasks} tasks remaining)")
|
|
131
139
|
|
|
132
|
-
self.kobj_queue.q.put(
|
|
133
|
-
self.event_queue.q.put(
|
|
140
|
+
self.kobj_queue.q.put(STOP_WORKER)
|
|
141
|
+
self.event_queue.q.put(STOP_WORKER)
|