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.
Files changed (54) hide show
  1. {koi_net-1.0.0b19 → koi_net-1.1.0}/.gitignore +2 -0
  2. {koi_net-1.0.0b19 → koi_net-1.1.0}/PKG-INFO +5 -4
  3. koi_net-1.1.0/examples/coordinator.py +76 -0
  4. koi_net-1.1.0/examples/partial.py +37 -0
  5. {koi_net-1.0.0b19 → koi_net-1.1.0}/pyproject.toml +6 -5
  6. koi_net-1.1.0/src/koi_net/actor.py +60 -0
  7. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/config.py +44 -18
  8. koi_net-1.1.0/src/koi_net/context.py +63 -0
  9. koi_net-1.1.0/src/koi_net/core.py +194 -0
  10. koi_net-1.1.0/src/koi_net/default_actions.py +15 -0
  11. koi_net-1.1.0/src/koi_net/effector.py +139 -0
  12. koi_net-1.1.0/src/koi_net/identity.py +24 -0
  13. koi_net-1.1.0/src/koi_net/lifecycle.py +104 -0
  14. koi_net-1.1.0/src/koi_net/network/error_handler.py +50 -0
  15. koi_net-1.1.0/src/koi_net/network/event_queue.py +199 -0
  16. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/network/graph.py +23 -38
  17. koi_net-1.1.0/src/koi_net/network/request_handler.py +212 -0
  18. koi_net-1.1.0/src/koi_net/network/resolver.py +150 -0
  19. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/network/response_handler.py +15 -6
  20. koi_net-1.1.0/src/koi_net/poller.py +40 -0
  21. koi_net-1.1.0/src/koi_net/processor/__init__.py +0 -0
  22. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/processor/default_handlers.py +71 -42
  23. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/processor/handler.py +3 -7
  24. koi_net-1.1.0/src/koi_net/processor/interface.py +101 -0
  25. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/processor/knowledge_object.py +10 -17
  26. 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
  27. koi_net-1.1.0/src/koi_net/protocol/__init__.py +0 -0
  28. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/protocol/api_models.py +18 -3
  29. koi_net-1.1.0/src/koi_net/protocol/edge.py +45 -0
  30. koi_net-1.1.0/src/koi_net/protocol/envelope.py +58 -0
  31. koi_net-1.1.0/src/koi_net/protocol/errors.py +23 -0
  32. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/protocol/event.py +0 -3
  33. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/protocol/node.py +2 -1
  34. koi_net-1.1.0/src/koi_net/protocol/secure.py +160 -0
  35. koi_net-1.1.0/src/koi_net/secure.py +117 -0
  36. koi_net-1.1.0/src/koi_net/server.py +129 -0
  37. koi_net-1.1.0/uv.lock +1011 -0
  38. koi_net-1.0.0b19/examples/basic_coordinator_node.py +0 -141
  39. koi_net-1.0.0b19/examples/basic_partial_node.py +0 -46
  40. koi_net-1.0.0b19/src/koi_net/core.py +0 -126
  41. koi_net-1.0.0b19/src/koi_net/identity.py +0 -42
  42. koi_net-1.0.0b19/src/koi_net/network/__init__.py +0 -1
  43. koi_net-1.0.0b19/src/koi_net/network/interface.py +0 -276
  44. koi_net-1.0.0b19/src/koi_net/network/request_handler.py +0 -149
  45. koi_net-1.0.0b19/src/koi_net/processor/__init__.py +0 -1
  46. koi_net-1.0.0b19/src/koi_net/protocol/edge.py +0 -20
  47. koi_net-1.0.0b19/src/koi_net/protocol/helpers.py +0 -25
  48. {koi_net-1.0.0b19 → koi_net-1.1.0}/.github/workflows/publish-to-pypi.yml +0 -0
  49. {koi_net-1.0.0b19 → koi_net-1.1.0}/LICENSE +0 -0
  50. {koi_net-1.0.0b19 → koi_net-1.1.0}/README.md +0 -0
  51. {koi_net-1.0.0b19 → koi_net-1.1.0}/requirements.txt +0 -0
  52. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/__init__.py +0 -0
  53. {koi_net-1.0.0b19/src/koi_net/protocol → koi_net-1.1.0/src/koi_net/network}/__init__.py +0 -0
  54. {koi_net-1.0.0b19 → koi_net-1.1.0}/src/koi_net/protocol/consts.py +0 -0
@@ -1,6 +1,8 @@
1
1
  rid-lib
2
2
  __pycache__
3
3
  *.json
4
+ *.pem
5
+ *.yaml
4
6
  venv
5
7
  .env
6
8
  prototypes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koi-net
3
- Version: 1.0.0b19
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.3
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.0.0-beta.19"
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.3",
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 | None = "127.0.0.1"
12
- port: int | None = 8000
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 | None = ".rid_cache"
25
- event_queues_path: str | None = "event_queues.json"
26
-
27
- first_contact: str | None = None
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 | None = Field(default_factory=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
- config.koi_net.node_rid or KoiNetNode.generate(config.koi_net.node_name)
78
- )
79
- config.koi_net.node_profile.base_url = (
80
- config.koi_net.node_profile.base_url or config.server.url
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
+ )