koi-net 1.2.0b2__tar.gz → 1.2.0b3__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.

Files changed (82) hide show
  1. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/PKG-INFO +1 -1
  2. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/examples/coordinator.py +27 -32
  3. koi_net-1.2.0b3/examples/partial.py +30 -0
  4. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/pyproject.toml +1 -1
  5. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/__init__.py +0 -1
  6. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/assembler.py +20 -7
  7. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/cli/models.py +2 -2
  8. koi_net-1.2.0b3/src/koi_net/config/core.py +71 -0
  9. koi_net-1.2.0b3/src/koi_net/config/full_node.py +31 -0
  10. koi_net-1.2.0b3/src/koi_net/config/loader.py +46 -0
  11. koi_net-1.2.0b3/src/koi_net/config/partial_node.py +18 -0
  12. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/core.py +15 -23
  13. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/default_actions.py +1 -2
  14. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/effector.py +1 -1
  15. koi_net-1.2.0b3/src/koi_net/entrypoints/__init__.py +2 -0
  16. koi_net-1.2.0b3/src/koi_net/entrypoints/base.py +5 -0
  17. {koi_net-1.2.0b2/src/koi_net → koi_net-1.2.0b3/src/koi_net/entrypoints}/poller.py +9 -9
  18. {koi_net-1.2.0b2/src/koi_net → koi_net-1.2.0b3/src/koi_net/entrypoints}/server.py +9 -10
  19. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/handshaker.py +2 -2
  20. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/identity.py +1 -1
  21. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/lifecycle.py +6 -6
  22. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/network/error_handler.py +1 -1
  23. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/network/event_queue.py +1 -1
  24. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/network/poll_event_buffer.py +1 -1
  25. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/network/resolver.py +1 -1
  26. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/network/response_handler.py +1 -1
  27. {koi_net-1.2.0b2/src/koi_net → koi_net-1.2.0b3/src/koi_net/processor}/context.py +6 -6
  28. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/processor/handler.py +4 -1
  29. koi_net-1.2.0b2/src/koi_net/processor/handlers.py → koi_net-1.2.0b3/src/koi_net/processor/knowledge_handlers.py +6 -6
  30. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/processor/knowledge_object.py +2 -3
  31. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/processor/kobj_queue.py +1 -1
  32. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/processor/pipeline.py +2 -2
  33. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/node.py +3 -3
  34. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/secure.py +6 -0
  35. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/secure.py +1 -2
  36. koi_net-1.2.0b3/src/koi_net/workers/__init__.py +2 -0
  37. {koi_net-1.2.0b2/src/koi_net/processor → koi_net-1.2.0b3/src/koi_net/workers}/event_worker.py +8 -8
  38. {koi_net-1.2.0b2/src/koi_net/processor → koi_net-1.2.0b3/src/koi_net/workers}/kobj_worker.py +3 -3
  39. koi_net-1.2.0b2/examples/partial.py +0 -35
  40. koi_net-1.2.0b2/src/koi_net/config.py +0 -161
  41. koi_net-1.2.0b2/src/koi_net/interfaces/entrypoint.py +0 -5
  42. koi_net-1.2.0b2/src/koi_net/sentry.py +0 -13
  43. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/.github/workflows/publish-to-pypi.yml +0 -0
  44. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/.gitignore +0 -0
  45. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/LICENSE +0 -0
  46. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/README.md +0 -0
  47. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/koi-net-protocol-openapi.json +0 -0
  48. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/requirements.txt +0 -0
  49. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/bundle.schema.json +0 -0
  50. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/bundles_payload.schema.json +0 -0
  51. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/edge_profile.schema.json +0 -0
  52. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/error_response.schema.json +0 -0
  53. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/event.schema.json +0 -0
  54. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/events_payload.schema.json +0 -0
  55. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/fetch_bundles.schema.json +0 -0
  56. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/fetch_manifests.schema.json +0 -0
  57. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/fetch_rids.schema.json +0 -0
  58. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/manifest.schema.json +0 -0
  59. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/manifests_payload.schema.json +0 -0
  60. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/node_profile.schema.json +0 -0
  61. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/poll_events.schema.json +0 -0
  62. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/rids_payload.schema.json +0 -0
  63. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/signed_envelope.schema.json +0 -0
  64. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/schemas/unsigned_envelope.json +0 -0
  65. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/cli/__init__.py +0 -0
  66. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/cli/commands.py +0 -0
  67. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/logger.py +0 -0
  68. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/network/__init__.py +0 -0
  69. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/network/graph.py +0 -0
  70. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/network/request_handler.py +0 -0
  71. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/processor/__init__.py +0 -0
  72. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/__init__.py +0 -0
  73. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/api_models.py +0 -0
  74. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/consts.py +0 -0
  75. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/edge.py +0 -0
  76. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/envelope.py +0 -0
  77. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/errors.py +0 -0
  78. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/event.py +0 -0
  79. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/protocol/model_map.py +0 -0
  80. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/src/koi_net/utils.py +0 -0
  81. /koi_net-1.2.0b2/src/koi_net/interfaces/worker.py → /koi_net-1.2.0b3/src/koi_net/workers/base.py +0 -0
  82. {koi_net-1.2.0b2 → koi_net-1.2.0b3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koi-net
3
- Version: 1.2.0b2
3
+ Version: 1.2.0b3
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>
@@ -1,11 +1,15 @@
1
1
  import logging
2
2
  from rich.logging import RichHandler
3
- from pydantic import Field
4
3
  from rid_lib.types import KoiNetNode, KoiNetEdge
5
- from koi_net.config import NodeConfig, KoiNetConfig, ServerConfig
6
- from koi_net.core import NodeAssembler
7
- from koi_net.protocol.node import NodeProfile, NodeProvides, NodeType
8
- from koi_net.context import HandlerContext
4
+ from koi_net.config.full_node import (
5
+ FullNodeConfig,
6
+ ServerConfig,
7
+ KoiNetConfig,
8
+ NodeProfile,
9
+ NodeProvides
10
+ )
11
+ from koi_net.core import FullNode
12
+ from koi_net.processor.context import HandlerContext
9
13
  from koi_net.processor.handler import HandlerType, KnowledgeHandler
10
14
  from koi_net.processor.knowledge_object import KnowledgeObject
11
15
  from koi_net.protocol.event import Event, EventType
@@ -22,22 +26,17 @@ logging.getLogger("koi_net").setLevel(logging.DEBUG)
22
26
  logger = logging.getLogger(__name__)
23
27
 
24
28
 
25
- class CoordinatorConfig(NodeConfig):
26
- server: ServerConfig = Field(default_factory=lambda:
27
- ServerConfig(port=8080)
28
- )
29
- koi_net: KoiNetConfig = Field(default_factory = lambda:
30
- KoiNetConfig(
31
- node_name="coordinator",
32
- node_profile=NodeProfile(
33
- node_type=NodeType.FULL,
34
- provides=NodeProvides(
35
- event=[KoiNetNode, KoiNetEdge],
36
- state=[KoiNetNode, KoiNetEdge]
37
- )
38
- ),
39
- rid_types_of_interest=[KoiNetNode, KoiNetEdge]
40
- )
29
+ class CoordinatorConfig(FullNodeConfig):
30
+ server: ServerConfig = ServerConfig(port=8080)
31
+ koi_net: KoiNetConfig = KoiNetConfig(
32
+ node_name="coordinator",
33
+ node_profile=NodeProfile(
34
+ provides=NodeProvides(
35
+ event=[KoiNetNode, KoiNetEdge],
36
+ state=[KoiNetNode, KoiNetEdge]
37
+ )
38
+ ),
39
+ rid_types_of_interest=[KoiNetNode, KoiNetEdge]
41
40
  )
42
41
 
43
42
  @KnowledgeHandler.create(
@@ -52,7 +51,7 @@ def handshake_handler(ctx: HandlerContext, kobj: KnowledgeObject):
52
51
 
53
52
  logger.info("Sharing this node's bundle with peer")
54
53
  identity_bundle = ctx.cache.read(ctx.identity.rid)
55
- ctx.event_queue.push_event_to(
54
+ ctx.event_queue.push(
56
55
  event=Event.from_bundle(EventType.NEW, identity_bundle),
57
56
  target=kobj.rid
58
57
  )
@@ -67,17 +66,13 @@ def handshake_handler(ctx: HandlerContext, kobj: KnowledgeObject):
67
66
  rid_types=[KoiNetNode, KoiNetEdge]
68
67
  )
69
68
 
70
- ctx.kobj_queue.put_kobj(rid=edge_bundle.rid, event_type=EventType.FORGET)
71
- ctx.kobj_queue.put_kobj(bundle=edge_bundle)
69
+ ctx.kobj_queue.push(rid=edge_bundle.rid, event_type=EventType.FORGET)
70
+ ctx.kobj_queue.push(bundle=edge_bundle)
72
71
 
73
- class CoordinatorNodeAssembler(NodeAssembler):
72
+ class CoordinatorNode(FullNode):
74
73
  config = CoordinatorConfig
75
- knowledge_handlers = [
76
- *NodeAssembler.knowledge_handlers,
77
- handshake_handler
78
- ]
79
-
74
+ knowledge_handlers = FullNode.knowledge_handlers + [handshake_handler]
80
75
 
81
76
  if __name__ == "__main__":
82
- node = CoordinatorNodeAssembler.create()
83
- node.server.run()
77
+ node = CoordinatorNode()
78
+ node.entrypoint.run()
@@ -0,0 +1,30 @@
1
+ import logging
2
+ from rich.logging import RichHandler
3
+ from koi_net.config.partial_node import PartialNodeConfig, KoiNetConfig, NodeProfile
4
+ from koi_net.core import PartialNode
5
+
6
+
7
+ logging.basicConfig(
8
+ level=logging.INFO,
9
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
10
+ datefmt="%Y-%m-%d %H:%M:%S",
11
+ handlers=[RichHandler()]
12
+ )
13
+
14
+ logging.getLogger("koi_net").setLevel(logging.DEBUG)
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class MyPartialNodeConfig(PartialNodeConfig):
19
+ koi_net: KoiNetConfig = KoiNetConfig(
20
+ node_name="partial",
21
+ node_profile=NodeProfile()
22
+ )
23
+
24
+ class MyPartialNode(PartialNode):
25
+ config_cls = MyPartialNodeConfig
26
+
27
+
28
+ if __name__ == "__main__":
29
+ node = MyPartialNode()
30
+ # node.entrypoint.run()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "koi-net"
7
- version = "1.2.0b2"
7
+ version = "1.2.0b3"
8
8
  description = "Implementation of KOI-net protocol in Python"
9
9
  authors = [
10
10
  {name = "Luke Miller", email = "luke@block.science"}
@@ -1,2 +1 @@
1
1
  from . import logger
2
- from . import sentry
@@ -2,9 +2,10 @@ import inspect
2
2
  from typing import Protocol
3
3
  from dataclasses import make_dataclass
4
4
 
5
+ from pydantic import BaseModel
5
6
  import structlog
6
7
 
7
- from .interfaces.entrypoint import EntryPoint
8
+ from .entrypoints.base import EntryPoint
8
9
 
9
10
  log = structlog.stdlib.get_logger()
10
11
 
@@ -41,13 +42,25 @@ class NodeAssembler(metaclass=BuildOrderer):
41
42
  @classmethod
42
43
  def _build(cls) -> NodeContainer:
43
44
  components = {}
44
- for comp_name in cls._build_order:
45
- comp_factory = getattr(cls, comp_name, None)
45
+ for comp_name in cls._build_order:
46
+ comp = getattr(cls, comp_name, None)
46
47
 
47
- if comp_factory is None:
48
+ if comp is None:
48
49
  raise Exception(f"Couldn't find factory for component '{comp_name}'")
49
50
 
50
- sig = inspect.signature(comp_factory)
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)
51
64
 
52
65
  required_comps = []
53
66
  for name, param in sig.parameters.items():
@@ -58,7 +71,7 @@ class NodeAssembler(metaclass=BuildOrderer):
58
71
  else:
59
72
  s = f"{comp_name} -> {', '.join([name for name, _type in required_comps])}"
60
73
 
61
- print(s.replace("graph", "_graph"), end=";\n")
74
+ # print(s.replace("graph", "_graph"), end=";\n")
62
75
 
63
76
  dependencies = {}
64
77
  for req_comp_name, req_comp_type in required_comps:
@@ -67,7 +80,7 @@ class NodeAssembler(metaclass=BuildOrderer):
67
80
 
68
81
  dependencies[req_comp_name] = components[req_comp_name]
69
82
 
70
- components[comp_name] = comp_factory(**dependencies)
83
+ components[comp_name] = comp(**dependencies)
71
84
 
72
85
  NodeContainer = make_dataclass(
73
86
  cls_name="NodeContainer",
@@ -1,9 +1,9 @@
1
- from pydantic import BaseModel, Field, PrivateAttr
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] = Field(default_factory=dict)
6
+ nodes: dict[str, str] = {}
7
7
  _file_path: str = PrivateAttr(default="koi-net-config.yaml")
8
8
 
9
9
  @classmethod
@@ -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
@@ -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()
@@ -1,11 +1,13 @@
1
1
  from rid_lib.ext import Cache
2
+
3
+ from .config.loader import ConfigLoader
2
4
  from .assembler import NodeAssembler
3
- from .config.base import BaseConfig
4
- from .context import HandlerContext
5
+ from .config.core import NodeConfig
6
+ from .processor.context import HandlerContext
5
7
  from .effector import Effector
6
8
  from .handshaker import Handshaker
7
9
  from .identity import NodeIdentity
8
- from .processor.kobj_worker import KnowledgeProcessingWorker
10
+ from .workers import KnowledgeProcessingWorker, EventProcessingWorker
9
11
  from .lifecycle import NodeLifecycle
10
12
  from .network.error_handler import ErrorHandler
11
13
  from .network.event_queue import EventQueue
@@ -14,8 +16,11 @@ from .network.request_handler import RequestHandler
14
16
  from .network.resolver import NetworkResolver
15
17
  from .network.response_handler import ResponseHandler
16
18
  from .network.poll_event_buffer import PollEventBuffer
17
- from .poller import NodePoller
18
- from .processor.handlers import (
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 (
19
24
  basic_manifest_handler,
20
25
  basic_network_output_filter,
21
26
  basic_rid_handler,
@@ -24,28 +29,15 @@ from .processor.handlers import (
24
29
  forget_edge_on_node_deletion,
25
30
  secure_profile_handler
26
31
  )
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
32
 
42
33
 
43
34
  class BaseNode(NodeAssembler):
44
- config = lambda: None
35
+ config_cls = NodeConfig
45
36
  kobj_queue = KobjQueue
46
37
  event_queue = EventQueue
47
38
  poll_event_buf = PollEventBuffer
48
- knowledge_handlers = lambda: [
39
+ config = ConfigLoader
40
+ knowledge_handlers = [
49
41
  basic_rid_handler,
50
42
  basic_manifest_handler,
51
43
  secure_profile_handler,
@@ -54,7 +46,8 @@ class BaseNode(NodeAssembler):
54
46
  basic_network_output_filter,
55
47
  forget_edge_on_node_deletion
56
48
  ]
57
- cache = make_cache
49
+ cache = lambda config: Cache(
50
+ directory_path=config.koi_net.cache_directory_path)
58
51
  identity = NodeIdentity
59
52
  graph = NetworkGraph
60
53
  secure = Secure
@@ -70,7 +63,6 @@ class BaseNode(NodeAssembler):
70
63
  event_worker = EventProcessingWorker
71
64
  lifecycle = NodeLifecycle
72
65
 
73
-
74
66
  class FullNode(BaseNode):
75
67
  entrypoint = NodeServer
76
68
 
@@ -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)
@@ -155,7 +155,7 @@ class Effector:
155
155
  and bundle is not None
156
156
  and source != BundleSource.CACHE
157
157
  ):
158
- self.kobj_queue.put_kobj(
158
+ self.kobj_queue.push(
159
159
  bundle=bundle,
160
160
  source=source if type(source) is KoiNetNode else None
161
161
  )
@@ -0,0 +1,2 @@
1
+ from .poller import NodePoller
2
+ from .server import NodeServer
@@ -0,0 +1,5 @@
1
+ from koi_net.config.core import NodeConfig
2
+
3
+
4
+ class EntryPoint:
5
+ def run(self): ...
@@ -2,11 +2,11 @@
2
2
  import time
3
3
  import structlog
4
4
 
5
- from koi_net.interfaces.entrypoint import EntryPoint
6
- from .processor.kobj_queue import KobjQueue
7
- from .lifecycle import NodeLifecycle
8
- from .network.resolver import NetworkResolver
9
- from .config import NodeConfig
5
+ from .base import EntryPoint
6
+ from ..processor.kobj_queue import KobjQueue
7
+ from ..lifecycle import NodeLifecycle
8
+ from ..network.resolver import NetworkResolver
9
+ from ..config.partial_node import PartialNodeConfig
10
10
 
11
11
  log = structlog.stdlib.get_logger()
12
12
 
@@ -16,11 +16,11 @@ class NodePoller(EntryPoint):
16
16
  kobj_queue: KobjQueue
17
17
  lifecycle: NodeLifecycle
18
18
  resolver: NetworkResolver
19
- config: NodeConfig
19
+ config: PartialNodeConfig
20
20
 
21
21
  def __init__(
22
22
  self,
23
- config: NodeConfig,
23
+ config: PartialNodeConfig,
24
24
  lifecycle: NodeLifecycle,
25
25
  kobj_queue: KobjQueue,
26
26
  resolver: NetworkResolver,
@@ -35,7 +35,7 @@ class NodePoller(EntryPoint):
35
35
  neighbors = self.resolver.poll_neighbors()
36
36
  for node_rid in neighbors:
37
37
  for event in neighbors[node_rid]:
38
- self.kobj_queue.put_kobj(event=event, source=node_rid)
38
+ self.kobj_queue.push(event=event, source=node_rid)
39
39
 
40
40
  def run(self):
41
41
  """Runs polling event loop."""
@@ -44,6 +44,6 @@ class NodePoller(EntryPoint):
44
44
  start_time = time.time()
45
45
  self.poll()
46
46
  elapsed = time.time() - start_time
47
- sleep_time = self.config.koi_net.polling_interval - elapsed
47
+ sleep_time = self.config.poller.polling_interval - elapsed
48
48
  if sleep_time > 0:
49
49
  time.sleep(sleep_time)
@@ -4,21 +4,20 @@ from contextlib import asynccontextmanager
4
4
  from fastapi import FastAPI, APIRouter
5
5
  from fastapi.responses import JSONResponse
6
6
 
7
- from koi_net.interfaces.entrypoint import EntryPoint
8
-
9
- from .network.response_handler import ResponseHandler
10
- from .protocol.model_map import API_MODEL_MAP
11
- from .protocol.api_models import ErrorResponse
12
- from .protocol.errors import ProtocolError
13
- from .lifecycle import NodeLifecycle
14
- from .config import NodeConfig
7
+ from .base import EntryPoint
8
+ from ..network.response_handler import ResponseHandler
9
+ from ..protocol.model_map import API_MODEL_MAP
10
+ from ..protocol.api_models import ErrorResponse
11
+ from ..protocol.errors import ProtocolError
12
+ from ..lifecycle import NodeLifecycle
13
+ from ..config.full_node import FullNodeConfig
15
14
 
16
15
  log = structlog.stdlib.get_logger()
17
16
 
18
17
 
19
18
  class NodeServer(EntryPoint):
20
19
  """Manages FastAPI server and event handling for full nodes."""
21
- config: NodeConfig
20
+ config: FullNodeConfig
22
21
  lifecycle: NodeLifecycle
23
22
  response_handler: ResponseHandler
24
23
  app: FastAPI
@@ -26,7 +25,7 @@ class NodeServer(EntryPoint):
26
25
 
27
26
  def __init__(
28
27
  self,
29
- config: NodeConfig,
28
+ config: FullNodeConfig,
30
29
  lifecycle: NodeLifecycle,
31
30
  response_handler: ResponseHandler,
32
31
  ):
@@ -25,13 +25,13 @@ class Handshaker:
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
- self.event_queue.push_event_to(
28
+ self.event_queue.push(
29
29
  Event.from_rid(
30
30
  event_type=EventType.FORGET,
31
31
  rid=self.identity.rid),
32
32
  target=target
33
33
  )
34
- self.event_queue.push_event_to(
34
+ self.event_queue.push(
35
35
  event=Event.from_bundle(
36
36
  event_type=EventType.NEW,
37
37
  bundle=self.cache.read(self.identity.rid)),
@@ -1,6 +1,6 @@
1
1
  import structlog
2
2
  from rid_lib.types.koi_net_node import KoiNetNode
3
- from .config import NodeConfig
3
+ from .config.core import NodeConfig
4
4
  from .protocol.node import NodeProfile
5
5
 
6
6
  log = structlog.stdlib.get_logger()
@@ -6,12 +6,12 @@ from rid_lib.types import KoiNetNode
6
6
 
7
7
  from .handshaker import Handshaker
8
8
  from .network.request_handler import RequestHandler
9
- from .processor.kobj_worker import KnowledgeProcessingWorker
9
+ from .workers.kobj_worker import KnowledgeProcessingWorker
10
10
  from .network.event_queue import EventQueue
11
- from .processor.event_worker import EventProcessingWorker
11
+ from .workers import EventProcessingWorker
12
12
  from .protocol.api_models import ErrorResponse
13
- from .interfaces.worker import STOP_WORKER
14
- from .config import NodeConfig
13
+ from .workers.base import STOP_WORKER
14
+ from .config.core import NodeConfig
15
15
  from .processor.kobj_queue import KobjQueue
16
16
  from .network.graph import NetworkGraph
17
17
  from .identity import NodeIdentity
@@ -99,7 +99,7 @@ class NodeLifecycle:
99
99
 
100
100
  # refresh to reflect changes (if any) in config.yaml
101
101
 
102
- self.kobj_queue.put_kobj(bundle=Bundle.generate(
102
+ self.kobj_queue.push(bundle=Bundle.generate(
103
103
  rid=self.identity.rid,
104
104
  contents=self.identity.profile.model_dump()
105
105
  ))
@@ -119,7 +119,7 @@ class NodeLifecycle:
119
119
  continue
120
120
 
121
121
  for manifest in payload.manifests:
122
- self.kobj_queue.put_kobj(
122
+ self.kobj_queue.push(
123
123
  manifest=manifest,
124
124
  source=coordinator
125
125
  )
@@ -31,7 +31,7 @@ class ErrorHandler:
31
31
 
32
32
  if self.timeout_counter[node] > 3:
33
33
  log.debug(f"Exceeded time out limit, forgetting node")
34
- self.kobj_queue.put_kobj(rid=node, event_type=EventType.FORGET)
34
+ self.kobj_queue.push(rid=node, event_type=EventType.FORGET)
35
35
  # do something
36
36
 
37
37
 
@@ -20,7 +20,7 @@ class EventQueue:
20
20
  def __init__(self):
21
21
  self.q = Queue()
22
22
 
23
- def push_event_to(self, event: Event, target: KoiNetNode):
23
+ def push(self, event: Event, target: KoiNetNode):
24
24
  """Pushes event to queue of specified node.
25
25
 
26
26
  Event will be sent to webhook or poll queue depending on the