koi-net 1.2.0b1__py3-none-any.whl → 1.2.0b3__py3-none-any.whl
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/__init__.py +1 -1
- koi_net/assembler.py +95 -0
- koi_net/cli/models.py +2 -2
- koi_net/config/core.py +71 -0
- koi_net/config/full_node.py +31 -0
- koi_net/config/loader.py +46 -0
- koi_net/config/partial_node.py +18 -0
- koi_net/core.py +43 -206
- koi_net/default_actions.py +1 -2
- koi_net/effector.py +27 -15
- koi_net/entrypoints/__init__.py +2 -0
- koi_net/entrypoints/base.py +5 -0
- koi_net/{poller.py → entrypoints/poller.py} +14 -12
- koi_net/entrypoints/server.py +94 -0
- koi_net/handshaker.py +5 -5
- koi_net/identity.py +3 -4
- koi_net/lifecycle.py +42 -34
- koi_net/logger.py +176 -0
- koi_net/network/error_handler.py +7 -7
- koi_net/network/event_queue.py +9 -7
- koi_net/network/graph.py +8 -8
- koi_net/network/poll_event_buffer.py +26 -0
- koi_net/network/request_handler.py +23 -28
- koi_net/network/resolver.py +14 -14
- koi_net/network/response_handler.py +74 -9
- koi_net/{context.py → processor/context.py} +11 -19
- koi_net/processor/handler.py +4 -1
- koi_net/processor/{default_handlers.py → knowledge_handlers.py} +32 -31
- koi_net/processor/knowledge_object.py +2 -3
- koi_net/processor/kobj_queue.py +4 -4
- koi_net/processor/{knowledge_pipeline.py → pipeline.py} +25 -28
- koi_net/protocol/api_models.py +5 -2
- koi_net/protocol/envelope.py +5 -6
- koi_net/protocol/model_map.py +61 -0
- koi_net/protocol/node.py +3 -3
- koi_net/protocol/secure.py +14 -8
- koi_net/secure.py +6 -7
- koi_net/workers/__init__.py +2 -0
- koi_net/{worker.py → workers/base.py} +7 -0
- koi_net/{processor → workers}/event_worker.py +19 -23
- koi_net/{kobj_worker.py → workers/kobj_worker.py} +12 -13
- {koi_net-1.2.0b1.dist-info → koi_net-1.2.0b3.dist-info}/METADATA +2 -1
- koi_net-1.2.0b3.dist-info/RECORD +56 -0
- koi_net/behaviors.py +0 -51
- koi_net/config.py +0 -161
- koi_net/models.py +0 -14
- koi_net/poll_event_buffer.py +0 -17
- koi_net/server.py +0 -145
- koi_net-1.2.0b1.dist-info/RECORD +0 -49
- {koi_net-1.2.0b1.dist-info → koi_net-1.2.0b3.dist-info}/WHEEL +0 -0
- {koi_net-1.2.0b1.dist-info → koi_net-1.2.0b3.dist-info}/entry_points.txt +0 -0
- {koi_net-1.2.0b1.dist-info → koi_net-1.2.0b3.dist-info}/licenses/LICENSE +0 -0
koi_net/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
from .
|
|
1
|
+
from . import logger
|
koi_net/assembler.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
from dataclasses import make_dataclass
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
import structlog
|
|
7
|
+
|
|
8
|
+
from .entrypoints.base import EntryPoint
|
|
9
|
+
|
|
10
|
+
log = structlog.stdlib.get_logger()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BuildOrderer(type):
|
|
14
|
+
def __new__(cls, name: str, bases: tuple, dct: dict[str]):
|
|
15
|
+
"""Sets `cls._build_order` from component order in class definition."""
|
|
16
|
+
cls = super().__new__(cls, name, bases, dct)
|
|
17
|
+
|
|
18
|
+
if "_build_order" not in dct:
|
|
19
|
+
components = {}
|
|
20
|
+
# adds components from base classes (including cls)
|
|
21
|
+
for base in reversed(inspect.getmro(cls)[:-1]):
|
|
22
|
+
for k, v in vars(base).items():
|
|
23
|
+
# excludes built in and private attributes
|
|
24
|
+
if not k.startswith("_"):
|
|
25
|
+
components[k] = v
|
|
26
|
+
|
|
27
|
+
# recipe list constructed from names of non-None components
|
|
28
|
+
cls._build_order = [
|
|
29
|
+
name for name, _type in components.items()
|
|
30
|
+
if _type is not None
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
return cls
|
|
34
|
+
|
|
35
|
+
class NodeContainer(Protocol):
|
|
36
|
+
entrypoint = EntryPoint
|
|
37
|
+
|
|
38
|
+
class NodeAssembler(metaclass=BuildOrderer):
|
|
39
|
+
def __new__(self) -> NodeContainer:
|
|
40
|
+
return self._build()
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def _build(cls) -> NodeContainer:
|
|
44
|
+
components = {}
|
|
45
|
+
for comp_name in cls._build_order:
|
|
46
|
+
comp = getattr(cls, comp_name, None)
|
|
47
|
+
|
|
48
|
+
if comp is None:
|
|
49
|
+
raise Exception(f"Couldn't find factory for component '{comp_name}'")
|
|
50
|
+
|
|
51
|
+
print(comp_name)
|
|
52
|
+
|
|
53
|
+
if not callable(comp):
|
|
54
|
+
print(f"Treating {comp_name} as a literal")
|
|
55
|
+
components[comp_name] = comp
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
if issubclass(comp, BaseModel):
|
|
59
|
+
print(f"Treating {comp_name} as a pydantic model")
|
|
60
|
+
components[comp_name] = comp
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
sig = inspect.signature(comp)
|
|
64
|
+
|
|
65
|
+
required_comps = []
|
|
66
|
+
for name, param in sig.parameters.items():
|
|
67
|
+
required_comps.append((name, param.annotation))
|
|
68
|
+
|
|
69
|
+
if len(required_comps) == 0:
|
|
70
|
+
s = comp_name
|
|
71
|
+
else:
|
|
72
|
+
s = f"{comp_name} -> {', '.join([name for name, _type in required_comps])}"
|
|
73
|
+
|
|
74
|
+
# print(s.replace("graph", "_graph"), end=";\n")
|
|
75
|
+
|
|
76
|
+
dependencies = {}
|
|
77
|
+
for req_comp_name, req_comp_type in required_comps:
|
|
78
|
+
if req_comp_name not in components:
|
|
79
|
+
raise Exception(f"Couldn't find required component '{req_comp_name}'")
|
|
80
|
+
|
|
81
|
+
dependencies[req_comp_name] = components[req_comp_name]
|
|
82
|
+
|
|
83
|
+
components[comp_name] = comp(**dependencies)
|
|
84
|
+
|
|
85
|
+
NodeContainer = make_dataclass(
|
|
86
|
+
cls_name="NodeContainer",
|
|
87
|
+
fields=[
|
|
88
|
+
(name, type(component))
|
|
89
|
+
for name, component
|
|
90
|
+
in components.items()
|
|
91
|
+
],
|
|
92
|
+
frozen=True
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return NodeContainer(**components)
|
koi_net/cli/models.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
from pydantic import BaseModel,
|
|
1
|
+
from pydantic import BaseModel, PrivateAttr
|
|
2
2
|
from ruamel.yaml import YAML
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class KoiNetworkConfig(BaseModel):
|
|
6
|
-
nodes: dict[str, str] =
|
|
6
|
+
nodes: dict[str, str] = {}
|
|
7
7
|
_file_path: str = PrivateAttr(default="koi-net-config.yaml")
|
|
8
8
|
|
|
9
9
|
@classmethod
|
koi_net/config/core.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pydantic import BaseModel, model_validator
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
from rid_lib import RIDType
|
|
5
|
+
from rid_lib.types import KoiNetNode
|
|
6
|
+
|
|
7
|
+
from koi_net.protocol.secure import PrivateKey
|
|
8
|
+
from ..protocol.node import NodeProfile
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class NodeContact(BaseModel):
|
|
12
|
+
rid: KoiNetNode | None = None
|
|
13
|
+
url: str | None = None
|
|
14
|
+
|
|
15
|
+
class KoiNetConfig(BaseModel):
|
|
16
|
+
"""Config for KOI-net."""
|
|
17
|
+
|
|
18
|
+
node_name: str
|
|
19
|
+
node_rid: KoiNetNode | None = None
|
|
20
|
+
node_profile: NodeProfile
|
|
21
|
+
|
|
22
|
+
rid_types_of_interest: list[RIDType] = [KoiNetNode]
|
|
23
|
+
|
|
24
|
+
cache_directory_path: str = ".rid_cache"
|
|
25
|
+
event_queues_path: str = "event_queues.json"
|
|
26
|
+
private_key_pem_path: str = "priv_key.pem"
|
|
27
|
+
|
|
28
|
+
first_contact: NodeContact = NodeContact()
|
|
29
|
+
|
|
30
|
+
class EnvConfig(BaseModel):
|
|
31
|
+
"""Config for environment variables.
|
|
32
|
+
|
|
33
|
+
Values set in the config are the variables names, and are loaded
|
|
34
|
+
from the environment at runtime. For example, if the config YAML
|
|
35
|
+
sets `priv_key_password: PRIV_KEY_PASSWORD` accessing
|
|
36
|
+
`priv_key_password` would retrieve the value of `PRIV_KEY_PASSWORD`
|
|
37
|
+
from the environment.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
priv_key_password: str = "PRIV_KEY_PASSWORD"
|
|
41
|
+
|
|
42
|
+
def __init__(self, **kwargs):
|
|
43
|
+
super().__init__(**kwargs)
|
|
44
|
+
load_dotenv()
|
|
45
|
+
|
|
46
|
+
def __getattribute__(self, name):
|
|
47
|
+
value = super().__getattribute__(name)
|
|
48
|
+
if name in type(self).model_fields:
|
|
49
|
+
env_val = os.getenv(value)
|
|
50
|
+
if env_val is None:
|
|
51
|
+
raise ValueError(f"Required environment variable {value} not set")
|
|
52
|
+
return env_val
|
|
53
|
+
return value
|
|
54
|
+
|
|
55
|
+
class NodeConfig(BaseModel):
|
|
56
|
+
koi_net: KoiNetConfig
|
|
57
|
+
env: EnvConfig = EnvConfig()
|
|
58
|
+
|
|
59
|
+
@model_validator(mode="after")
|
|
60
|
+
def generate_rid_cascade(self):
|
|
61
|
+
if not self.koi_net.node_rid:
|
|
62
|
+
priv_key = PrivateKey.generate()
|
|
63
|
+
pub_key = priv_key.public_key()
|
|
64
|
+
|
|
65
|
+
self.koi_net.node_rid = pub_key.to_node_rid(self.koi_net.node_name)
|
|
66
|
+
|
|
67
|
+
with open(self.koi_net.private_key_pem_path, "w") as f:
|
|
68
|
+
f.write(priv_key.to_pem(self.env.priv_key_password))
|
|
69
|
+
|
|
70
|
+
self.koi_net.node_profile.public_key = pub_key.to_der()
|
|
71
|
+
return self
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from pydantic import BaseModel, model_validator
|
|
2
|
+
from koi_net.config.core import NodeConfig, KoiNetConfig as BaseKoiNetConfig
|
|
3
|
+
from ..protocol.node import NodeProfile as BaseNodeProfile, NodeType, NodeProvides
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NodeProfile(BaseNodeProfile):
|
|
7
|
+
node_type: NodeType = NodeType.FULL
|
|
8
|
+
|
|
9
|
+
class KoiNetConfig(BaseKoiNetConfig):
|
|
10
|
+
node_profile: NodeProfile
|
|
11
|
+
|
|
12
|
+
class ServerConfig(BaseModel):
|
|
13
|
+
"""Config for the node server (full node only)."""
|
|
14
|
+
|
|
15
|
+
host: str = "127.0.0.1"
|
|
16
|
+
port: int = 8000
|
|
17
|
+
path: str | None = "/koi-net"
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def url(self) -> str:
|
|
21
|
+
return f"http://{self.host}:{self.port}{self.path or ''}"
|
|
22
|
+
|
|
23
|
+
class FullNodeConfig(NodeConfig):
|
|
24
|
+
koi_net: KoiNetConfig
|
|
25
|
+
server: ServerConfig = ServerConfig()
|
|
26
|
+
|
|
27
|
+
@model_validator(mode="after")
|
|
28
|
+
def check_url(self):
|
|
29
|
+
if not self.koi_net.node_profile.base_url:
|
|
30
|
+
self.koi_net.node_profile.base_url = self.server.url
|
|
31
|
+
return self
|
koi_net/config/loader.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from ruamel.yaml import YAML
|
|
2
|
+
from .core import NodeConfig
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ConfigLoader:
|
|
6
|
+
_config: NodeConfig
|
|
7
|
+
|
|
8
|
+
_file_path: str = "config.yaml"
|
|
9
|
+
_file_content: str
|
|
10
|
+
|
|
11
|
+
def __init__(self, config_cls: type[NodeConfig]):
|
|
12
|
+
self._config_cls = config_cls
|
|
13
|
+
self.load_from_yaml()
|
|
14
|
+
|
|
15
|
+
def __getattr__(self, name):
|
|
16
|
+
return getattr(self._config, name)
|
|
17
|
+
|
|
18
|
+
def load_from_yaml(self):
|
|
19
|
+
"""Loads config state from YAML file."""
|
|
20
|
+
yaml = YAML()
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
with open(self._file_path, "r") as f:
|
|
24
|
+
self._file_content = f.read()
|
|
25
|
+
config_data = yaml.load(self._file_content)
|
|
26
|
+
self._config = self._config_cls.model_validate(config_data)
|
|
27
|
+
|
|
28
|
+
except FileNotFoundError:
|
|
29
|
+
self._config = self._config_cls()
|
|
30
|
+
|
|
31
|
+
self.save_to_yaml()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def save_to_yaml(self):
|
|
35
|
+
yaml = YAML()
|
|
36
|
+
|
|
37
|
+
with open(self._file_path, "w") as f:
|
|
38
|
+
try:
|
|
39
|
+
config_data = self._config.model_dump(mode="json")
|
|
40
|
+
yaml.dump(config_data, f)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
if self._file_content:
|
|
43
|
+
f.seek(0)
|
|
44
|
+
f.truncate()
|
|
45
|
+
f.write(self._file_content)
|
|
46
|
+
raise e
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
from koi_net.config.core import NodeConfig, KoiNetConfig
|
|
3
|
+
from ..protocol.node import NodeProfile, NodeType, NodeProvides
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NodeProfile(NodeProfile):
|
|
7
|
+
base_url: str | None = None
|
|
8
|
+
node_type: NodeType = NodeType.PARTIAL
|
|
9
|
+
|
|
10
|
+
class KoiNetConfig(KoiNetConfig):
|
|
11
|
+
node_profile: NodeProfile
|
|
12
|
+
|
|
13
|
+
class PollerConfig(BaseModel):
|
|
14
|
+
polling_interval: int = 5
|
|
15
|
+
|
|
16
|
+
class PartialNodeConfig(NodeConfig):
|
|
17
|
+
koi_net: KoiNetConfig
|
|
18
|
+
poller: PollerConfig = PollerConfig()
|
koi_net/core.py
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
1
|
from rid_lib.ext import Cache
|
|
3
|
-
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
from
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from
|
|
19
|
-
from
|
|
2
|
+
|
|
3
|
+
from .config.loader import ConfigLoader
|
|
4
|
+
from .assembler import NodeAssembler
|
|
5
|
+
from .config.core import NodeConfig
|
|
6
|
+
from .processor.context import HandlerContext
|
|
7
|
+
from .effector import Effector
|
|
8
|
+
from .handshaker import Handshaker
|
|
9
|
+
from .identity import NodeIdentity
|
|
10
|
+
from .workers import KnowledgeProcessingWorker, EventProcessingWorker
|
|
11
|
+
from .lifecycle import NodeLifecycle
|
|
12
|
+
from .network.error_handler import ErrorHandler
|
|
13
|
+
from .network.event_queue import EventQueue
|
|
14
|
+
from .network.graph import NetworkGraph
|
|
15
|
+
from .network.request_handler import RequestHandler
|
|
16
|
+
from .network.resolver import NetworkResolver
|
|
17
|
+
from .network.response_handler import ResponseHandler
|
|
18
|
+
from .network.poll_event_buffer import PollEventBuffer
|
|
19
|
+
from .processor.pipeline import KnowledgePipeline
|
|
20
|
+
from .processor.kobj_queue import KobjQueue
|
|
21
|
+
from .secure import Secure
|
|
22
|
+
from .entrypoints import NodeServer, NodePoller
|
|
23
|
+
from .processor.knowledge_handlers import (
|
|
20
24
|
basic_manifest_handler,
|
|
21
25
|
basic_network_output_filter,
|
|
22
26
|
basic_rid_handler,
|
|
@@ -25,50 +29,14 @@ from koi_net.processor.default_handlers import (
|
|
|
25
29
|
forget_edge_on_node_deletion,
|
|
26
30
|
secure_profile_handler
|
|
27
31
|
)
|
|
28
|
-
from koi_net.processor.event_worker import EventProcessingWorker
|
|
29
|
-
from koi_net.processor.knowledge_pipeline import KnowledgePipeline
|
|
30
|
-
from koi_net.processor.kobj_queue import KobjQueue
|
|
31
|
-
from koi_net.secure import Secure
|
|
32
|
-
from koi_net.server import NodeServer
|
|
33
|
-
|
|
34
32
|
|
|
35
|
-
@dataclass
|
|
36
|
-
class NodeContainer:
|
|
37
|
-
poll_event_buf: PollEventBuffer
|
|
38
|
-
kobj_queue: KobjQueue
|
|
39
|
-
event_queue: EventQueue
|
|
40
|
-
config: NodeConfig
|
|
41
|
-
cache: Cache
|
|
42
|
-
identity: NodeIdentity
|
|
43
|
-
graph: NetworkGraph
|
|
44
|
-
secure: Secure
|
|
45
|
-
request_handler: RequestHandler
|
|
46
|
-
response_handler: ResponseHandler
|
|
47
|
-
resolver: NetworkResolver
|
|
48
|
-
handler_context: HandlerContext
|
|
49
|
-
behaviors: Behaviors
|
|
50
|
-
pipeline: KnowledgePipeline
|
|
51
|
-
kobj_worker: KnowledgeProcessingWorker
|
|
52
|
-
event_worker: EventProcessingWorker
|
|
53
|
-
error_handler: ErrorHandler
|
|
54
|
-
lifecycle: NodeLifecycle
|
|
55
|
-
server: NodeServer
|
|
56
|
-
poller: NodePoller
|
|
57
|
-
|
|
58
33
|
|
|
59
|
-
class NodeAssembler:
|
|
60
|
-
|
|
34
|
+
class BaseNode(NodeAssembler):
|
|
35
|
+
config_cls = NodeConfig
|
|
61
36
|
kobj_queue = KobjQueue
|
|
62
37
|
event_queue = EventQueue
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
identity = NodeIdentity
|
|
66
|
-
graph = NetworkGraph
|
|
67
|
-
secure = Secure
|
|
68
|
-
handshaker = Handshaker
|
|
69
|
-
request_handler = RequestHandler
|
|
70
|
-
response_handler = ResponseHandler
|
|
71
|
-
resolver = NetworkResolver
|
|
38
|
+
poll_event_buf = PollEventBuffer
|
|
39
|
+
config = ConfigLoader
|
|
72
40
|
knowledge_handlers = [
|
|
73
41
|
basic_rid_handler,
|
|
74
42
|
basic_manifest_handler,
|
|
@@ -78,156 +46,25 @@ class NodeAssembler:
|
|
|
78
46
|
basic_network_output_filter,
|
|
79
47
|
forget_edge_on_node_deletion
|
|
80
48
|
]
|
|
81
|
-
|
|
82
|
-
|
|
49
|
+
cache = lambda config: Cache(
|
|
50
|
+
directory_path=config.koi_net.cache_directory_path)
|
|
51
|
+
identity = NodeIdentity
|
|
52
|
+
graph = NetworkGraph
|
|
53
|
+
secure = Secure
|
|
54
|
+
handshaker = Handshaker
|
|
55
|
+
error_handler = ErrorHandler
|
|
56
|
+
request_handler = RequestHandler
|
|
57
|
+
response_handler = ResponseHandler
|
|
58
|
+
resolver = NetworkResolver
|
|
83
59
|
effector = Effector
|
|
84
|
-
|
|
60
|
+
handler_context = HandlerContext
|
|
85
61
|
pipeline = KnowledgePipeline
|
|
86
62
|
kobj_worker = KnowledgeProcessingWorker
|
|
87
63
|
event_worker = EventProcessingWorker
|
|
88
|
-
error_handler = ErrorHandler
|
|
89
64
|
lifecycle = NodeLifecycle
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
kobj_queue = cls.kobj_queue()
|
|
97
|
-
event_queue = cls.event_queue()
|
|
98
|
-
config = cls.config.load_from_yaml()
|
|
99
|
-
cache = cls.cache(
|
|
100
|
-
directory_path=config.koi_net.cache_directory_path
|
|
101
|
-
)
|
|
102
|
-
identity = cls.identity(
|
|
103
|
-
config=config
|
|
104
|
-
)
|
|
105
|
-
graph = cls.graph(
|
|
106
|
-
cache=cache,
|
|
107
|
-
identity=identity
|
|
108
|
-
)
|
|
109
|
-
secure = cls.secure(
|
|
110
|
-
identity=identity,
|
|
111
|
-
cache=cache,
|
|
112
|
-
config=config
|
|
113
|
-
)
|
|
114
|
-
handshaker = cls.handshaker(
|
|
115
|
-
cache=cache,
|
|
116
|
-
identity=identity,
|
|
117
|
-
event_queue=event_queue
|
|
118
|
-
)
|
|
119
|
-
error_handler = cls.error_handler(
|
|
120
|
-
kobj_queue=kobj_queue,
|
|
121
|
-
handshaker=handshaker
|
|
122
|
-
)
|
|
123
|
-
request_handler = cls.request_handler(
|
|
124
|
-
cache=cache,
|
|
125
|
-
identity=identity,
|
|
126
|
-
secure=secure,
|
|
127
|
-
error_handler=error_handler
|
|
128
|
-
)
|
|
129
|
-
response_handler = cls.response_handler(
|
|
130
|
-
cache=cache
|
|
131
|
-
)
|
|
132
|
-
resolver = cls.resolver(
|
|
133
|
-
config=config,
|
|
134
|
-
cache=cache,
|
|
135
|
-
identity=identity,
|
|
136
|
-
graph=graph,
|
|
137
|
-
request_handler=request_handler
|
|
138
|
-
)
|
|
139
|
-
handler_context = cls.handler_context(
|
|
140
|
-
identity=identity,
|
|
141
|
-
config=config,
|
|
142
|
-
cache=cache,
|
|
143
|
-
event_queue=event_queue,
|
|
144
|
-
kobj_queue=kobj_queue,
|
|
145
|
-
graph=graph,
|
|
146
|
-
request_handler=request_handler,
|
|
147
|
-
resolver=resolver
|
|
148
|
-
)
|
|
149
|
-
action_context = cls.action_context(
|
|
150
|
-
identity=identity
|
|
151
|
-
)
|
|
152
|
-
effector = cls.effector(
|
|
153
|
-
cache=cache,
|
|
154
|
-
resolver=resolver,
|
|
155
|
-
kobj_queue=kobj_queue,
|
|
156
|
-
action_context=action_context
|
|
157
|
-
)
|
|
158
|
-
behaviors = cls.behaviors(
|
|
159
|
-
cache=cache,
|
|
160
|
-
identity=identity,
|
|
161
|
-
event_queue=event_queue,
|
|
162
|
-
resolver=resolver,
|
|
163
|
-
request_handler=request_handler,
|
|
164
|
-
kobj_queue=kobj_queue
|
|
165
|
-
)
|
|
166
|
-
pipeline = cls.pipeline(
|
|
167
|
-
handler_context=handler_context,
|
|
168
|
-
cache=cache,
|
|
169
|
-
request_handler=request_handler,
|
|
170
|
-
event_queue=event_queue,
|
|
171
|
-
graph=graph,
|
|
172
|
-
knowledge_handlers=cls.knowledge_handlers
|
|
173
|
-
)
|
|
174
|
-
kobj_worker = cls.kobj_worker(
|
|
175
|
-
kobj_queue=kobj_queue,
|
|
176
|
-
pipeline=pipeline
|
|
177
|
-
)
|
|
178
|
-
event_worker = cls.event_worker(
|
|
179
|
-
config=config,
|
|
180
|
-
cache=cache,
|
|
181
|
-
event_queue=event_queue,
|
|
182
|
-
request_handler=request_handler,
|
|
183
|
-
poll_event_buf=poll_event_buffer
|
|
184
|
-
)
|
|
185
|
-
lifecycle = cls.lifecycle(
|
|
186
|
-
config=config,
|
|
187
|
-
identity=identity,
|
|
188
|
-
graph=graph,
|
|
189
|
-
kobj_queue=kobj_queue,
|
|
190
|
-
kobj_worker=kobj_worker,
|
|
191
|
-
event_queue=event_queue,
|
|
192
|
-
event_worker=event_worker,
|
|
193
|
-
cache=cache,
|
|
194
|
-
handshaker=handshaker,
|
|
195
|
-
behaviors=behaviors
|
|
196
|
-
)
|
|
197
|
-
server = cls.server(
|
|
198
|
-
config=config,
|
|
199
|
-
lifecycle=lifecycle,
|
|
200
|
-
secure=secure,
|
|
201
|
-
kobj_queue=kobj_queue,
|
|
202
|
-
response_handler=response_handler,
|
|
203
|
-
poll_event_buf=poll_event_buffer
|
|
204
|
-
)
|
|
205
|
-
poller = cls.poller(
|
|
206
|
-
kobj_queue=kobj_queue,
|
|
207
|
-
lifecycle=lifecycle,
|
|
208
|
-
resolver=resolver,
|
|
209
|
-
config=config
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
return NodeContainer(
|
|
213
|
-
poll_event_buf=poll_event_buffer,
|
|
214
|
-
kobj_queue=kobj_queue,
|
|
215
|
-
event_queue=event_queue,
|
|
216
|
-
config=config,
|
|
217
|
-
cache=cache,
|
|
218
|
-
identity=identity,
|
|
219
|
-
graph=graph,
|
|
220
|
-
secure=secure,
|
|
221
|
-
request_handler=request_handler,
|
|
222
|
-
response_handler=response_handler,
|
|
223
|
-
resolver=resolver,
|
|
224
|
-
handler_context=handler_context,
|
|
225
|
-
behaviors=behaviors,
|
|
226
|
-
pipeline=pipeline,
|
|
227
|
-
kobj_worker=kobj_worker,
|
|
228
|
-
event_worker=event_worker,
|
|
229
|
-
error_handler=error_handler,
|
|
230
|
-
lifecycle=lifecycle,
|
|
231
|
-
server=server,
|
|
232
|
-
poller=poller
|
|
233
|
-
)
|
|
65
|
+
|
|
66
|
+
class FullNode(BaseNode):
|
|
67
|
+
entrypoint = NodeServer
|
|
68
|
+
|
|
69
|
+
class PartialNode(BaseNode):
|
|
70
|
+
entrypoint = NodePoller
|
koi_net/default_actions.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"""Implementations of default dereference actions."""
|
|
2
2
|
|
|
3
|
-
from .context import ActionContext
|
|
4
3
|
from rid_lib.types import KoiNetNode
|
|
5
4
|
from rid_lib.ext import Bundle
|
|
6
|
-
from .effector import Effector
|
|
5
|
+
from .effector import Effector, ActionContext
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
@Effector.register_default_action(KoiNetNode)
|
koi_net/effector.py
CHANGED
|
@@ -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
|
|
@@ -143,7 +155,7 @@ class Effector:
|
|
|
143
155
|
and bundle is not None
|
|
144
156
|
and source != BundleSource.CACHE
|
|
145
157
|
):
|
|
146
|
-
self.kobj_queue.
|
|
158
|
+
self.kobj_queue.push(
|
|
147
159
|
bundle=bundle,
|
|
148
160
|
source=source if type(source) is KoiNetNode else None
|
|
149
161
|
)
|