koi-net 1.1.0b8__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.
- koi_net/__init__.py +2 -1
- koi_net/assembler.py +82 -0
- koi_net/cli/__init__.py +1 -0
- koi_net/cli/commands.py +99 -0
- koi_net/cli/models.py +41 -0
- koi_net/config.py +34 -0
- koi_net/context.py +11 -28
- koi_net/core.py +63 -179
- koi_net/default_actions.py +10 -1
- koi_net/effector.py +61 -34
- koi_net/handshaker.py +39 -0
- koi_net/identity.py +2 -3
- koi_net/interfaces/entrypoint.py +5 -0
- koi_net/interfaces/worker.py +17 -0
- koi_net/lifecycle.py +85 -48
- koi_net/logger.py +176 -0
- koi_net/network/error_handler.py +18 -16
- koi_net/network/event_queue.py +17 -185
- koi_net/network/graph.py +15 -10
- koi_net/network/poll_event_buffer.py +26 -0
- koi_net/network/request_handler.py +54 -47
- koi_net/network/resolver.py +18 -21
- koi_net/network/response_handler.py +79 -15
- koi_net/poller.py +18 -9
- koi_net/processor/event_worker.py +117 -0
- koi_net/processor/handler.py +4 -2
- koi_net/processor/{default_handlers.py → handlers.py} +109 -59
- koi_net/processor/knowledge_object.py +19 -7
- koi_net/processor/kobj_queue.py +51 -0
- koi_net/processor/kobj_worker.py +44 -0
- koi_net/processor/{knowledge_pipeline.py → pipeline.py} +31 -53
- koi_net/protocol/api_models.py +7 -3
- koi_net/protocol/envelope.py +5 -6
- koi_net/protocol/model_map.py +61 -0
- koi_net/protocol/node.py +3 -3
- koi_net/protocol/secure.py +8 -8
- koi_net/secure.py +33 -13
- koi_net/sentry.py +13 -0
- koi_net/server.py +44 -78
- koi_net/utils.py +18 -0
- {koi_net-1.1.0b8.dist-info → koi_net-1.2.0b2.dist-info}/METADATA +8 -3
- koi_net-1.2.0b2.dist-info/RECORD +52 -0
- koi_net-1.2.0b2.dist-info/entry_points.txt +2 -0
- koi_net/actor.py +0 -60
- koi_net/processor/interface.py +0 -101
- koi_net-1.1.0b8.dist-info/RECORD +0 -38
- {koi_net-1.1.0b8.dist-info → koi_net-1.2.0b2.dist-info}/WHEEL +0 -0
- {koi_net-1.1.0b8.dist-info → koi_net-1.2.0b2.dist-info}/licenses/LICENSE +0 -0
koi_net/network/resolver.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import structlog
|
|
2
2
|
import httpx
|
|
3
3
|
from rid_lib import RID
|
|
4
4
|
from rid_lib.core import RIDType
|
|
@@ -12,17 +12,15 @@ from ..protocol.event import Event
|
|
|
12
12
|
from ..protocol.api_models import ErrorResponse
|
|
13
13
|
from ..identity import NodeIdentity
|
|
14
14
|
from ..config import NodeConfig
|
|
15
|
-
from ..effector import Effector
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
log = structlog.stdlib.get_logger()
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class NetworkResolver:
|
|
21
|
-
"""
|
|
20
|
+
"""Handles resolving nodes or knowledge objects from the network."""
|
|
22
21
|
|
|
23
22
|
config: NodeConfig
|
|
24
23
|
identity: NodeIdentity
|
|
25
|
-
effector: Effector
|
|
26
24
|
cache: Cache
|
|
27
25
|
graph: NetworkGraph
|
|
28
26
|
request_handler: RequestHandler
|
|
@@ -32,7 +30,6 @@ class NetworkResolver:
|
|
|
32
30
|
config: NodeConfig,
|
|
33
31
|
cache: Cache,
|
|
34
32
|
identity: NodeIdentity,
|
|
35
|
-
effector: Effector,
|
|
36
33
|
graph: NetworkGraph,
|
|
37
34
|
request_handler: RequestHandler,
|
|
38
35
|
):
|
|
@@ -41,15 +38,14 @@ class NetworkResolver:
|
|
|
41
38
|
self.cache = cache
|
|
42
39
|
self.graph = graph
|
|
43
40
|
self.request_handler = request_handler
|
|
44
|
-
self.effector = effector
|
|
45
41
|
|
|
46
42
|
self.poll_event_queue = dict()
|
|
47
43
|
self.webhook_event_queue = dict()
|
|
48
44
|
|
|
49
45
|
def get_state_providers(self, rid_type: RIDType) -> list[KoiNetNode]:
|
|
50
|
-
"""Returns list of node RIDs which provide state for
|
|
46
|
+
"""Returns list of node RIDs which provide state for specified RID type."""
|
|
51
47
|
|
|
52
|
-
|
|
48
|
+
log.debug(f"Looking for state providers of {rid_type}")
|
|
53
49
|
provider_nodes = []
|
|
54
50
|
for node_rid in self.cache.list_rids(rid_types=[KoiNetNode]):
|
|
55
51
|
if node_rid == self.identity.rid:
|
|
@@ -60,17 +56,17 @@ class NetworkResolver:
|
|
|
60
56
|
node_profile = node_bundle.validate_contents(NodeProfile)
|
|
61
57
|
|
|
62
58
|
if (node_profile.node_type == NodeType.FULL) and (rid_type in node_profile.provides.state):
|
|
63
|
-
|
|
59
|
+
log.debug(f"Found provider {node_rid!r}")
|
|
64
60
|
provider_nodes.append(node_rid)
|
|
65
61
|
|
|
66
62
|
if not provider_nodes:
|
|
67
|
-
|
|
63
|
+
log.debug("Failed to find providers")
|
|
68
64
|
return provider_nodes
|
|
69
65
|
|
|
70
66
|
def fetch_remote_bundle(self, rid: RID) -> tuple[Bundle | None, KoiNetNode | None]:
|
|
71
67
|
"""Attempts to fetch a bundle by RID from known peer nodes."""
|
|
72
68
|
|
|
73
|
-
|
|
69
|
+
log.debug(f"Fetching remote bundle {rid!r}")
|
|
74
70
|
remote_bundle, node_rid = None, None
|
|
75
71
|
for node_rid in self.get_state_providers(type(rid)):
|
|
76
72
|
payload = self.request_handler.fetch_bundles(
|
|
@@ -78,18 +74,18 @@ class NetworkResolver:
|
|
|
78
74
|
|
|
79
75
|
if payload.bundles:
|
|
80
76
|
remote_bundle = payload.bundles[0]
|
|
81
|
-
|
|
77
|
+
log.debug(f"Got bundle from {node_rid!r}")
|
|
82
78
|
break
|
|
83
79
|
|
|
84
80
|
if not remote_bundle:
|
|
85
|
-
|
|
81
|
+
log.warning("Failed to fetch remote bundle")
|
|
86
82
|
|
|
87
83
|
return remote_bundle, node_rid
|
|
88
84
|
|
|
89
85
|
def fetch_remote_manifest(self, rid: RID) -> tuple[Bundle | None, KoiNetNode | None]:
|
|
90
86
|
"""Attempts to fetch a manifest by RID from known peer nodes."""
|
|
91
87
|
|
|
92
|
-
|
|
88
|
+
log.debug(f"Fetching remote manifest {rid!r}")
|
|
93
89
|
remote_manifest, node_rid = None, None
|
|
94
90
|
for node_rid in self.get_state_providers(type(rid)):
|
|
95
91
|
payload = self.request_handler.fetch_manifests(
|
|
@@ -97,18 +93,19 @@ class NetworkResolver:
|
|
|
97
93
|
|
|
98
94
|
if payload.manifests:
|
|
99
95
|
remote_manifest = payload.manifests[0]
|
|
100
|
-
|
|
96
|
+
log.debug(f"Got bundle from {node_rid!r}")
|
|
101
97
|
break
|
|
102
98
|
|
|
103
99
|
if not remote_manifest:
|
|
104
|
-
|
|
100
|
+
log.warning("Failed to fetch remote bundle")
|
|
105
101
|
|
|
106
102
|
return remote_manifest, node_rid
|
|
107
103
|
|
|
108
104
|
def poll_neighbors(self) -> dict[KoiNetNode, list[Event]]:
|
|
109
|
-
"""Polls all
|
|
105
|
+
"""Polls all neighbor nodes and returns compiled list of events.
|
|
110
106
|
|
|
111
|
-
|
|
107
|
+
Neighbor nodes also include the first contact, regardless of
|
|
108
|
+
whether the first contact profile is known to this node.
|
|
112
109
|
"""
|
|
113
110
|
|
|
114
111
|
graph_neighbors = self.graph.get_neighbors()
|
|
@@ -139,12 +136,12 @@ class NetworkResolver:
|
|
|
139
136
|
continue
|
|
140
137
|
|
|
141
138
|
if payload.events:
|
|
142
|
-
|
|
139
|
+
log.debug(f"Received {len(payload.events)} events from {node_rid!r}")
|
|
143
140
|
|
|
144
141
|
event_dict[node_rid] = payload.events
|
|
145
142
|
|
|
146
143
|
except httpx.ConnectError:
|
|
147
|
-
|
|
144
|
+
log.debug(f"Failed to reach node {node_rid!r}")
|
|
148
145
|
continue
|
|
149
146
|
|
|
150
147
|
return event_dict
|
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import structlog
|
|
2
2
|
from rid_lib import RID
|
|
3
3
|
from rid_lib.types import KoiNetNode
|
|
4
4
|
from rid_lib.ext import Manifest, Cache
|
|
5
5
|
from rid_lib.ext.bundle import Bundle
|
|
6
6
|
|
|
7
|
+
from koi_net.network.poll_event_buffer import PollEventBuffer
|
|
8
|
+
from koi_net.processor.kobj_queue import KobjQueue
|
|
9
|
+
from koi_net.protocol.consts import BROADCAST_EVENTS_PATH, FETCH_BUNDLES_PATH, FETCH_MANIFESTS_PATH, FETCH_RIDS_PATH, POLL_EVENTS_PATH
|
|
10
|
+
from koi_net.protocol.envelope import SignedEnvelope
|
|
11
|
+
from koi_net.protocol.model_map import API_MODEL_MAP
|
|
12
|
+
from koi_net.secure import Secure
|
|
13
|
+
|
|
7
14
|
from ..protocol.api_models import (
|
|
15
|
+
ApiModels,
|
|
16
|
+
EventsPayload,
|
|
17
|
+
PollEvents,
|
|
8
18
|
RidsPayload,
|
|
9
19
|
ManifestsPayload,
|
|
10
20
|
BundlesPayload,
|
|
@@ -12,39 +22,88 @@ from ..protocol.api_models import (
|
|
|
12
22
|
FetchManifests,
|
|
13
23
|
FetchBundles,
|
|
14
24
|
)
|
|
15
|
-
from ..effector import Effector
|
|
16
25
|
|
|
17
|
-
|
|
26
|
+
log = structlog.stdlib.get_logger()
|
|
18
27
|
|
|
19
28
|
|
|
20
29
|
class ResponseHandler:
|
|
21
30
|
"""Handles generating responses to requests from other KOI nodes."""
|
|
22
31
|
|
|
23
32
|
cache: Cache
|
|
24
|
-
|
|
33
|
+
kobj_queue: KobjQueue
|
|
34
|
+
poll_event_buf: PollEventBuffer
|
|
25
35
|
|
|
26
36
|
def __init__(
|
|
27
37
|
self,
|
|
28
|
-
cache: Cache,
|
|
29
|
-
|
|
38
|
+
cache: Cache,
|
|
39
|
+
kobj_queue: KobjQueue,
|
|
40
|
+
poll_event_buf: PollEventBuffer,
|
|
41
|
+
secure: Secure
|
|
30
42
|
):
|
|
31
43
|
self.cache = cache
|
|
32
|
-
self.
|
|
44
|
+
self.kobj_queue = kobj_queue
|
|
45
|
+
self.poll_event_buf = poll_event_buf
|
|
46
|
+
self.secure = secure
|
|
47
|
+
|
|
48
|
+
def handle_response(self, path: str, req: SignedEnvelope):
|
|
49
|
+
self.secure.validate_envelope(req)
|
|
50
|
+
|
|
51
|
+
response_map = {
|
|
52
|
+
BROADCAST_EVENTS_PATH: self.broadcast_events_handler,
|
|
53
|
+
POLL_EVENTS_PATH: self.poll_events_handler,
|
|
54
|
+
FETCH_RIDS_PATH: self.fetch_rids_handler,
|
|
55
|
+
FETCH_MANIFESTS_PATH: self.fetch_manifests_handler,
|
|
56
|
+
FETCH_BUNDLES_PATH: self.fetch_bundles_handler
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
response = response_map[path](req.payload, req.source_node)
|
|
60
|
+
|
|
61
|
+
if response is None:
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
return self.secure.create_envelope(
|
|
65
|
+
payload=response,
|
|
66
|
+
target=req.source_node
|
|
67
|
+
)
|
|
33
68
|
|
|
34
|
-
def
|
|
35
|
-
|
|
69
|
+
def broadcast_events_handler(self, req: EventsPayload, source: KoiNetNode):
|
|
70
|
+
log.info(f"Request to broadcast events, received {len(req.events)} event(s)")
|
|
71
|
+
|
|
72
|
+
for event in req.events:
|
|
73
|
+
self.kobj_queue.put_kobj(event=event, source=source)
|
|
74
|
+
|
|
75
|
+
def poll_events_handler(
|
|
76
|
+
self,
|
|
77
|
+
req: PollEvents,
|
|
78
|
+
source: KoiNetNode
|
|
79
|
+
) -> EventsPayload:
|
|
80
|
+
log.info(f"Request to poll events")
|
|
81
|
+
events = self.poll_event_buf.flush(source, limit=req.limit)
|
|
82
|
+
return EventsPayload(events=events)
|
|
83
|
+
|
|
84
|
+
def fetch_rids_handler(
|
|
85
|
+
self,
|
|
86
|
+
req: FetchRids,
|
|
87
|
+
source: KoiNetNode
|
|
88
|
+
) -> RidsPayload:
|
|
89
|
+
"""Returns response to fetch RIDs request."""
|
|
90
|
+
log.info(f"Request to fetch rids, allowed types {req.rid_types}")
|
|
36
91
|
rids = self.cache.list_rids(req.rid_types)
|
|
37
92
|
|
|
38
93
|
return RidsPayload(rids=rids)
|
|
39
94
|
|
|
40
|
-
def
|
|
41
|
-
|
|
95
|
+
def fetch_manifests_handler(self,
|
|
96
|
+
req: FetchManifests,
|
|
97
|
+
source: KoiNetNode
|
|
98
|
+
) -> ManifestsPayload:
|
|
99
|
+
"""Returns response to fetch manifests request."""
|
|
100
|
+
log.info(f"Request to fetch manifests, allowed types {req.rid_types}, rids {req.rids}")
|
|
42
101
|
|
|
43
102
|
manifests: list[Manifest] = []
|
|
44
103
|
not_found: list[RID] = []
|
|
45
104
|
|
|
46
105
|
for rid in (req.rids or self.cache.list_rids(req.rid_types)):
|
|
47
|
-
bundle = self.
|
|
106
|
+
bundle = self.cache.read(rid)
|
|
48
107
|
if bundle:
|
|
49
108
|
manifests.append(bundle.manifest)
|
|
50
109
|
else:
|
|
@@ -52,14 +111,19 @@ class ResponseHandler:
|
|
|
52
111
|
|
|
53
112
|
return ManifestsPayload(manifests=manifests, not_found=not_found)
|
|
54
113
|
|
|
55
|
-
def
|
|
56
|
-
|
|
114
|
+
def fetch_bundles_handler(
|
|
115
|
+
self,
|
|
116
|
+
req: FetchBundles,
|
|
117
|
+
source: KoiNetNode
|
|
118
|
+
) -> BundlesPayload:
|
|
119
|
+
"""Returns response to fetch bundles request."""
|
|
120
|
+
log.info(f"Request to fetch bundles, requested rids {req.rids}")
|
|
57
121
|
|
|
58
122
|
bundles: list[Bundle] = []
|
|
59
123
|
not_found: list[RID] = []
|
|
60
124
|
|
|
61
125
|
for rid in req.rids:
|
|
62
|
-
bundle = self.
|
|
126
|
+
bundle = self.cache.read(rid)
|
|
63
127
|
if bundle:
|
|
64
128
|
bundles.append(bundle)
|
|
65
129
|
else:
|
koi_net/poller.py
CHANGED
|
@@ -1,35 +1,44 @@
|
|
|
1
1
|
|
|
2
2
|
import time
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import structlog
|
|
4
|
+
|
|
5
|
+
from koi_net.interfaces.entrypoint import EntryPoint
|
|
6
|
+
from .processor.kobj_queue import KobjQueue
|
|
5
7
|
from .lifecycle import NodeLifecycle
|
|
6
8
|
from .network.resolver import NetworkResolver
|
|
7
9
|
from .config import NodeConfig
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
log = structlog.stdlib.get_logger()
|
|
10
12
|
|
|
11
13
|
|
|
12
|
-
class NodePoller:
|
|
14
|
+
class NodePoller(EntryPoint):
|
|
15
|
+
"""Manages polling based event loop for partial nodes."""
|
|
16
|
+
kobj_queue: KobjQueue
|
|
17
|
+
lifecycle: NodeLifecycle
|
|
18
|
+
resolver: NetworkResolver
|
|
19
|
+
config: NodeConfig
|
|
20
|
+
|
|
13
21
|
def __init__(
|
|
14
22
|
self,
|
|
15
|
-
|
|
23
|
+
config: NodeConfig,
|
|
16
24
|
lifecycle: NodeLifecycle,
|
|
25
|
+
kobj_queue: KobjQueue,
|
|
17
26
|
resolver: NetworkResolver,
|
|
18
|
-
config: NodeConfig
|
|
19
27
|
):
|
|
20
|
-
self.
|
|
28
|
+
self.kobj_queue = kobj_queue
|
|
21
29
|
self.lifecycle = lifecycle
|
|
22
30
|
self.resolver = resolver
|
|
23
31
|
self.config = config
|
|
24
32
|
|
|
25
33
|
def poll(self):
|
|
34
|
+
"""Polls neighbors and processes returned events."""
|
|
26
35
|
neighbors = self.resolver.poll_neighbors()
|
|
27
36
|
for node_rid in neighbors:
|
|
28
37
|
for event in neighbors[node_rid]:
|
|
29
|
-
self.
|
|
30
|
-
self.processor.flush_kobj_queue()
|
|
38
|
+
self.kobj_queue.put_kobj(event=event, source=node_rid)
|
|
31
39
|
|
|
32
40
|
def run(self):
|
|
41
|
+
"""Runs polling event loop."""
|
|
33
42
|
with self.lifecycle.run():
|
|
34
43
|
while True:
|
|
35
44
|
start_time = time.time()
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import queue
|
|
2
|
+
import traceback
|
|
3
|
+
import time
|
|
4
|
+
import structlog
|
|
5
|
+
|
|
6
|
+
from rid_lib.ext import Cache
|
|
7
|
+
from rid_lib.types import KoiNetNode
|
|
8
|
+
|
|
9
|
+
from koi_net.config import NodeConfig
|
|
10
|
+
from koi_net.network.event_queue import EventQueue, QueuedEvent
|
|
11
|
+
from koi_net.network.request_handler import RequestHandler
|
|
12
|
+
from koi_net.network.poll_event_buffer import PollEventBuffer
|
|
13
|
+
from koi_net.protocol.event import Event
|
|
14
|
+
from koi_net.protocol.node import NodeProfile, NodeType
|
|
15
|
+
from koi_net.interfaces.worker import ThreadWorker, STOP_WORKER
|
|
16
|
+
|
|
17
|
+
log = structlog.stdlib.get_logger()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EventProcessingWorker(ThreadWorker):
|
|
21
|
+
event_buffer: dict[KoiNetNode, list[Event]]
|
|
22
|
+
buffer_times: dict[KoiNetNode, float]
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
event_queue: EventQueue,
|
|
27
|
+
request_handler: RequestHandler,
|
|
28
|
+
config: NodeConfig,
|
|
29
|
+
cache: Cache,
|
|
30
|
+
poll_event_buf: PollEventBuffer
|
|
31
|
+
):
|
|
32
|
+
self.event_queue = event_queue
|
|
33
|
+
self.request_handler = request_handler
|
|
34
|
+
|
|
35
|
+
self.config = config
|
|
36
|
+
self.cache = cache
|
|
37
|
+
self.poll_event_buf = poll_event_buf
|
|
38
|
+
|
|
39
|
+
self.timeout: float = 0.1
|
|
40
|
+
self.max_buf_len: int = 5
|
|
41
|
+
self.max_wait_time: float = 1.0
|
|
42
|
+
|
|
43
|
+
self.event_buffer = dict()
|
|
44
|
+
self.buffer_times = dict()
|
|
45
|
+
|
|
46
|
+
super().__init__()
|
|
47
|
+
|
|
48
|
+
def flush_buffer(self, target: KoiNetNode, buffer: list[Event]):
|
|
49
|
+
try:
|
|
50
|
+
self.request_handler.broadcast_events(target, events=buffer)
|
|
51
|
+
except Exception as e:
|
|
52
|
+
traceback.print_exc()
|
|
53
|
+
|
|
54
|
+
self.event_buffer[target] = []
|
|
55
|
+
self.buffer_times[target] = None
|
|
56
|
+
|
|
57
|
+
def decide_event(self, item: QueuedEvent) -> bool:
|
|
58
|
+
node_bundle = self.cache.read(item.target)
|
|
59
|
+
if node_bundle:
|
|
60
|
+
node_profile = node_bundle.validate_contents(NodeProfile)
|
|
61
|
+
|
|
62
|
+
if node_profile.node_type == NodeType.FULL:
|
|
63
|
+
return True
|
|
64
|
+
|
|
65
|
+
elif node_profile.node_type == NodeType.PARTIAL:
|
|
66
|
+
self.poll_event_buf.put(item.target, item.event)
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
elif item.target == self.config.koi_net.first_contact.rid:
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
else:
|
|
73
|
+
log.warning(f"Couldn't handle event {item.event!r} in queue, node {item.target!r} unknown to me")
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def run(self):
|
|
78
|
+
log.info("Started event worker")
|
|
79
|
+
while True:
|
|
80
|
+
now = time.time()
|
|
81
|
+
try:
|
|
82
|
+
item = self.event_queue.q.get(timeout=self.timeout)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
if item is STOP_WORKER:
|
|
86
|
+
log.info(f"Received 'STOP_WORKER' signal, flushing buffer...")
|
|
87
|
+
for target in self.event_buffer.keys():
|
|
88
|
+
self.flush_buffer(target, self.event_buffer[target])
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
log.info(f"Dequeued {item.event!r} -> {item.target!r}")
|
|
92
|
+
|
|
93
|
+
if not self.decide_event(item):
|
|
94
|
+
continue
|
|
95
|
+
|
|
96
|
+
event_buf = self.event_buffer.setdefault(item.target, [])
|
|
97
|
+
if not event_buf:
|
|
98
|
+
self.buffer_times[item.target] = now
|
|
99
|
+
|
|
100
|
+
event_buf.append(item.event)
|
|
101
|
+
|
|
102
|
+
# When new events are dequeued, check buffer for max length
|
|
103
|
+
if len(event_buf) >= self.max_buf_len:
|
|
104
|
+
self.flush_buffer(item.target, event_buf)
|
|
105
|
+
finally:
|
|
106
|
+
self.event_queue.q.task_done()
|
|
107
|
+
|
|
108
|
+
except queue.Empty:
|
|
109
|
+
# On timeout, check all buffers for max wait time
|
|
110
|
+
for target, event_buf in self.event_buffer.items():
|
|
111
|
+
if (len(event_buf) == 0) or (self.buffer_times.get(target) is None):
|
|
112
|
+
continue
|
|
113
|
+
if (now - self.buffer_times[target]) >= self.max_wait_time:
|
|
114
|
+
self.flush_buffer(target, event_buf)
|
|
115
|
+
|
|
116
|
+
except Exception as e:
|
|
117
|
+
traceback.print_exc()
|
koi_net/processor/handler.py
CHANGED
|
@@ -44,9 +44,11 @@ class KnowledgeHandler:
|
|
|
44
44
|
rid_types: list[RIDType] | None = None,
|
|
45
45
|
event_types: list[EventType | None] | None = None
|
|
46
46
|
):
|
|
47
|
-
"""
|
|
47
|
+
"""Decorator wraps a function, returns a KnowledgeHandler.
|
|
48
48
|
|
|
49
|
-
The function symbol will redefined as a `KnowledgeHandler`,
|
|
49
|
+
The function symbol will redefined as a `KnowledgeHandler`,
|
|
50
|
+
which can be passed into the `ProcessorInterface` constructor.
|
|
51
|
+
This is used to register default handlers.
|
|
50
52
|
"""
|
|
51
53
|
def decorator(func: Callable) -> KnowledgeHandler:
|
|
52
54
|
handler = cls(func, handler_type, rid_types, event_types)
|