koi-net 1.2.0b1__py3-none-any.whl → 1.2.0b2__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.

Files changed (40) hide show
  1. koi_net/__init__.py +2 -1
  2. koi_net/assembler.py +82 -0
  3. koi_net/context.py +5 -13
  4. koi_net/core.py +51 -206
  5. koi_net/effector.py +26 -14
  6. koi_net/handshaker.py +3 -3
  7. koi_net/identity.py +2 -3
  8. koi_net/interfaces/entrypoint.py +5 -0
  9. koi_net/{worker.py → interfaces/worker.py} +7 -0
  10. koi_net/lifecycle.py +40 -32
  11. koi_net/logger.py +176 -0
  12. koi_net/network/error_handler.py +6 -6
  13. koi_net/network/event_queue.py +8 -6
  14. koi_net/network/graph.py +8 -8
  15. koi_net/network/poll_event_buffer.py +26 -0
  16. koi_net/network/request_handler.py +23 -28
  17. koi_net/network/resolver.py +13 -13
  18. koi_net/network/response_handler.py +74 -9
  19. koi_net/poller.py +7 -5
  20. koi_net/processor/event_worker.py +14 -18
  21. koi_net/processor/{default_handlers.py → handlers.py} +26 -25
  22. koi_net/processor/kobj_queue.py +3 -3
  23. koi_net/{kobj_worker.py → processor/kobj_worker.py} +12 -13
  24. koi_net/processor/{knowledge_pipeline.py → pipeline.py} +24 -27
  25. koi_net/protocol/api_models.py +5 -2
  26. koi_net/protocol/envelope.py +5 -6
  27. koi_net/protocol/model_map.py +61 -0
  28. koi_net/protocol/secure.py +8 -8
  29. koi_net/secure.py +5 -5
  30. koi_net/sentry.py +13 -0
  31. koi_net/server.py +36 -86
  32. {koi_net-1.2.0b1.dist-info → koi_net-1.2.0b2.dist-info}/METADATA +2 -1
  33. koi_net-1.2.0b2.dist-info/RECORD +52 -0
  34. koi_net/behaviors.py +0 -51
  35. koi_net/models.py +0 -14
  36. koi_net/poll_event_buffer.py +0 -17
  37. koi_net-1.2.0b1.dist-info/RECORD +0 -49
  38. {koi_net-1.2.0b1.dist-info → koi_net-1.2.0b2.dist-info}/WHEEL +0 -0
  39. {koi_net-1.2.0b1.dist-info → koi_net-1.2.0b2.dist-info}/entry_points.txt +0 -0
  40. {koi_net-1.2.0b1.dist-info → koi_net-1.2.0b2.dist-info}/licenses/LICENSE +0 -0
koi_net/__init__.py CHANGED
@@ -1 +1,2 @@
1
- from .core import NodeContainer
1
+ from . import logger
2
+ from . import sentry
koi_net/assembler.py ADDED
@@ -0,0 +1,82 @@
1
+ import inspect
2
+ from typing import Protocol
3
+ from dataclasses import make_dataclass
4
+
5
+ import structlog
6
+
7
+ from .interfaces.entrypoint import EntryPoint
8
+
9
+ log = structlog.stdlib.get_logger()
10
+
11
+
12
+ class BuildOrderer(type):
13
+ def __new__(cls, name: str, bases: tuple, dct: dict[str]):
14
+ """Sets `cls._build_order` from component order in class definition."""
15
+ cls = super().__new__(cls, name, bases, dct)
16
+
17
+ if "_build_order" not in dct:
18
+ components = {}
19
+ # adds components from base classes (including cls)
20
+ for base in reversed(inspect.getmro(cls)[:-1]):
21
+ for k, v in vars(base).items():
22
+ # excludes built in and private attributes
23
+ if not k.startswith("_"):
24
+ components[k] = v
25
+
26
+ # recipe list constructed from names of non-None components
27
+ cls._build_order = [
28
+ name for name, _type in components.items()
29
+ if _type is not None
30
+ ]
31
+
32
+ return cls
33
+
34
+ class NodeContainer(Protocol):
35
+ entrypoint = EntryPoint
36
+
37
+ class NodeAssembler(metaclass=BuildOrderer):
38
+ def __new__(self) -> NodeContainer:
39
+ return self._build()
40
+
41
+ @classmethod
42
+ def _build(cls) -> NodeContainer:
43
+ components = {}
44
+ for comp_name in cls._build_order:
45
+ comp_factory = getattr(cls, comp_name, None)
46
+
47
+ if comp_factory is None:
48
+ raise Exception(f"Couldn't find factory for component '{comp_name}'")
49
+
50
+ sig = inspect.signature(comp_factory)
51
+
52
+ required_comps = []
53
+ for name, param in sig.parameters.items():
54
+ required_comps.append((name, param.annotation))
55
+
56
+ if len(required_comps) == 0:
57
+ s = comp_name
58
+ else:
59
+ s = f"{comp_name} -> {', '.join([name for name, _type in required_comps])}"
60
+
61
+ print(s.replace("graph", "_graph"), end=";\n")
62
+
63
+ dependencies = {}
64
+ for req_comp_name, req_comp_type in required_comps:
65
+ if req_comp_name not in components:
66
+ raise Exception(f"Couldn't find required component '{req_comp_name}'")
67
+
68
+ dependencies[req_comp_name] = components[req_comp_name]
69
+
70
+ components[comp_name] = comp_factory(**dependencies)
71
+
72
+ NodeContainer = make_dataclass(
73
+ cls_name="NodeContainer",
74
+ fields=[
75
+ (name, type(component))
76
+ for name, component
77
+ in components.items()
78
+ ],
79
+ frozen=True
80
+ )
81
+
82
+ return NodeContainer(**components)
koi_net/context.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from rid_lib.ext import Cache
2
2
 
3
+ from koi_net.effector import Effector
3
4
  from koi_net.network.resolver import NetworkResolver
4
5
  from .config import NodeConfig
5
6
  from .network.graph import NetworkGraph
@@ -9,18 +10,6 @@ from .identity import NodeIdentity
9
10
  from .processor.kobj_queue import KobjQueue
10
11
 
11
12
 
12
- class ActionContext:
13
- """Provides action handlers access to other subsystems."""
14
-
15
- identity: NodeIdentity
16
-
17
- def __init__(
18
- self,
19
- identity: NodeIdentity,
20
- ):
21
- self.identity = identity
22
-
23
-
24
13
  class HandlerContext:
25
14
  """Provides knowledge handlers access to other subsystems."""
26
15
 
@@ -32,6 +21,7 @@ class HandlerContext:
32
21
  graph: NetworkGraph
33
22
  request_handler: RequestHandler
34
23
  resolver: NetworkResolver
24
+ effector: Effector
35
25
 
36
26
  def __init__(
37
27
  self,
@@ -43,6 +33,7 @@ class HandlerContext:
43
33
  graph: NetworkGraph,
44
34
  request_handler: RequestHandler,
45
35
  resolver: NetworkResolver,
36
+ effector: Effector
46
37
  ):
47
38
  self.identity = identity
48
39
  self.config = config
@@ -51,4 +42,5 @@ class HandlerContext:
51
42
  self.kobj_queue = kobj_queue
52
43
  self.graph = graph
53
44
  self.request_handler = request_handler
54
- self.resolver = resolver
45
+ self.resolver = resolver
46
+ self.effector = effector
koi_net/core.py CHANGED
@@ -1,22 +1,21 @@
1
- from dataclasses import dataclass
2
1
  from rid_lib.ext import Cache
3
- from koi_net.behaviors import Behaviors
4
- from koi_net.config import NodeConfig
5
- from koi_net.context import ActionContext, HandlerContext
6
- from koi_net.effector import Effector
7
- from koi_net.handshaker import Handshaker
8
- from koi_net.identity import NodeIdentity
9
- from koi_net.kobj_worker import KnowledgeProcessingWorker
10
- from koi_net.lifecycle import NodeLifecycle
11
- from koi_net.network.error_handler import ErrorHandler
12
- from koi_net.network.event_queue import EventQueue
13
- from koi_net.network.graph import NetworkGraph
14
- from koi_net.network.request_handler import RequestHandler
15
- from koi_net.network.resolver import NetworkResolver
16
- from koi_net.network.response_handler import ResponseHandler
17
- from koi_net.poll_event_buffer import PollEventBuffer
18
- from koi_net.poller import NodePoller
19
- from koi_net.processor.default_handlers import (
2
+ from .assembler import NodeAssembler
3
+ from .config.base import BaseConfig
4
+ from .context import HandlerContext
5
+ from .effector import Effector
6
+ from .handshaker import Handshaker
7
+ from .identity import NodeIdentity
8
+ from .processor.kobj_worker import KnowledgeProcessingWorker
9
+ from .lifecycle import NodeLifecycle
10
+ from .network.error_handler import ErrorHandler
11
+ from .network.event_queue import EventQueue
12
+ from .network.graph import NetworkGraph
13
+ from .network.request_handler import RequestHandler
14
+ from .network.resolver import NetworkResolver
15
+ from .network.response_handler import ResponseHandler
16
+ from .network.poll_event_buffer import PollEventBuffer
17
+ from .poller import NodePoller
18
+ from .processor.handlers import (
20
19
  basic_manifest_handler,
21
20
  basic_network_output_filter,
22
21
  basic_rid_handler,
@@ -25,51 +24,28 @@ from koi_net.processor.default_handlers import (
25
24
  forget_edge_on_node_deletion,
26
25
  secure_profile_handler
27
26
  )
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
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
33
32
 
34
33
 
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
-
34
+ # factory functions for components with non standard initializiation
58
35
 
59
- class NodeAssembler:
60
- poll_event_buf = PollEventBuffer
36
+ def make_config() -> BaseConfig:
37
+ return BaseConfig.load_from_yaml()
38
+
39
+ def make_cache(config: BaseConfig) -> Cache:
40
+ return Cache(directory_path=config.koi_net.cache_directory_path)
41
+
42
+
43
+ class BaseNode(NodeAssembler):
44
+ config = lambda: None
61
45
  kobj_queue = KobjQueue
62
46
  event_queue = EventQueue
63
- config = NodeConfig
64
- cache = Cache
65
- identity = NodeIdentity
66
- graph = NetworkGraph
67
- secure = Secure
68
- handshaker = Handshaker
69
- request_handler = RequestHandler
70
- response_handler = ResponseHandler
71
- resolver = NetworkResolver
72
- knowledge_handlers = [
47
+ poll_event_buf = PollEventBuffer
48
+ knowledge_handlers = lambda: [
73
49
  basic_rid_handler,
74
50
  basic_manifest_handler,
75
51
  secure_profile_handler,
@@ -78,156 +54,25 @@ class NodeAssembler:
78
54
  basic_network_output_filter,
79
55
  forget_edge_on_node_deletion
80
56
  ]
81
- handler_context = HandlerContext
82
- action_context = ActionContext
57
+ cache = make_cache
58
+ identity = NodeIdentity
59
+ graph = NetworkGraph
60
+ secure = Secure
61
+ handshaker = Handshaker
62
+ error_handler = ErrorHandler
63
+ request_handler = RequestHandler
64
+ response_handler = ResponseHandler
65
+ resolver = NetworkResolver
83
66
  effector = Effector
84
- behaviors = Behaviors
67
+ handler_context = HandlerContext
85
68
  pipeline = KnowledgePipeline
86
69
  kobj_worker = KnowledgeProcessingWorker
87
70
  event_worker = EventProcessingWorker
88
- error_handler = ErrorHandler
89
71
  lifecycle = NodeLifecycle
90
- server = NodeServer
91
- poller = NodePoller
92
-
93
- @classmethod
94
- def create(cls) -> NodeContainer:
95
- poll_event_buffer = cls.poll_event_buf()
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
- )
72
+
73
+
74
+ class FullNode(BaseNode):
75
+ entrypoint = NodeServer
76
+
77
+ class PartialNode(BaseNode):
78
+ entrypoint = NodePoller
koi_net/effector.py CHANGED
@@ -1,4 +1,4 @@
1
- import logging
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 .context import ActionContext
9
+ from .identity import NodeIdentity
10
10
 
11
- logger = logging.getLogger(__name__)
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
- action_context: ActionContext
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 = 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
- logger.debug("Cache hit")
85
+ log.debug("Cache hit")
74
86
  return bundle, BundleSource.CACHE
75
87
  else:
76
- logger.debug("Cache miss")
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
- logger.debug("No action available")
93
+ log.debug("No action available")
82
94
  return None
83
95
 
84
- logger.debug("Action available")
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
- logger.debug("Action hit")
104
+ log.debug("Action hit")
93
105
  return bundle, BundleSource.ACTION
94
106
  else:
95
- logger.debug("Action miss")
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
- logger.debug("Network hit")
115
+ log.debug("Network hit")
104
116
  return bundle, source
105
117
  else:
106
- logger.debug("Network miss")
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
- logger.debug(f"Dereferencing {rid!r}")
142
+ log.debug(f"Dereferencing {rid!r}")
131
143
 
132
144
  bundle, source = (
133
145
  # if `refresh_cache`, skip try cache
koi_net/handshaker.py CHANGED
@@ -1,11 +1,11 @@
1
- from logging import getLogger
1
+ import structlog
2
2
  from rid_lib.ext import Cache
3
3
  from rid_lib.types import KoiNetNode
4
4
  from koi_net.identity import NodeIdentity
5
5
  from koi_net.network.event_queue import EventQueue
6
6
  from .protocol.event import Event, EventType
7
7
 
8
- logger = getLogger(__name__)
8
+ log = structlog.stdlib.get_logger()
9
9
 
10
10
 
11
11
  class Handshaker:
@@ -24,7 +24,7 @@ class Handshaker:
24
24
  Pushes successive `FORGET` and `NEW` events to target node to
25
25
  reset the target's cache in case it already knew this node.
26
26
  """
27
- logger.debug(f"Initiating handshake with {target}")
27
+ log.debug(f"Initiating handshake with {target}")
28
28
  self.event_queue.push_event_to(
29
29
  Event.from_rid(
30
30
  event_type=EventType.FORGET,
koi_net/identity.py CHANGED
@@ -1,10 +1,9 @@
1
- import logging
1
+ import structlog
2
2
  from rid_lib.types.koi_net_node import KoiNetNode
3
3
  from .config import NodeConfig
4
4
  from .protocol.node import NodeProfile
5
5
 
6
-
7
- logger = logging.getLogger(__name__)
6
+ log = structlog.stdlib.get_logger()
8
7
 
9
8
 
10
9
  class NodeIdentity:
@@ -0,0 +1,5 @@
1
+ from typing import Protocol
2
+
3
+
4
+ class EntryPoint(Protocol):
5
+ def run(self): ...
@@ -1,5 +1,12 @@
1
1
  import threading
2
2
 
3
+
4
+ class End:
5
+ """Class for a sentinel value by knowledge handlers."""
6
+ pass
7
+
8
+ STOP_WORKER = End()
9
+
3
10
  class ThreadWorker:
4
11
  thread: threading.Thread
5
12