koi-net 1.0.0b19__tar.gz → 1.1.0__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.
- {koi_net-1.0.0b19 → koi_net-1.1.0}/.gitignore +2 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/PKG-INFO +5 -4
- koi_net-1.1.0/examples/coordinator.py +76 -0
- koi_net-1.1.0/examples/partial.py +37 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/pyproject.toml +6 -5
- koi_net-1.1.0/src/koi_net/actor.py +60 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/config.py +44 -18
- koi_net-1.1.0/src/koi_net/context.py +63 -0
- koi_net-1.1.0/src/koi_net/core.py +194 -0
- koi_net-1.1.0/src/koi_net/default_actions.py +15 -0
- koi_net-1.1.0/src/koi_net/effector.py +139 -0
- koi_net-1.1.0/src/koi_net/identity.py +24 -0
- koi_net-1.1.0/src/koi_net/lifecycle.py +104 -0
- koi_net-1.1.0/src/koi_net/network/error_handler.py +50 -0
- koi_net-1.1.0/src/koi_net/network/event_queue.py +199 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/network/graph.py +23 -38
- koi_net-1.1.0/src/koi_net/network/request_handler.py +212 -0
- koi_net-1.1.0/src/koi_net/network/resolver.py +150 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/network/response_handler.py +15 -6
- koi_net-1.1.0/src/koi_net/poller.py +40 -0
- koi_net-1.1.0/src/koi_net/processor/__init__.py +0 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/processor/default_handlers.py +71 -42
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/processor/handler.py +3 -7
- koi_net-1.1.0/src/koi_net/processor/interface.py +101 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/processor/knowledge_object.py +10 -17
- koi_net-1.0.0b19/src/koi_net/processor/interface.py → koi_net-1.1.0/src/koi_net/processor/knowledge_pipeline.py +63 -143
- koi_net-1.1.0/src/koi_net/protocol/__init__.py +0 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/protocol/api_models.py +18 -3
- koi_net-1.1.0/src/koi_net/protocol/edge.py +45 -0
- koi_net-1.1.0/src/koi_net/protocol/envelope.py +58 -0
- koi_net-1.1.0/src/koi_net/protocol/errors.py +23 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/protocol/event.py +0 -3
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/protocol/node.py +2 -1
- koi_net-1.1.0/src/koi_net/protocol/secure.py +160 -0
- koi_net-1.1.0/src/koi_net/secure.py +117 -0
- koi_net-1.1.0/src/koi_net/server.py +129 -0
- koi_net-1.1.0/uv.lock +1011 -0
- koi_net-1.0.0b19/examples/basic_coordinator_node.py +0 -141
- koi_net-1.0.0b19/examples/basic_partial_node.py +0 -46
- koi_net-1.0.0b19/src/koi_net/core.py +0 -126
- koi_net-1.0.0b19/src/koi_net/identity.py +0 -42
- koi_net-1.0.0b19/src/koi_net/network/__init__.py +0 -1
- koi_net-1.0.0b19/src/koi_net/network/interface.py +0 -276
- koi_net-1.0.0b19/src/koi_net/network/request_handler.py +0 -149
- koi_net-1.0.0b19/src/koi_net/processor/__init__.py +0 -1
- koi_net-1.0.0b19/src/koi_net/protocol/edge.py +0 -20
- koi_net-1.0.0b19/src/koi_net/protocol/helpers.py +0 -25
- {koi_net-1.0.0b19 → koi_net-1.1.0}/.github/workflows/publish-to-pypi.yml +0 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/LICENSE +0 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/README.md +0 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/requirements.txt +0 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/__init__.py +0 -0
- {koi_net-1.0.0b19/src/koi_net/protocol → koi_net-1.1.0/src/koi_net/network}/__init__.py +0 -0
- {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/protocol/consts.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: koi-net
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
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>
|
|
@@ -27,19 +27,20 @@ License: MIT License
|
|
|
27
27
|
SOFTWARE.
|
|
28
28
|
License-File: LICENSE
|
|
29
29
|
Requires-Python: >=3.10
|
|
30
|
+
Requires-Dist: cryptography>=45.0.3
|
|
31
|
+
Requires-Dist: fastapi>=0.115.12
|
|
30
32
|
Requires-Dist: httpx>=0.28.1
|
|
31
33
|
Requires-Dist: networkx>=3.4.2
|
|
32
34
|
Requires-Dist: pydantic>=2.10.6
|
|
33
35
|
Requires-Dist: python-dotenv>=1.1.0
|
|
34
|
-
Requires-Dist: rid-lib>=3.2.
|
|
36
|
+
Requires-Dist: rid-lib>=3.2.7
|
|
35
37
|
Requires-Dist: ruamel-yaml>=0.18.10
|
|
38
|
+
Requires-Dist: uvicorn>=0.34.2
|
|
36
39
|
Provides-Extra: dev
|
|
37
40
|
Requires-Dist: build; extra == 'dev'
|
|
38
41
|
Requires-Dist: twine>=6.0; extra == 'dev'
|
|
39
42
|
Provides-Extra: examples
|
|
40
|
-
Requires-Dist: fastapi; extra == 'examples'
|
|
41
43
|
Requires-Dist: rich; extra == 'examples'
|
|
42
|
-
Requires-Dist: uvicorn; extra == 'examples'
|
|
43
44
|
Description-Content-Type: text/markdown
|
|
44
45
|
|
|
45
46
|
# KOI-net
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from rich.logging import RichHandler
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
from rid_lib.types import KoiNetNode, KoiNetEdge
|
|
5
|
+
from koi_net.config import NodeConfig, KoiNetConfig
|
|
6
|
+
from koi_net.protocol.node import NodeProfile, NodeProvides, NodeType
|
|
7
|
+
from koi_net import NodeInterface
|
|
8
|
+
from koi_net.context import HandlerContext
|
|
9
|
+
from koi_net.processor.handler import HandlerType
|
|
10
|
+
from koi_net.processor.knowledge_object import KnowledgeObject
|
|
11
|
+
from koi_net.protocol.event import Event, EventType
|
|
12
|
+
from koi_net.protocol.edge import EdgeType, generate_edge_bundle
|
|
13
|
+
|
|
14
|
+
logging.basicConfig(
|
|
15
|
+
level=logging.INFO,
|
|
16
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
17
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
18
|
+
handlers=[RichHandler()]
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
logging.getLogger("koi_net").setLevel(logging.DEBUG)
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
class CoordinatorConfig(NodeConfig):
|
|
25
|
+
koi_net: KoiNetConfig = Field(default_factory = lambda:
|
|
26
|
+
KoiNetConfig(
|
|
27
|
+
node_name="coordinator",
|
|
28
|
+
node_profile=NodeProfile(
|
|
29
|
+
node_type=NodeType.FULL,
|
|
30
|
+
provides=NodeProvides(
|
|
31
|
+
event=[KoiNetNode, KoiNetEdge],
|
|
32
|
+
state=[KoiNetNode, KoiNetEdge]
|
|
33
|
+
)
|
|
34
|
+
),
|
|
35
|
+
cache_directory_path=".coordinator_rid_cache",
|
|
36
|
+
event_queues_path="coordinator_event_queues.json",
|
|
37
|
+
private_key_pem_path="coordinator_priv_key.pem"
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
node = NodeInterface(
|
|
42
|
+
config=CoordinatorConfig.load_from_yaml("coordinator_config.yaml"),
|
|
43
|
+
use_kobj_processor_thread=True
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
@node.processor.pipeline.register_handler(HandlerType.Network, rid_types=[KoiNetNode])
|
|
47
|
+
def handshake_handler(ctx: HandlerContext, kobj: KnowledgeObject):
|
|
48
|
+
logger.info("Handling node handshake")
|
|
49
|
+
|
|
50
|
+
# only respond if node declares itself as NEW
|
|
51
|
+
if kobj.event_type != EventType.NEW:
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
logger.info("Sharing this node's bundle with peer")
|
|
55
|
+
identity_bundle = ctx.effector.deref(ctx.identity.rid)
|
|
56
|
+
ctx.event_queue.push_event_to(
|
|
57
|
+
event=Event.from_bundle(EventType.NEW, identity_bundle),
|
|
58
|
+
node=kobj.rid,
|
|
59
|
+
flush=True
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
logger.info("Proposing new edge")
|
|
63
|
+
# defer handling of proposed edge
|
|
64
|
+
|
|
65
|
+
edge_bundle = generate_edge_bundle(
|
|
66
|
+
source=kobj.rid,
|
|
67
|
+
target=ctx.identity.rid,
|
|
68
|
+
edge_type=EdgeType.WEBHOOK,
|
|
69
|
+
rid_types=[KoiNetNode, KoiNetEdge]
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
ctx.handle(rid=edge_bundle.rid, event_type=EventType.FORGET)
|
|
73
|
+
ctx.handle(bundle=edge_bundle)
|
|
74
|
+
|
|
75
|
+
if __name__ == "__main__":
|
|
76
|
+
node.server.run()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
from rich.logging import RichHandler
|
|
4
|
+
from koi_net import NodeInterface
|
|
5
|
+
from koi_net.protocol.node import NodeProfile, NodeType
|
|
6
|
+
from koi_net.config import NodeConfig, KoiNetConfig
|
|
7
|
+
|
|
8
|
+
logging.basicConfig(
|
|
9
|
+
level=logging.INFO,
|
|
10
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
11
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
12
|
+
handlers=[RichHandler()]
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
logging.getLogger("koi_net").setLevel(logging.DEBUG)
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PartialNodeConfig(NodeConfig):
|
|
20
|
+
koi_net: KoiNetConfig = Field(default_factory = lambda:
|
|
21
|
+
KoiNetConfig(
|
|
22
|
+
node_name="partial",
|
|
23
|
+
node_profile=NodeProfile(
|
|
24
|
+
node_type=NodeType.PARTIAL
|
|
25
|
+
),
|
|
26
|
+
cache_directory_path=".partial_rid_cache",
|
|
27
|
+
event_queues_path="partial_event_queues.json",
|
|
28
|
+
private_key_pem_path="partial_priv_key.pem"
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
node = NodeInterface(
|
|
33
|
+
config=PartialNodeConfig.load_from_yaml("partial_config.yaml")
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__":
|
|
37
|
+
node.poller.run()
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "koi-net"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.1.0"
|
|
8
8
|
description = "Implementation of KOI-net protocol in Python"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Luke Miller", email = "luke@block.science"}
|
|
@@ -13,20 +13,21 @@ readme = "README.md"
|
|
|
13
13
|
requires-python = ">=3.10"
|
|
14
14
|
license = {file = "LICENSE"}
|
|
15
15
|
dependencies = [
|
|
16
|
-
"rid-lib>=3.2.
|
|
16
|
+
"rid-lib>=3.2.7",
|
|
17
17
|
"networkx>=3.4.2",
|
|
18
18
|
"httpx>=0.28.1",
|
|
19
19
|
"pydantic>=2.10.6",
|
|
20
20
|
"ruamel.yaml>=0.18.10",
|
|
21
|
-
"python-dotenv>=1.1.0"
|
|
21
|
+
"python-dotenv>=1.1.0",
|
|
22
|
+
"cryptography>=45.0.3",
|
|
23
|
+
"fastapi>=0.115.12",
|
|
24
|
+
"uvicorn>=0.34.2"
|
|
22
25
|
]
|
|
23
26
|
|
|
24
27
|
[project.optional-dependencies]
|
|
25
28
|
dev = ["twine>=6.0", "build"]
|
|
26
29
|
examples = [
|
|
27
30
|
"rich",
|
|
28
|
-
"fastapi",
|
|
29
|
-
"uvicorn"
|
|
30
31
|
]
|
|
31
32
|
|
|
32
33
|
[project.urls]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from logging import getLogger
|
|
2
|
+
from rid_lib.types import KoiNetNode
|
|
3
|
+
from rid_lib import RIDType
|
|
4
|
+
from koi_net.context import HandlerContext
|
|
5
|
+
from koi_net.protocol.api_models import ErrorResponse
|
|
6
|
+
from .protocol.event import Event, EventType
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
logger = getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Actor:
|
|
13
|
+
ctx: HandlerContext
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
def set_ctx(self, ctx: HandlerContext):
|
|
19
|
+
self.ctx = ctx
|
|
20
|
+
|
|
21
|
+
def handshake_with(self, target: KoiNetNode):
|
|
22
|
+
logger.debug(f"Initiating handshake with {target}")
|
|
23
|
+
self.ctx.event_queue.push_event_to(
|
|
24
|
+
Event.from_rid(
|
|
25
|
+
event_type=EventType.FORGET,
|
|
26
|
+
rid=self.ctx.identity.rid),
|
|
27
|
+
node=target
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
self.ctx.event_queue.push_event_to(
|
|
31
|
+
event=Event.from_bundle(
|
|
32
|
+
event_type=EventType.NEW,
|
|
33
|
+
bundle=self.ctx.effector.deref(self.ctx.identity.rid)),
|
|
34
|
+
node=target
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
self.ctx.event_queue.flush_webhook_queue(target)
|
|
38
|
+
|
|
39
|
+
def identify_coordinators(self):
|
|
40
|
+
return self.ctx.resolver.get_state_providers(KoiNetNode)
|
|
41
|
+
|
|
42
|
+
def catch_up_with(self, target: KoiNetNode, rid_types: list[RIDType] = []):
|
|
43
|
+
logger.debug(f"catching up with {target} on {rid_types or 'all types'}")
|
|
44
|
+
|
|
45
|
+
payload = self.ctx.request_handler.fetch_manifests(
|
|
46
|
+
node=target,
|
|
47
|
+
rid_types=rid_types
|
|
48
|
+
)
|
|
49
|
+
if type(payload) == ErrorResponse:
|
|
50
|
+
logger.debug("failed to reach node")
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
for manifest in payload.manifests:
|
|
54
|
+
if manifest.rid == self.ctx.identity.rid:
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
self.ctx.handle(
|
|
58
|
+
manifest=manifest,
|
|
59
|
+
source=target
|
|
60
|
+
)
|
|
@@ -1,32 +1,43 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from typing import TypeVar
|
|
3
2
|
from ruamel.yaml import YAML
|
|
4
|
-
from koi_net.protocol.node import NodeProfile
|
|
5
|
-
from rid_lib.types import KoiNetNode
|
|
6
3
|
from pydantic import BaseModel, Field, PrivateAttr
|
|
7
4
|
from dotenv import load_dotenv
|
|
5
|
+
from rid_lib.ext.utils import sha256_hash
|
|
6
|
+
from rid_lib.types import KoiNetNode
|
|
7
|
+
from .protocol.secure import PrivateKey
|
|
8
|
+
from .protocol.node import NodeProfile, NodeType
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class ServerConfig(BaseModel):
|
|
11
|
-
host: str
|
|
12
|
-
port: int
|
|
12
|
+
host: str = "127.0.0.1"
|
|
13
|
+
port: int = 8000
|
|
13
14
|
path: str | None = "/koi-net"
|
|
14
15
|
|
|
15
16
|
@property
|
|
16
17
|
def url(self) -> str:
|
|
17
18
|
return f"http://{self.host}:{self.port}{self.path or ''}"
|
|
18
19
|
|
|
20
|
+
class NodeContact(BaseModel):
|
|
21
|
+
rid: KoiNetNode | None = None
|
|
22
|
+
url: str | None = None
|
|
23
|
+
|
|
19
24
|
class KoiNetConfig(BaseModel):
|
|
20
25
|
node_name: str
|
|
21
26
|
node_rid: KoiNetNode | None = None
|
|
22
27
|
node_profile: NodeProfile
|
|
23
28
|
|
|
24
|
-
cache_directory_path: str
|
|
25
|
-
event_queues_path: str
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
cache_directory_path: str = ".rid_cache"
|
|
30
|
+
event_queues_path: str = "event_queues.json"
|
|
31
|
+
private_key_pem_path: str = "priv_key.pem"
|
|
32
|
+
polling_interval: int = 5
|
|
33
|
+
|
|
34
|
+
first_contact: NodeContact = Field(default_factory=NodeContact)
|
|
35
|
+
|
|
36
|
+
_priv_key: PrivateKey | None = PrivateAttr(default=None)
|
|
28
37
|
|
|
29
38
|
class EnvConfig(BaseModel):
|
|
39
|
+
priv_key_password: str | None = "PRIV_KEY_PASSWORD"
|
|
40
|
+
|
|
30
41
|
def __init__(self, **kwargs):
|
|
31
42
|
super().__init__(**kwargs)
|
|
32
43
|
load_dotenv()
|
|
@@ -41,8 +52,10 @@ class EnvConfig(BaseModel):
|
|
|
41
52
|
return value
|
|
42
53
|
|
|
43
54
|
class NodeConfig(BaseModel):
|
|
44
|
-
server: ServerConfig
|
|
55
|
+
server: ServerConfig = Field(default_factory=ServerConfig)
|
|
45
56
|
koi_net: KoiNetConfig
|
|
57
|
+
env: EnvConfig = Field(default_factory=EnvConfig)
|
|
58
|
+
|
|
46
59
|
_file_path: str = PrivateAttr(default="config.yaml")
|
|
47
60
|
_file_content: str | None = PrivateAttr(default=None)
|
|
48
61
|
|
|
@@ -72,13 +85,27 @@ class NodeConfig(BaseModel):
|
|
|
72
85
|
|
|
73
86
|
config._file_path = file_path
|
|
74
87
|
|
|
75
|
-
if generate_missing:
|
|
76
|
-
config.koi_net.node_rid
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
config.koi_net.
|
|
81
|
-
|
|
88
|
+
if generate_missing:
|
|
89
|
+
if not config.koi_net.node_rid:
|
|
90
|
+
priv_key = PrivateKey.generate()
|
|
91
|
+
pub_key = priv_key.public_key()
|
|
92
|
+
|
|
93
|
+
config.koi_net.node_rid = KoiNetNode(
|
|
94
|
+
config.koi_net.node_name,
|
|
95
|
+
sha256_hash(pub_key.to_der())
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
with open(config.koi_net.private_key_pem_path, "w") as f:
|
|
99
|
+
f.write(
|
|
100
|
+
priv_key.to_pem(config.env.priv_key_password)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
config.koi_net.node_profile.public_key = pub_key.to_der()
|
|
104
|
+
|
|
105
|
+
if config.koi_net.node_profile.node_type == NodeType.FULL:
|
|
106
|
+
config.koi_net.node_profile.base_url = (
|
|
107
|
+
config.koi_net.node_profile.base_url or config.server.url
|
|
108
|
+
)
|
|
82
109
|
|
|
83
110
|
config.save_to_yaml()
|
|
84
111
|
|
|
@@ -98,4 +125,3 @@ class NodeConfig(BaseModel):
|
|
|
98
125
|
f.write(self._file_content)
|
|
99
126
|
raise e
|
|
100
127
|
|
|
101
|
-
ConfigType = TypeVar("ConfigType", bound=NodeConfig)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from rid_lib.ext import Cache
|
|
2
|
+
|
|
3
|
+
from koi_net.network.resolver import NetworkResolver
|
|
4
|
+
from .config import NodeConfig
|
|
5
|
+
from .effector import Effector
|
|
6
|
+
from .network.graph import NetworkGraph
|
|
7
|
+
from .network.event_queue import NetworkEventQueue
|
|
8
|
+
from .network.request_handler import RequestHandler
|
|
9
|
+
from .identity import NodeIdentity
|
|
10
|
+
from .processor.interface import ProcessorInterface
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ActionContext:
|
|
14
|
+
identity: NodeIdentity
|
|
15
|
+
effector: Effector
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
identity: NodeIdentity,
|
|
20
|
+
effector: Effector
|
|
21
|
+
):
|
|
22
|
+
self.identity = identity
|
|
23
|
+
self.effector = effector
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class HandlerContext:
|
|
27
|
+
identity: NodeIdentity
|
|
28
|
+
config: NodeConfig
|
|
29
|
+
cache: Cache
|
|
30
|
+
event_queue: NetworkEventQueue
|
|
31
|
+
graph: NetworkGraph
|
|
32
|
+
request_handler: RequestHandler
|
|
33
|
+
resolver: NetworkResolver
|
|
34
|
+
effector: Effector
|
|
35
|
+
_processor: ProcessorInterface | None
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
identity: NodeIdentity,
|
|
40
|
+
config: NodeConfig,
|
|
41
|
+
cache: Cache,
|
|
42
|
+
event_queue: NetworkEventQueue,
|
|
43
|
+
graph: NetworkGraph,
|
|
44
|
+
request_handler: RequestHandler,
|
|
45
|
+
resolver: NetworkResolver,
|
|
46
|
+
effector: Effector
|
|
47
|
+
):
|
|
48
|
+
self.identity = identity
|
|
49
|
+
self.config = config
|
|
50
|
+
self.cache = cache
|
|
51
|
+
self.event_queue = event_queue
|
|
52
|
+
self.graph = graph
|
|
53
|
+
self.request_handler = request_handler
|
|
54
|
+
self.resolver = resolver
|
|
55
|
+
self.effector = effector
|
|
56
|
+
self._processor = None
|
|
57
|
+
|
|
58
|
+
def set_processor(self, processor: ProcessorInterface):
|
|
59
|
+
self._processor = processor
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def handle(self):
|
|
63
|
+
return self._processor.handle
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Generic, TypeVar
|
|
3
|
+
from rid_lib.ext import Cache
|
|
4
|
+
from .network.resolver import NetworkResolver
|
|
5
|
+
from .network.event_queue import NetworkEventQueue
|
|
6
|
+
from .network.graph import NetworkGraph
|
|
7
|
+
from .network.request_handler import RequestHandler
|
|
8
|
+
from .network.response_handler import ResponseHandler
|
|
9
|
+
from .network.error_handler import ErrorHandler
|
|
10
|
+
from .actor import Actor
|
|
11
|
+
from .processor.interface import ProcessorInterface
|
|
12
|
+
from .processor import default_handlers
|
|
13
|
+
from .processor.handler import KnowledgeHandler
|
|
14
|
+
from .processor.knowledge_pipeline import KnowledgePipeline
|
|
15
|
+
from .identity import NodeIdentity
|
|
16
|
+
from .secure import Secure
|
|
17
|
+
from .config import NodeConfig
|
|
18
|
+
from .context import HandlerContext, ActionContext
|
|
19
|
+
from .effector import Effector
|
|
20
|
+
from .server import NodeServer
|
|
21
|
+
from .lifecycle import NodeLifecycle
|
|
22
|
+
from .poller import NodePoller
|
|
23
|
+
from . import default_actions
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
T = TypeVar("T", bound=NodeConfig)
|
|
29
|
+
|
|
30
|
+
class NodeInterface(Generic[T]):
|
|
31
|
+
config: T
|
|
32
|
+
cache: Cache
|
|
33
|
+
identity: NodeIdentity
|
|
34
|
+
resolver: NetworkResolver
|
|
35
|
+
event_queue: NetworkEventQueue
|
|
36
|
+
graph: NetworkGraph
|
|
37
|
+
processor: ProcessorInterface
|
|
38
|
+
secure: Secure
|
|
39
|
+
server: NodeServer
|
|
40
|
+
|
|
41
|
+
use_kobj_processor_thread: bool
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
config: T,
|
|
46
|
+
use_kobj_processor_thread: bool = False,
|
|
47
|
+
handlers: list[KnowledgeHandler] | None = None,
|
|
48
|
+
|
|
49
|
+
CacheOverride: type[Cache] | None = None,
|
|
50
|
+
NodeIdentityOverride: type[NodeIdentity] | None = None,
|
|
51
|
+
EffectorOverride: type[Effector] | None = None,
|
|
52
|
+
NetworkGraphOverride: type[NetworkGraph] | None = None,
|
|
53
|
+
SecureOverride: type[Secure] | None = None,
|
|
54
|
+
RequestHandlerOverride: type[RequestHandler] | None = None,
|
|
55
|
+
ResponseHandlerOverride: type[ResponseHandler] | None = None,
|
|
56
|
+
NetworkResolverOverride: type[NetworkResolver] | None = None,
|
|
57
|
+
NetworkEventQueueOverride: type[NetworkEventQueue] | None = None,
|
|
58
|
+
ActorOverride: type[Actor] | None = None,
|
|
59
|
+
ActionContextOverride: type[ActionContext] | None = None,
|
|
60
|
+
HandlerContextOverride: type[HandlerContext] | None = None,
|
|
61
|
+
KnowledgePipelineOverride: type[KnowledgePipeline] | None = None,
|
|
62
|
+
ProcessorInterfaceOverride: type[ProcessorInterface] | None = None,
|
|
63
|
+
ErrorHandlerOverride: type[ErrorHandler] | None = None,
|
|
64
|
+
NodeLifecycleOverride: type[NodeLifecycle] | None = None,
|
|
65
|
+
NodeServerOverride: type[NodeServer] | None = None,
|
|
66
|
+
NodePollerOverride: type[NodePoller] | None = None,
|
|
67
|
+
):
|
|
68
|
+
self.config = config
|
|
69
|
+
self.cache = (CacheOverride or Cache)(
|
|
70
|
+
directory_path=self.config.koi_net.cache_directory_path
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
self.identity = (NodeIdentityOverride or NodeIdentity)(config=self.config)
|
|
74
|
+
self.effector = (EffectorOverride or Effector)(cache=self.cache)
|
|
75
|
+
|
|
76
|
+
self.graph = (NetworkGraphOverride or NetworkGraph)(
|
|
77
|
+
cache=self.cache,
|
|
78
|
+
identity=self.identity
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
self.secure = (SecureOverride or Secure)(
|
|
82
|
+
identity=self.identity,
|
|
83
|
+
effector=self.effector,
|
|
84
|
+
config=self.config
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
self.request_handler = (RequestHandlerOverride or RequestHandler)(
|
|
88
|
+
effector=self.effector,
|
|
89
|
+
identity=self.identity,
|
|
90
|
+
secure=self.secure
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
self.response_handler = (ResponseHandlerOverride or ResponseHandler)(self.cache, self.effector)
|
|
94
|
+
|
|
95
|
+
self.resolver = (NetworkResolverOverride or NetworkResolver)(
|
|
96
|
+
config=self.config,
|
|
97
|
+
cache=self.cache,
|
|
98
|
+
identity=self.identity,
|
|
99
|
+
graph=self.graph,
|
|
100
|
+
request_handler=self.request_handler,
|
|
101
|
+
effector=self.effector
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
self.event_queue = (NetworkEventQueueOverride or NetworkEventQueue)(
|
|
105
|
+
config=self.config,
|
|
106
|
+
cache=self.cache,
|
|
107
|
+
identity=self.identity,
|
|
108
|
+
graph=self.graph,
|
|
109
|
+
request_handler=self.request_handler,
|
|
110
|
+
effector=self.effector
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
self.actor = (ActorOverride or Actor)()
|
|
114
|
+
|
|
115
|
+
# pull all handlers defined in default_handlers module
|
|
116
|
+
if handlers is None:
|
|
117
|
+
handlers = [
|
|
118
|
+
obj for obj in vars(default_handlers).values()
|
|
119
|
+
if isinstance(obj, KnowledgeHandler)
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
self.use_kobj_processor_thread = use_kobj_processor_thread
|
|
123
|
+
|
|
124
|
+
self.action_context = (ActionContextOverride or ActionContext)(
|
|
125
|
+
identity=self.identity,
|
|
126
|
+
effector=self.effector
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
self.handler_context = (HandlerContextOverride or HandlerContext)(
|
|
130
|
+
identity=self.identity,
|
|
131
|
+
config=self.config,
|
|
132
|
+
cache=self.cache,
|
|
133
|
+
event_queue=self.event_queue,
|
|
134
|
+
graph=self.graph,
|
|
135
|
+
request_handler=self.request_handler,
|
|
136
|
+
resolver=self.resolver,
|
|
137
|
+
effector=self.effector
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
self.pipeline = (KnowledgePipelineOverride or KnowledgePipeline)(
|
|
141
|
+
handler_context=self.handler_context,
|
|
142
|
+
cache=self.cache,
|
|
143
|
+
request_handler=self.request_handler,
|
|
144
|
+
event_queue=self.event_queue,
|
|
145
|
+
graph=self.graph,
|
|
146
|
+
default_handlers=handlers
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
self.processor = (ProcessorInterfaceOverride or ProcessorInterface)(
|
|
150
|
+
pipeline=self.pipeline,
|
|
151
|
+
use_kobj_processor_thread=self.use_kobj_processor_thread
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
self.error_handler = (ErrorHandlerOverride or ErrorHandler)(
|
|
155
|
+
processor=self.processor,
|
|
156
|
+
actor=self.actor
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
self.request_handler.set_error_handler(self.error_handler)
|
|
160
|
+
|
|
161
|
+
self.handler_context.set_processor(self.processor)
|
|
162
|
+
|
|
163
|
+
self.effector.set_processor(self.processor)
|
|
164
|
+
self.effector.set_resolver(self.resolver)
|
|
165
|
+
self.effector.set_action_context(self.action_context)
|
|
166
|
+
|
|
167
|
+
self.actor.set_ctx(self.handler_context)
|
|
168
|
+
|
|
169
|
+
self.lifecycle = (NodeLifecycleOverride or NodeLifecycle)(
|
|
170
|
+
config=self.config,
|
|
171
|
+
identity=self.identity,
|
|
172
|
+
graph=self.graph,
|
|
173
|
+
processor=self.processor,
|
|
174
|
+
effector=self.effector,
|
|
175
|
+
actor=self.actor,
|
|
176
|
+
use_kobj_processor_thread=use_kobj_processor_thread
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# if self.config.koi_net.node_profile.node_type == NodeType.FULL:
|
|
180
|
+
self.server = (NodeServerOverride or NodeServer)(
|
|
181
|
+
config=self.config,
|
|
182
|
+
lifecycle=self.lifecycle,
|
|
183
|
+
secure=self.secure,
|
|
184
|
+
processor=self.processor,
|
|
185
|
+
event_queue=self.event_queue,
|
|
186
|
+
response_handler=self.response_handler
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
self.poller = (NodePollerOverride or NodePoller)(
|
|
190
|
+
processor=self.processor,
|
|
191
|
+
lifecycle=self.lifecycle,
|
|
192
|
+
resolver=self.resolver,
|
|
193
|
+
config=self.config
|
|
194
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .context import ActionContext
|
|
2
|
+
from rid_lib.types import KoiNetNode
|
|
3
|
+
from rid_lib.ext import Bundle
|
|
4
|
+
from .effector import Effector
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@Effector.register_default_action(KoiNetNode)
|
|
8
|
+
def dereference_koi_node(ctx: ActionContext, rid: KoiNetNode) -> Bundle:
|
|
9
|
+
if rid != ctx.identity.rid:
|
|
10
|
+
return
|
|
11
|
+
|
|
12
|
+
return Bundle.generate(
|
|
13
|
+
rid=ctx.identity.rid,
|
|
14
|
+
contents=ctx.identity.profile.model_dump()
|
|
15
|
+
)
|