koi-net 1.0.0b11__py3-none-any.whl → 1.0.0b12__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 +125 -125
- koi_net/identity.py +69 -69
- koi_net/network/graph.py +127 -127
- koi_net/network/interface.py +273 -275
- koi_net/network/request_handler.py +148 -148
- koi_net/network/response_handler.py +58 -58
- koi_net/processor/default_handlers.py +162 -162
- koi_net/processor/handler.py +59 -59
- koi_net/processor/interface.py +298 -298
- koi_net/processor/knowledge_object.py +122 -122
- koi_net/protocol/api_models.py +46 -46
- koi_net/protocol/consts.py +6 -6
- koi_net/protocol/edge.py +20 -20
- koi_net/protocol/event.py +50 -50
- koi_net/protocol/helpers.py +24 -24
- koi_net/protocol/node.py +16 -16
- {koi_net-1.0.0b11.dist-info → koi_net-1.0.0b12.dist-info}/METADATA +1 -1
- koi_net-1.0.0b12.dist-info/RECORD +24 -0
- {koi_net-1.0.0b11.dist-info → koi_net-1.0.0b12.dist-info}/licenses/LICENSE +21 -21
- koi_net-1.0.0b11.dist-info/RECORD +0 -24
- {koi_net-1.0.0b11.dist-info → koi_net-1.0.0b12.dist-info}/WHEEL +0 -0
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
"""Provides implementations of default knowledge handlers."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
from rid_lib.ext.bundle import Bundle
|
|
5
|
-
from rid_lib.types import KoiNetNode, KoiNetEdge
|
|
6
|
-
from koi_net.protocol.node import NodeType
|
|
7
|
-
from .interface import ProcessorInterface
|
|
8
|
-
from .handler import KnowledgeHandler, HandlerType, STOP_CHAIN
|
|
9
|
-
from .knowledge_object import KnowledgeObject, KnowledgeSource
|
|
10
|
-
from ..protocol.event import Event, EventType
|
|
11
|
-
from ..protocol.edge import EdgeProfile, EdgeStatus, EdgeType
|
|
12
|
-
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
|
-
# RID handlers
|
|
16
|
-
|
|
17
|
-
@KnowledgeHandler.create(HandlerType.RID)
|
|
18
|
-
def basic_rid_handler(processor: ProcessorInterface, kobj: KnowledgeObject):
|
|
19
|
-
"""Default RID handler.
|
|
20
|
-
|
|
21
|
-
Blocks external events about this node. Allows `FORGET` events if RID is known to this node.
|
|
22
|
-
"""
|
|
23
|
-
if (kobj.rid == processor.identity.rid and
|
|
24
|
-
kobj.source == KnowledgeSource.External):
|
|
25
|
-
logger.debug("Don't let anyone else tell me who I am!")
|
|
26
|
-
return STOP_CHAIN
|
|
27
|
-
|
|
28
|
-
if kobj.event_type == EventType.FORGET:
|
|
29
|
-
kobj.normalized_event_type = EventType.FORGET
|
|
30
|
-
return kobj
|
|
31
|
-
|
|
32
|
-
# Manifest handlers
|
|
33
|
-
|
|
34
|
-
@KnowledgeHandler.create(HandlerType.Manifest)
|
|
35
|
-
def basic_manifest_handler(processor: ProcessorInterface, kobj: KnowledgeObject):
|
|
36
|
-
"""Default manifest handler.
|
|
37
|
-
|
|
38
|
-
Blocks manifests with the same hash, or aren't newer than the cached version. Sets the normalized event type to `NEW` or `UPDATE` depending on whether the RID was previously known to this node.
|
|
39
|
-
"""
|
|
40
|
-
prev_bundle = processor.cache.read(kobj.rid)
|
|
41
|
-
|
|
42
|
-
if prev_bundle:
|
|
43
|
-
if kobj.manifest.sha256_hash == prev_bundle.manifest.sha256_hash:
|
|
44
|
-
logger.debug("Hash of incoming manifest is same as existing knowledge, ignoring")
|
|
45
|
-
return STOP_CHAIN
|
|
46
|
-
if kobj.manifest.timestamp <= prev_bundle.manifest.timestamp:
|
|
47
|
-
logger.debug("Timestamp of incoming manifest is the same or older than existing knowledge, ignoring")
|
|
48
|
-
return STOP_CHAIN
|
|
49
|
-
|
|
50
|
-
logger.debug("RID previously known to me, labeling as 'UPDATE'")
|
|
51
|
-
kobj.normalized_event_type = EventType.UPDATE
|
|
52
|
-
|
|
53
|
-
else:
|
|
54
|
-
logger.debug("RID previously unknown to me, labeling as 'NEW'")
|
|
55
|
-
kobj.normalized_event_type = EventType.NEW
|
|
56
|
-
|
|
57
|
-
return kobj
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# Bundle handlers
|
|
61
|
-
|
|
62
|
-
@KnowledgeHandler.create(
|
|
63
|
-
handler_type=HandlerType.Bundle,
|
|
64
|
-
rid_types=[KoiNetEdge],
|
|
65
|
-
source=KnowledgeSource.External,
|
|
66
|
-
event_types=[EventType.NEW, EventType.UPDATE])
|
|
67
|
-
def edge_negotiation_handler(processor: ProcessorInterface, kobj: KnowledgeObject):
|
|
68
|
-
"""Handles basic edge negotiation process.
|
|
69
|
-
|
|
70
|
-
Automatically approves proposed edges if they request RID types this node can provide (or KOI nodes/edges). Validates the edge type is allowed for the node type (partial nodes cannot use webhooks). If edge is invalid, a `FORGET` event is sent to the other node.
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
edge_profile = EdgeProfile.model_validate(kobj.contents)
|
|
74
|
-
|
|
75
|
-
# indicates peer subscribing to me
|
|
76
|
-
if edge_profile.source == processor.identity.rid:
|
|
77
|
-
if edge_profile.status != EdgeStatus.PROPOSED:
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
logger.debug("Handling edge negotiation")
|
|
81
|
-
|
|
82
|
-
peer_rid = edge_profile.target
|
|
83
|
-
peer_profile = processor.network.graph.get_node_profile(peer_rid)
|
|
84
|
-
|
|
85
|
-
if not peer_profile:
|
|
86
|
-
logger.warning(f"Peer {peer_rid} unknown to me")
|
|
87
|
-
return STOP_CHAIN
|
|
88
|
-
|
|
89
|
-
# explicitly provided event RID types and (self) node + edge objects
|
|
90
|
-
provided_events = (
|
|
91
|
-
*processor.identity.profile.provides.event,
|
|
92
|
-
KoiNetNode, KoiNetEdge
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
abort = False
|
|
97
|
-
if (edge_profile.edge_type == EdgeType.WEBHOOK and
|
|
98
|
-
peer_profile.node_type == NodeType.PARTIAL):
|
|
99
|
-
logger.debug("Partial nodes cannot use webhooks")
|
|
100
|
-
abort = True
|
|
101
|
-
|
|
102
|
-
if not set(edge_profile.rid_types).issubset(provided_events):
|
|
103
|
-
logger.debug("Requested RID types not provided by this node")
|
|
104
|
-
abort = True
|
|
105
|
-
|
|
106
|
-
if abort:
|
|
107
|
-
event = Event.from_rid(EventType.FORGET, kobj.rid)
|
|
108
|
-
processor.network.push_event_to(event, peer_rid, flush=True)
|
|
109
|
-
return STOP_CHAIN
|
|
110
|
-
|
|
111
|
-
else:
|
|
112
|
-
# approve edge profile
|
|
113
|
-
logger.debug("Approving proposed edge")
|
|
114
|
-
edge_profile.status = EdgeStatus.APPROVED
|
|
115
|
-
updated_bundle = Bundle.generate(kobj.rid, edge_profile.model_dump())
|
|
116
|
-
|
|
117
|
-
processor.handle(bundle=updated_bundle, event_type=EventType.UPDATE)
|
|
118
|
-
return
|
|
119
|
-
|
|
120
|
-
elif edge_profile.target == processor.identity.rid:
|
|
121
|
-
if edge_profile.status == EdgeStatus.APPROVED:
|
|
122
|
-
logger.debug("Edge approved by other node!")
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
# Network handlers
|
|
126
|
-
|
|
127
|
-
@KnowledgeHandler.create(HandlerType.Network)
|
|
128
|
-
def basic_network_output_filter(processor: ProcessorInterface, kobj: KnowledgeObject):
|
|
129
|
-
"""Default network handler.
|
|
130
|
-
|
|
131
|
-
Allows broadcasting of all RID types this node is an event provider for (set in node profile), and other nodes have subscribed to. All nodes will also broadcast about their own (internally sourced) KOI node, and KOI edges that they are part of, regardless of their node profile configuration. Finally, nodes will also broadcast about edges to the other node involved (regardless of if they are subscribed)."""
|
|
132
|
-
|
|
133
|
-
involves_me = False
|
|
134
|
-
if kobj.source == KnowledgeSource.Internal:
|
|
135
|
-
if (type(kobj.rid) == KoiNetNode):
|
|
136
|
-
if (kobj.rid == processor.identity.rid):
|
|
137
|
-
involves_me = True
|
|
138
|
-
|
|
139
|
-
elif type(kobj.rid) == KoiNetEdge:
|
|
140
|
-
edge_profile = kobj.bundle.validate_contents(EdgeProfile)
|
|
141
|
-
|
|
142
|
-
if edge_profile.source == processor.identity.rid:
|
|
143
|
-
logger.debug(f"Adding edge target '{edge_profile.target!r}' to network targets")
|
|
144
|
-
kobj.network_targets.update([edge_profile.target])
|
|
145
|
-
involves_me = True
|
|
146
|
-
|
|
147
|
-
elif edge_profile.target == processor.identity.rid:
|
|
148
|
-
logger.debug(f"Adding edge source '{edge_profile.source!r}' to network targets")
|
|
149
|
-
kobj.network_targets.update([edge_profile.source])
|
|
150
|
-
involves_me = True
|
|
151
|
-
|
|
152
|
-
if (type(kobj.rid) in processor.identity.profile.provides.event or involves_me):
|
|
153
|
-
# broadcasts to subscribers if I'm an event provider of this RID type OR it involves me
|
|
154
|
-
subscribers = processor.network.graph.get_neighbors(
|
|
155
|
-
direction="out",
|
|
156
|
-
allowed_type=type(kobj.rid)
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
logger.debug(f"Updating network targets with '{type(kobj.rid)}' subscribers: {subscribers}")
|
|
160
|
-
kobj.network_targets.update(subscribers)
|
|
161
|
-
|
|
162
|
-
return kobj
|
|
1
|
+
"""Provides implementations of default knowledge handlers."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from rid_lib.ext.bundle import Bundle
|
|
5
|
+
from rid_lib.types import KoiNetNode, KoiNetEdge
|
|
6
|
+
from koi_net.protocol.node import NodeType
|
|
7
|
+
from .interface import ProcessorInterface
|
|
8
|
+
from .handler import KnowledgeHandler, HandlerType, STOP_CHAIN
|
|
9
|
+
from .knowledge_object import KnowledgeObject, KnowledgeSource
|
|
10
|
+
from ..protocol.event import Event, EventType
|
|
11
|
+
from ..protocol.edge import EdgeProfile, EdgeStatus, EdgeType
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
# RID handlers
|
|
16
|
+
|
|
17
|
+
@KnowledgeHandler.create(HandlerType.RID)
|
|
18
|
+
def basic_rid_handler(processor: ProcessorInterface, kobj: KnowledgeObject):
|
|
19
|
+
"""Default RID handler.
|
|
20
|
+
|
|
21
|
+
Blocks external events about this node. Allows `FORGET` events if RID is known to this node.
|
|
22
|
+
"""
|
|
23
|
+
if (kobj.rid == processor.identity.rid and
|
|
24
|
+
kobj.source == KnowledgeSource.External):
|
|
25
|
+
logger.debug("Don't let anyone else tell me who I am!")
|
|
26
|
+
return STOP_CHAIN
|
|
27
|
+
|
|
28
|
+
if kobj.event_type == EventType.FORGET:
|
|
29
|
+
kobj.normalized_event_type = EventType.FORGET
|
|
30
|
+
return kobj
|
|
31
|
+
|
|
32
|
+
# Manifest handlers
|
|
33
|
+
|
|
34
|
+
@KnowledgeHandler.create(HandlerType.Manifest)
|
|
35
|
+
def basic_manifest_handler(processor: ProcessorInterface, kobj: KnowledgeObject):
|
|
36
|
+
"""Default manifest handler.
|
|
37
|
+
|
|
38
|
+
Blocks manifests with the same hash, or aren't newer than the cached version. Sets the normalized event type to `NEW` or `UPDATE` depending on whether the RID was previously known to this node.
|
|
39
|
+
"""
|
|
40
|
+
prev_bundle = processor.cache.read(kobj.rid)
|
|
41
|
+
|
|
42
|
+
if prev_bundle:
|
|
43
|
+
if kobj.manifest.sha256_hash == prev_bundle.manifest.sha256_hash:
|
|
44
|
+
logger.debug("Hash of incoming manifest is same as existing knowledge, ignoring")
|
|
45
|
+
return STOP_CHAIN
|
|
46
|
+
if kobj.manifest.timestamp <= prev_bundle.manifest.timestamp:
|
|
47
|
+
logger.debug("Timestamp of incoming manifest is the same or older than existing knowledge, ignoring")
|
|
48
|
+
return STOP_CHAIN
|
|
49
|
+
|
|
50
|
+
logger.debug("RID previously known to me, labeling as 'UPDATE'")
|
|
51
|
+
kobj.normalized_event_type = EventType.UPDATE
|
|
52
|
+
|
|
53
|
+
else:
|
|
54
|
+
logger.debug("RID previously unknown to me, labeling as 'NEW'")
|
|
55
|
+
kobj.normalized_event_type = EventType.NEW
|
|
56
|
+
|
|
57
|
+
return kobj
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Bundle handlers
|
|
61
|
+
|
|
62
|
+
@KnowledgeHandler.create(
|
|
63
|
+
handler_type=HandlerType.Bundle,
|
|
64
|
+
rid_types=[KoiNetEdge],
|
|
65
|
+
source=KnowledgeSource.External,
|
|
66
|
+
event_types=[EventType.NEW, EventType.UPDATE])
|
|
67
|
+
def edge_negotiation_handler(processor: ProcessorInterface, kobj: KnowledgeObject):
|
|
68
|
+
"""Handles basic edge negotiation process.
|
|
69
|
+
|
|
70
|
+
Automatically approves proposed edges if they request RID types this node can provide (or KOI nodes/edges). Validates the edge type is allowed for the node type (partial nodes cannot use webhooks). If edge is invalid, a `FORGET` event is sent to the other node.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
edge_profile = EdgeProfile.model_validate(kobj.contents)
|
|
74
|
+
|
|
75
|
+
# indicates peer subscribing to me
|
|
76
|
+
if edge_profile.source == processor.identity.rid:
|
|
77
|
+
if edge_profile.status != EdgeStatus.PROPOSED:
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
logger.debug("Handling edge negotiation")
|
|
81
|
+
|
|
82
|
+
peer_rid = edge_profile.target
|
|
83
|
+
peer_profile = processor.network.graph.get_node_profile(peer_rid)
|
|
84
|
+
|
|
85
|
+
if not peer_profile:
|
|
86
|
+
logger.warning(f"Peer {peer_rid} unknown to me")
|
|
87
|
+
return STOP_CHAIN
|
|
88
|
+
|
|
89
|
+
# explicitly provided event RID types and (self) node + edge objects
|
|
90
|
+
provided_events = (
|
|
91
|
+
*processor.identity.profile.provides.event,
|
|
92
|
+
KoiNetNode, KoiNetEdge
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
abort = False
|
|
97
|
+
if (edge_profile.edge_type == EdgeType.WEBHOOK and
|
|
98
|
+
peer_profile.node_type == NodeType.PARTIAL):
|
|
99
|
+
logger.debug("Partial nodes cannot use webhooks")
|
|
100
|
+
abort = True
|
|
101
|
+
|
|
102
|
+
if not set(edge_profile.rid_types).issubset(provided_events):
|
|
103
|
+
logger.debug("Requested RID types not provided by this node")
|
|
104
|
+
abort = True
|
|
105
|
+
|
|
106
|
+
if abort:
|
|
107
|
+
event = Event.from_rid(EventType.FORGET, kobj.rid)
|
|
108
|
+
processor.network.push_event_to(event, peer_rid, flush=True)
|
|
109
|
+
return STOP_CHAIN
|
|
110
|
+
|
|
111
|
+
else:
|
|
112
|
+
# approve edge profile
|
|
113
|
+
logger.debug("Approving proposed edge")
|
|
114
|
+
edge_profile.status = EdgeStatus.APPROVED
|
|
115
|
+
updated_bundle = Bundle.generate(kobj.rid, edge_profile.model_dump())
|
|
116
|
+
|
|
117
|
+
processor.handle(bundle=updated_bundle, event_type=EventType.UPDATE)
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
elif edge_profile.target == processor.identity.rid:
|
|
121
|
+
if edge_profile.status == EdgeStatus.APPROVED:
|
|
122
|
+
logger.debug("Edge approved by other node!")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Network handlers
|
|
126
|
+
|
|
127
|
+
@KnowledgeHandler.create(HandlerType.Network)
|
|
128
|
+
def basic_network_output_filter(processor: ProcessorInterface, kobj: KnowledgeObject):
|
|
129
|
+
"""Default network handler.
|
|
130
|
+
|
|
131
|
+
Allows broadcasting of all RID types this node is an event provider for (set in node profile), and other nodes have subscribed to. All nodes will also broadcast about their own (internally sourced) KOI node, and KOI edges that they are part of, regardless of their node profile configuration. Finally, nodes will also broadcast about edges to the other node involved (regardless of if they are subscribed)."""
|
|
132
|
+
|
|
133
|
+
involves_me = False
|
|
134
|
+
if kobj.source == KnowledgeSource.Internal:
|
|
135
|
+
if (type(kobj.rid) == KoiNetNode):
|
|
136
|
+
if (kobj.rid == processor.identity.rid):
|
|
137
|
+
involves_me = True
|
|
138
|
+
|
|
139
|
+
elif type(kobj.rid) == KoiNetEdge:
|
|
140
|
+
edge_profile = kobj.bundle.validate_contents(EdgeProfile)
|
|
141
|
+
|
|
142
|
+
if edge_profile.source == processor.identity.rid:
|
|
143
|
+
logger.debug(f"Adding edge target '{edge_profile.target!r}' to network targets")
|
|
144
|
+
kobj.network_targets.update([edge_profile.target])
|
|
145
|
+
involves_me = True
|
|
146
|
+
|
|
147
|
+
elif edge_profile.target == processor.identity.rid:
|
|
148
|
+
logger.debug(f"Adding edge source '{edge_profile.source!r}' to network targets")
|
|
149
|
+
kobj.network_targets.update([edge_profile.source])
|
|
150
|
+
involves_me = True
|
|
151
|
+
|
|
152
|
+
if (type(kobj.rid) in processor.identity.profile.provides.event or involves_me):
|
|
153
|
+
# broadcasts to subscribers if I'm an event provider of this RID type OR it involves me
|
|
154
|
+
subscribers = processor.network.graph.get_neighbors(
|
|
155
|
+
direction="out",
|
|
156
|
+
allowed_type=type(kobj.rid)
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
logger.debug(f"Updating network targets with '{type(kobj.rid)}' subscribers: {subscribers}")
|
|
160
|
+
kobj.network_targets.update(subscribers)
|
|
161
|
+
|
|
162
|
+
return kobj
|
|
163
163
|
|
koi_net/processor/handler.py
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from enum import StrEnum
|
|
3
|
-
from typing import Callable
|
|
4
|
-
from rid_lib import RIDType
|
|
5
|
-
|
|
6
|
-
from ..protocol.event import EventType
|
|
7
|
-
from .knowledge_object import KnowledgeSource, KnowledgeEventType
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class StopChain:
|
|
11
|
-
"""Class for a sentinel value by knowledge handlers."""
|
|
12
|
-
pass
|
|
13
|
-
|
|
14
|
-
STOP_CHAIN = StopChain()
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class HandlerType(StrEnum):
|
|
18
|
-
"""Types of handlers used in knowledge processing pipeline.
|
|
19
|
-
|
|
20
|
-
- 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).
|
|
21
|
-
- Manifest - provided RID, manifest; decides whether to validate the bundle (and fetch it if not provided).
|
|
22
|
-
- Bundle - provided RID, manifest, contents (bundle); decides whether to write knowledge to the cache by setting the normalized event type to `NEW` or `UPDATE`.
|
|
23
|
-
- 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.)
|
|
24
|
-
- Final - provided RID, manifests, contents (bundle); final action taken after network broadcast.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
RID = "rid",
|
|
28
|
-
Manifest = "manifest",
|
|
29
|
-
Bundle = "bundle",
|
|
30
|
-
Network = "network",
|
|
31
|
-
Final = "final"
|
|
32
|
-
|
|
33
|
-
@dataclass
|
|
34
|
-
class KnowledgeHandler:
|
|
35
|
-
"""Handles knowledge processing events of the provided types."""
|
|
36
|
-
|
|
37
|
-
func: Callable
|
|
38
|
-
handler_type: HandlerType
|
|
39
|
-
rid_types: list[RIDType] | None
|
|
40
|
-
source: KnowledgeSource | None = None
|
|
41
|
-
event_types: list[KnowledgeEventType] | None = None
|
|
42
|
-
|
|
43
|
-
@classmethod
|
|
44
|
-
def create(
|
|
45
|
-
cls,
|
|
46
|
-
handler_type: HandlerType,
|
|
47
|
-
rid_types: list[RIDType] | None = None,
|
|
48
|
-
source: KnowledgeSource | None = None,
|
|
49
|
-
event_types: list[KnowledgeEventType] | None = None
|
|
50
|
-
):
|
|
51
|
-
"""Special decorator that returns a KnowledgeHandler instead of a function.
|
|
52
|
-
|
|
53
|
-
The function symbol will redefined as a `KnowledgeHandler`, which can be passed into the `ProcessorInterface` constructor. This is used to register default handlers.
|
|
54
|
-
"""
|
|
55
|
-
def decorator(func: Callable) -> KnowledgeHandler:
|
|
56
|
-
handler = cls(func, handler_type, rid_types, source, event_types)
|
|
57
|
-
return handler
|
|
58
|
-
return decorator
|
|
59
|
-
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from enum import StrEnum
|
|
3
|
+
from typing import Callable
|
|
4
|
+
from rid_lib import RIDType
|
|
5
|
+
|
|
6
|
+
from ..protocol.event import EventType
|
|
7
|
+
from .knowledge_object import KnowledgeSource, KnowledgeEventType
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class StopChain:
|
|
11
|
+
"""Class for a sentinel value by knowledge handlers."""
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
STOP_CHAIN = StopChain()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class HandlerType(StrEnum):
|
|
18
|
+
"""Types of handlers used in knowledge processing pipeline.
|
|
19
|
+
|
|
20
|
+
- 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).
|
|
21
|
+
- Manifest - provided RID, manifest; decides whether to validate the bundle (and fetch it if not provided).
|
|
22
|
+
- Bundle - provided RID, manifest, contents (bundle); decides whether to write knowledge to the cache by setting the normalized event type to `NEW` or `UPDATE`.
|
|
23
|
+
- 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.)
|
|
24
|
+
- Final - provided RID, manifests, contents (bundle); final action taken after network broadcast.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
RID = "rid",
|
|
28
|
+
Manifest = "manifest",
|
|
29
|
+
Bundle = "bundle",
|
|
30
|
+
Network = "network",
|
|
31
|
+
Final = "final"
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class KnowledgeHandler:
|
|
35
|
+
"""Handles knowledge processing events of the provided types."""
|
|
36
|
+
|
|
37
|
+
func: Callable
|
|
38
|
+
handler_type: HandlerType
|
|
39
|
+
rid_types: list[RIDType] | None
|
|
40
|
+
source: KnowledgeSource | None = None
|
|
41
|
+
event_types: list[KnowledgeEventType] | None = None
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def create(
|
|
45
|
+
cls,
|
|
46
|
+
handler_type: HandlerType,
|
|
47
|
+
rid_types: list[RIDType] | None = None,
|
|
48
|
+
source: KnowledgeSource | None = None,
|
|
49
|
+
event_types: list[KnowledgeEventType] | None = None
|
|
50
|
+
):
|
|
51
|
+
"""Special decorator that returns a KnowledgeHandler instead of a function.
|
|
52
|
+
|
|
53
|
+
The function symbol will redefined as a `KnowledgeHandler`, which can be passed into the `ProcessorInterface` constructor. This is used to register default handlers.
|
|
54
|
+
"""
|
|
55
|
+
def decorator(func: Callable) -> KnowledgeHandler:
|
|
56
|
+
handler = cls(func, handler_type, rid_types, source, event_types)
|
|
57
|
+
return handler
|
|
58
|
+
return decorator
|
|
59
|
+
|