koi-net 1.0.0b1__py3-none-any.whl → 1.0.0b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of koi-net might be problematic. Click here for more details.
- koi_net/core.py +24 -8
- koi_net/identity.py +8 -0
- koi_net/network/graph.py +15 -0
- koi_net/network/interface.py +38 -10
- koi_net/network/request_handler.py +77 -41
- koi_net/network/response_handler.py +2 -0
- koi_net/processor/default_handlers.py +25 -6
- koi_net/processor/handler.py +37 -7
- koi_net/processor/interface.py +53 -32
- koi_net/processor/knowledge_object.py +26 -7
- koi_net/protocol/api_models.py +9 -1
- koi_net/protocol/consts.py +2 -0
- koi_net-1.0.0b3.dist-info/METADATA +510 -0
- koi_net-1.0.0b3.dist-info/RECORD +24 -0
- koi_net-1.0.0b1.dist-info/METADATA +0 -43
- koi_net-1.0.0b1.dist-info/RECORD +0 -24
- {koi_net-1.0.0b1.dist-info → koi_net-1.0.0b3.dist-info}/WHEEL +0 -0
- {koi_net-1.0.0b1.dist-info → koi_net-1.0.0b3.dist-info}/licenses/LICENSE +0 -0
koi_net/processor/interface.py
CHANGED
|
@@ -11,7 +11,8 @@ from ..protocol.event import Event, EventType
|
|
|
11
11
|
from .handler import (
|
|
12
12
|
KnowledgeHandler,
|
|
13
13
|
HandlerType,
|
|
14
|
-
STOP_CHAIN
|
|
14
|
+
STOP_CHAIN,
|
|
15
|
+
StopChain
|
|
15
16
|
)
|
|
16
17
|
from .knowledge_object import (
|
|
17
18
|
KnowledgeObject,
|
|
@@ -23,6 +24,8 @@ logger = logging.getLogger(__name__)
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class ProcessorInterface:
|
|
27
|
+
"""Provides access to this node's knowledge processing pipeline."""
|
|
28
|
+
|
|
26
29
|
cache: Cache
|
|
27
30
|
network: NetworkInterface
|
|
28
31
|
identity: NodeIdentity
|
|
@@ -41,28 +44,19 @@ class ProcessorInterface:
|
|
|
41
44
|
self.identity = identity
|
|
42
45
|
self.handlers: list[KnowledgeHandler] = default_handlers
|
|
43
46
|
self.kobj_queue = Queue()
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
cls,
|
|
48
|
-
handler_type: HandlerType,
|
|
49
|
-
rid_types: list[RIDType] | None = None
|
|
50
|
-
):
|
|
51
|
-
"""Special decorator that returns a Handler instead of a function."""
|
|
52
|
-
def decorator(func: Callable) -> KnowledgeHandler:
|
|
53
|
-
handler = KnowledgeHandler(func, handler_type, rid_types, )
|
|
54
|
-
return handler
|
|
55
|
-
return decorator
|
|
47
|
+
|
|
48
|
+
def add_handler(self, handler: KnowledgeHandler):
|
|
49
|
+
self.handlers.append(handler)
|
|
56
50
|
|
|
57
51
|
def register_handler(
|
|
58
52
|
self,
|
|
59
53
|
handler_type: HandlerType,
|
|
60
54
|
rid_types: list[RIDType] | None = None
|
|
61
55
|
):
|
|
62
|
-
"""Assigns decorated function as handler for this
|
|
56
|
+
"""Assigns decorated function as handler for this processor."""
|
|
63
57
|
def decorator(func: Callable) -> Callable:
|
|
64
58
|
handler = KnowledgeHandler(func, handler_type, rid_types)
|
|
65
|
-
self.
|
|
59
|
+
self.add_handler(handler)
|
|
66
60
|
return func
|
|
67
61
|
return decorator
|
|
68
62
|
|
|
@@ -70,7 +64,17 @@ class ProcessorInterface:
|
|
|
70
64
|
self,
|
|
71
65
|
handler_type: HandlerType,
|
|
72
66
|
kobj: KnowledgeObject
|
|
73
|
-
):
|
|
67
|
+
) -> KnowledgeObject | StopChain:
|
|
68
|
+
"""Calls handlers of provided type, chaining their inputs and outputs together.
|
|
69
|
+
|
|
70
|
+
The knowledge object provided when this function is called will be passed to the first handler. A handler may return one of three types:
|
|
71
|
+
- `KnowledgeObject` - to modify the knowledge object for the next handler in the chain
|
|
72
|
+
- `None` - to keep the same knowledge object for the next handler in the chain
|
|
73
|
+
- `STOP_CHAIN` - to stop the handler chain and immediately exit the processing pipeline
|
|
74
|
+
|
|
75
|
+
Handlers will only be called in the chain if their handler and RID type match that of the inputted knowledge object.
|
|
76
|
+
"""
|
|
77
|
+
|
|
74
78
|
for handler in self.handlers:
|
|
75
79
|
if handler_type != handler.handler_type:
|
|
76
80
|
continue
|
|
@@ -98,7 +102,19 @@ class ProcessorInterface:
|
|
|
98
102
|
return kobj
|
|
99
103
|
|
|
100
104
|
|
|
101
|
-
def
|
|
105
|
+
def process_kobj(self, kobj: KnowledgeObject) -> None:
|
|
106
|
+
"""Sends provided knowledge obejct through knowledge processing pipeline.
|
|
107
|
+
|
|
108
|
+
Handler chains are called in between major events in the pipeline, indicated by their handler type. Each handler type is guaranteed to have access to certain knowledge, and may affect a subsequent action in the pipeline. The five handler types are as follows:
|
|
109
|
+
- RID - provided RID; if event type is `FORGET`, this handler decides whether to delete the knowledge from the cache by setting the normalized event type to `FORGET`, otherwise this handler decides whether to validate the manifest (and fetch it if not provided).
|
|
110
|
+
- Manifest - provided RID, manifest; decides whether to validate the bundle (and fetch it if not provided).
|
|
111
|
+
- Bundle - provided RID, manifest, contents (bundle); decides whether to write knowledge to the cache by setting the normalized event type to `NEW` or `UPDATE`.
|
|
112
|
+
- Network - provided RID, manifest, contents (bundle); decides which nodes (if any) to broadcast an event about this knowledge to. (Note, if event type is `FORGET`, the manifest and contents will be retrieved from the local cache, and indicate the last state of the knowledge before it was deleted.)
|
|
113
|
+
- Final - provided RID, manifests, contents (bundle); final action taken after network broadcast.
|
|
114
|
+
|
|
115
|
+
The pipeline may be stopped by any point by a single handler returning the `STOP_CHAIN` sentinel. In that case, the process will exit immediately. Further handlers of that type and later handler chains will not be called.
|
|
116
|
+
"""
|
|
117
|
+
|
|
102
118
|
logger.info(f"Handling {kobj!r}")
|
|
103
119
|
kobj = self.call_handler_chain(HandlerType.RID, kobj)
|
|
104
120
|
if kobj is STOP_CHAIN: return
|
|
@@ -183,19 +199,13 @@ class ProcessorInterface:
|
|
|
183
199
|
self.network.flush_all_webhook_queues()
|
|
184
200
|
|
|
185
201
|
kobj = self.call_handler_chain(HandlerType.Final, kobj)
|
|
186
|
-
|
|
187
|
-
def queue_kobj(self, kobj: KnowledgeObject, flush: bool = False):
|
|
188
|
-
self.kobj_queue.put(kobj)
|
|
189
|
-
logger.info(f"Queued {kobj!r}")
|
|
190
|
-
|
|
191
|
-
if flush:
|
|
192
|
-
self.flush_kobj_queue()
|
|
193
202
|
|
|
194
203
|
def flush_kobj_queue(self):
|
|
204
|
+
"""Flushes all knowledge objects from queue and processes them."""
|
|
195
205
|
while not self.kobj_queue.empty():
|
|
196
206
|
kobj = self.kobj_queue.get()
|
|
197
207
|
logger.info(f"Dequeued {kobj!r}")
|
|
198
|
-
self.
|
|
208
|
+
self.process_kobj(kobj)
|
|
199
209
|
logger.info("Done handling")
|
|
200
210
|
|
|
201
211
|
def handle(
|
|
@@ -204,19 +214,30 @@ class ProcessorInterface:
|
|
|
204
214
|
manifest: Manifest | None = None,
|
|
205
215
|
bundle: Bundle | None = None,
|
|
206
216
|
event: Event | None = None,
|
|
217
|
+
kobj: KnowledgeObject | None = None,
|
|
207
218
|
event_type: KnowledgeEventType = None,
|
|
208
219
|
source: KnowledgeSource = KnowledgeSource.Internal,
|
|
209
220
|
flush: bool = False
|
|
210
221
|
):
|
|
222
|
+
"""Queues provided knowledge to be handled by processing pipeline.
|
|
223
|
+
|
|
224
|
+
Knowledge may take the form of an RID, manifest, bundle, event, or knowledge object (with an optional event type for RID, manifest, or bundle objects). All objects will be normalized into knowledge objects and queued. If `flush` is `True`, the queue will be flushed immediately after adding the new knowledge.
|
|
225
|
+
"""
|
|
211
226
|
if rid:
|
|
212
|
-
|
|
227
|
+
_kobj = KnowledgeObject.from_rid(rid, event_type, source)
|
|
213
228
|
elif manifest:
|
|
214
|
-
|
|
229
|
+
_kobj = KnowledgeObject.from_manifest(manifest, event_type, source)
|
|
215
230
|
elif bundle:
|
|
216
|
-
|
|
231
|
+
_kobj = KnowledgeObject.from_bundle(bundle, event_type, source)
|
|
217
232
|
elif event:
|
|
218
|
-
|
|
233
|
+
_kobj = KnowledgeObject.from_event(event, source)
|
|
234
|
+
elif _kobj:
|
|
235
|
+
_kobj = kobj
|
|
219
236
|
else:
|
|
220
|
-
raise ValueError("One of 'rid', 'manifest', 'bundle', or '
|
|
221
|
-
|
|
222
|
-
self.
|
|
237
|
+
raise ValueError("One of 'rid', 'manifest', 'bundle', 'event', or 'kobj' must be provided")
|
|
238
|
+
|
|
239
|
+
self.kobj_queue.put(kobj)
|
|
240
|
+
logger.info(f"Queued {kobj!r}")
|
|
241
|
+
|
|
242
|
+
if flush:
|
|
243
|
+
self.flush_kobj_queue()
|
|
@@ -14,6 +14,18 @@ class KnowledgeSource(StrEnum):
|
|
|
14
14
|
External = "EXTERNAL"
|
|
15
15
|
|
|
16
16
|
class KnowledgeObject(BaseModel):
|
|
17
|
+
"""A normalized knowledge representation for internal processing.
|
|
18
|
+
|
|
19
|
+
Capable of representing an RID, manifest, bundle, or event. Contains three additional fields use for decision making in the knowledge processing pipeline.
|
|
20
|
+
|
|
21
|
+
The source indicates whether this object was generated by this node, or sourced from another node in the network.
|
|
22
|
+
|
|
23
|
+
The normalized event type indicates how the knowledge object is viewed from the perspective of this node, and what cache actions will take place. `NEW`, `UPDATE` -> cache write, `FORGET` -> cache delete, `None` -> no cache action.
|
|
24
|
+
|
|
25
|
+
The network targets indicate other nodes in the network this knowledge object will be sent to. The event sent to them will be constructed from this knowledge object's RID, manifest, contents, and normalized event type.
|
|
26
|
+
|
|
27
|
+
Constructors are provided to create a knowledge object from an RID, manifest, bundle, or event.
|
|
28
|
+
"""
|
|
17
29
|
rid: RID
|
|
18
30
|
manifest: Manifest | None = None
|
|
19
31
|
contents: dict | None = None
|
|
@@ -93,12 +105,19 @@ class KnowledgeObject(BaseModel):
|
|
|
93
105
|
|
|
94
106
|
@property
|
|
95
107
|
def normalized_event(self):
|
|
96
|
-
if
|
|
108
|
+
if self.normalized_event_type is None:
|
|
97
109
|
raise ValueError("Internal event's normalized event type is None, cannot convert to Event")
|
|
98
110
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
elif self.normalized_event_type == EventType.FORGET:
|
|
112
|
+
return Event(
|
|
113
|
+
rid=self.rid,
|
|
114
|
+
event_type=EventType.FORGET
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
else:
|
|
118
|
+
return Event(
|
|
119
|
+
rid=self.rid,
|
|
120
|
+
event_type=self.normalized_event_type,
|
|
121
|
+
manifest=self.manifest,
|
|
122
|
+
contents=self.contents
|
|
123
|
+
)
|
koi_net/protocol/api_models.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Pydantic models for request and response/payload objects in the KOI-net API."""
|
|
2
|
+
|
|
1
3
|
from pydantic import BaseModel
|
|
2
4
|
from rid_lib import RID, RIDType
|
|
3
5
|
from rid_lib.ext import Bundle, Manifest
|
|
@@ -36,4 +38,10 @@ class BundlesPayload(BaseModel):
|
|
|
36
38
|
deferred: list[RID] = []
|
|
37
39
|
|
|
38
40
|
class EventsPayload(BaseModel):
|
|
39
|
-
events: list[Event]
|
|
41
|
+
events: list[Event]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# TYPES
|
|
45
|
+
|
|
46
|
+
type RequestModels = EventsPayload | PollEvents | FetchRids | FetchManifests | FetchBundles
|
|
47
|
+
type ResponseModels = RidsPayload | ManifestsPayload | BundlesPayload | EventsPayload
|