hat-event 0.9.27__cp310.cp311.cp312.cp313-abi3-win_amd64.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.
Files changed (73) hide show
  1. hat/event/__init__.py +1 -0
  2. hat/event/adminer/__init__.py +18 -0
  3. hat/event/adminer/client.py +124 -0
  4. hat/event/adminer/common.py +27 -0
  5. hat/event/adminer/server.py +111 -0
  6. hat/event/backends/__init__.py +0 -0
  7. hat/event/backends/dummy.py +49 -0
  8. hat/event/backends/lmdb/__init__.py +9 -0
  9. hat/event/backends/lmdb/backend.py +319 -0
  10. hat/event/backends/lmdb/common.py +277 -0
  11. hat/event/backends/lmdb/conditions.py +102 -0
  12. hat/event/backends/lmdb/convert/__init__.py +0 -0
  13. hat/event/backends/lmdb/convert/__main__.py +8 -0
  14. hat/event/backends/lmdb/convert/convert_v06_to_v07.py +213 -0
  15. hat/event/backends/lmdb/convert/convert_v07_to_v09.py +175 -0
  16. hat/event/backends/lmdb/convert/main.py +88 -0
  17. hat/event/backends/lmdb/convert/v06.py +216 -0
  18. hat/event/backends/lmdb/convert/v07.py +508 -0
  19. hat/event/backends/lmdb/convert/v09.py +50 -0
  20. hat/event/backends/lmdb/convert/version.py +63 -0
  21. hat/event/backends/lmdb/environment.py +100 -0
  22. hat/event/backends/lmdb/latestdb.py +116 -0
  23. hat/event/backends/lmdb/manager/__init__.py +0 -0
  24. hat/event/backends/lmdb/manager/__main__.py +8 -0
  25. hat/event/backends/lmdb/manager/common.py +45 -0
  26. hat/event/backends/lmdb/manager/copy.py +92 -0
  27. hat/event/backends/lmdb/manager/main.py +34 -0
  28. hat/event/backends/lmdb/manager/query.py +215 -0
  29. hat/event/backends/lmdb/refdb.py +234 -0
  30. hat/event/backends/lmdb/systemdb.py +102 -0
  31. hat/event/backends/lmdb/timeseriesdb.py +486 -0
  32. hat/event/backends/memory.py +178 -0
  33. hat/event/common/__init__.py +144 -0
  34. hat/event/common/backend.py +91 -0
  35. hat/event/common/collection/__init__.py +8 -0
  36. hat/event/common/collection/common.py +28 -0
  37. hat/event/common/collection/list.py +19 -0
  38. hat/event/common/collection/tree.py +62 -0
  39. hat/event/common/common.py +176 -0
  40. hat/event/common/encoder.py +305 -0
  41. hat/event/common/json_schema_repo.json +1 -0
  42. hat/event/common/matches.py +44 -0
  43. hat/event/common/module.py +142 -0
  44. hat/event/common/sbs_repo.json +1 -0
  45. hat/event/common/subscription/__init__.py +22 -0
  46. hat/event/common/subscription/_csubscription.abi3.pyd +0 -0
  47. hat/event/common/subscription/common.py +145 -0
  48. hat/event/common/subscription/csubscription.py +47 -0
  49. hat/event/common/subscription/pysubscription.py +97 -0
  50. hat/event/component.py +284 -0
  51. hat/event/eventer/__init__.py +28 -0
  52. hat/event/eventer/client.py +260 -0
  53. hat/event/eventer/common.py +27 -0
  54. hat/event/eventer/server.py +286 -0
  55. hat/event/manager/__init__.py +0 -0
  56. hat/event/manager/__main__.py +8 -0
  57. hat/event/manager/common.py +48 -0
  58. hat/event/manager/main.py +387 -0
  59. hat/event/server/__init__.py +0 -0
  60. hat/event/server/__main__.py +8 -0
  61. hat/event/server/adminer_server.py +43 -0
  62. hat/event/server/engine.py +216 -0
  63. hat/event/server/engine_runner.py +127 -0
  64. hat/event/server/eventer_client.py +205 -0
  65. hat/event/server/eventer_client_runner.py +152 -0
  66. hat/event/server/eventer_server.py +119 -0
  67. hat/event/server/main.py +84 -0
  68. hat/event/server/main_runner.py +212 -0
  69. hat_event-0.9.27.dist-info/LICENSE +202 -0
  70. hat_event-0.9.27.dist-info/METADATA +108 -0
  71. hat_event-0.9.27.dist-info/RECORD +73 -0
  72. hat_event-0.9.27.dist-info/WHEEL +7 -0
  73. hat_event-0.9.27.dist-info/entry_points.txt +5 -0
@@ -0,0 +1,234 @@
1
+ import collections
2
+ import itertools
3
+ import typing
4
+
5
+ import lmdb
6
+
7
+ from hat import util
8
+
9
+ from hat.event.backends.lmdb import common
10
+ from hat.event.backends.lmdb import environment
11
+
12
+
13
+ # depending on dict order for added refs
14
+ class ServerChanges(typing.NamedTuple):
15
+ added: dict[common.EventId,
16
+ tuple[common.Event,
17
+ set[common.EventRef]]]
18
+ removed: dict[common.EventId,
19
+ set[common.EventRef]]
20
+
21
+
22
+ Changes: typing.TypeAlias = dict[common.ServerId, ServerChanges]
23
+
24
+
25
+ class RefDb:
26
+
27
+ def __init__(self,
28
+ env: environment.Environment,
29
+ max_results: int = 4096):
30
+ self._env = env
31
+ self._max_results = max_results
32
+ self._last_event_ids = {}
33
+ self._changes = collections.defaultdict(_create_server_changes)
34
+
35
+ def add(self,
36
+ event: common.Event,
37
+ refs: typing.Iterable[common.EventRef]):
38
+ last_event_id = self._last_event_ids.get(event.id.server)
39
+ if last_event_id and last_event_id > event.id:
40
+ raise Exception('event older than last')
41
+
42
+ self._last_event_ids[event.id.server] = event.id
43
+
44
+ server_changes = self._changes[event.id.server]
45
+ server_changes.added[event.id] = event, set(refs)
46
+
47
+ def remove(self,
48
+ event_id: common.EventId,
49
+ ref: common.EventRef):
50
+ server_changes = self._changes[event_id.server]
51
+ added = server_changes.added.get(event_id)
52
+
53
+ if added and ref in added[1]:
54
+ added[1].remove(ref)
55
+
56
+ if not added[1]:
57
+ server_changes.added.pop(event_id)
58
+
59
+ return
60
+
61
+ removed = server_changes.removed[event_id]
62
+ removed.add(ref)
63
+
64
+ async def query(self,
65
+ params: common.QueryServerParams
66
+ ) -> common.QueryResult:
67
+ if (params.last_event_id and
68
+ params.last_event_id.server != params.server_id):
69
+ raise ValueError('invalid server id')
70
+
71
+ max_results = (params.max_results
72
+ if params.max_results is not None and
73
+ params.max_results < self._max_results
74
+ else self._max_results)
75
+
76
+ changes = self._changes
77
+ events = await self._env.execute(_ext_query_events, self._env,
78
+ params.server_id, max_results + 1,
79
+ params.last_event_id)
80
+
81
+ if not params.persisted and len(events) <= max_results:
82
+ last_event_id = events[-1].id if events else params.last_event_id
83
+ changes_max_result = max_results + 1 - len(events)
84
+ changes_events = _query_changes(changes, params.server_id,
85
+ changes_max_result, last_event_id)
86
+
87
+ events.extend(changes_events)
88
+
89
+ if len(events) > max_results:
90
+ events = list(itertools.islice(events, max_results))
91
+ more_follows = True
92
+
93
+ else:
94
+ events = list(events)
95
+ more_follows = False
96
+
97
+ return common.QueryResult(events=events,
98
+ more_follows=more_follows)
99
+
100
+ def create_changes(self) -> Changes:
101
+ self._changes, changes = (
102
+ collections.defaultdict(_create_server_changes), self._changes)
103
+ return changes
104
+
105
+ def ext_write(self,
106
+ txn: lmdb.Transaction,
107
+ changes: Changes):
108
+ db_def = common.db_defs[common.DbType.REF]
109
+
110
+ with self._env.ext_cursor(txn, common.DbType.REF) as cursor:
111
+ for server_changes in changes.values():
112
+ event_ids = {*server_changes.added.keys(),
113
+ *server_changes.removed.keys()}
114
+
115
+ for event_id in event_ids:
116
+ encoded_key = db_def.encode_key(event_id)
117
+ encoded_value = cursor.pop(encoded_key)
118
+ value = (db_def.decode_value(encoded_value)
119
+ if encoded_value else set())
120
+
121
+ added = server_changes.added.get(event_id)
122
+ if added:
123
+ value.update(added[1])
124
+
125
+ removed = server_changes.removed.get(event_id)
126
+ if removed:
127
+ value.difference_update(removed)
128
+
129
+ if not value:
130
+ continue
131
+
132
+ encoded_value = db_def.encode_value(value)
133
+ cursor.put(encoded_key, encoded_value)
134
+
135
+ def ext_cleanup(self,
136
+ txn: lmdb.Transaction,
137
+ refs: typing.Iterable[tuple[common.EventId,
138
+ common.EventRef]]):
139
+ db_def = common.db_defs[common.DbType.REF]
140
+
141
+ with self._env.ext_cursor(txn, common.DbType.REF) as cursor:
142
+ for event_id, ref in refs:
143
+ encoded_key = db_def.encode_key(event_id)
144
+ encoded_value = cursor.pop(encoded_key)
145
+ if not encoded_value:
146
+ continue
147
+
148
+ value = db_def.decode_value(encoded_value)
149
+ value.discard(ref)
150
+
151
+ if not value:
152
+ continue
153
+
154
+ encoded_value = db_def.encode_value(value)
155
+ cursor.put(encoded_key, encoded_value)
156
+
157
+
158
+ def _query_changes(changes, server_id, max_results, last_event_id):
159
+ server_changes = changes.get(server_id)
160
+ if not server_changes:
161
+ return []
162
+
163
+ events = (event for _, (event, __) in server_changes.added.items())
164
+
165
+ if last_event_id:
166
+ events = itertools.dropwhile(lambda i: i.id <= last_event_id,
167
+ events)
168
+
169
+ return itertools.islice(events, max_results)
170
+
171
+
172
+ def _ext_query_events(env, server_id, max_results, last_event_id):
173
+ db_def = common.db_defs[common.DbType.REF]
174
+
175
+ start_key = (last_event_id if last_event_id
176
+ else common.EventId(server=server_id,
177
+ session=0,
178
+ instance=0))
179
+ stop_key = common.EventId(server=server_id + 1,
180
+ session=0,
181
+ instance=0)
182
+
183
+ encoded_start_key = db_def.encode_key(start_key)
184
+ encoded_stop_key = db_def.encode_key(stop_key)
185
+
186
+ events = collections.deque()
187
+
188
+ with env.ext_begin() as txn:
189
+ with env.ext_cursor(txn, common.DbType.REF) as cursor:
190
+ available = cursor.set_range(encoded_start_key)
191
+ if available and bytes(cursor.key()) == encoded_start_key:
192
+ available = cursor.next()
193
+
194
+ while (available and
195
+ len(events) < max_results and
196
+ bytes(cursor.key()) < encoded_stop_key):
197
+ value = db_def.decode_value(cursor.value())
198
+ ref = util.first(value)
199
+ if not ref:
200
+ continue
201
+
202
+ event = _ext_get_event(env, txn, ref)
203
+ if event:
204
+ # TODO decode key and check event_id == event.id
205
+ events.append(event)
206
+
207
+ available = cursor.next()
208
+
209
+ return events
210
+
211
+
212
+ def _ext_get_event(env, txn, ref):
213
+ if isinstance(ref, common.LatestEventRef):
214
+ db_type = common.DbType.LATEST_DATA
215
+
216
+ elif isinstance(ref, common.TimeseriesEventRef):
217
+ db_type = common.DbType.TIMESERIES_DATA
218
+
219
+ else:
220
+ raise ValueError('unsupported event reference type')
221
+
222
+ db_def = common.db_defs[db_type]
223
+ encoded_key = db_def.encode_key(ref.key)
224
+
225
+ with env.ext_cursor(txn, db_type) as cursor:
226
+ encoded_value = cursor.get(encoded_key)
227
+ if not encoded_value:
228
+ return
229
+
230
+ return db_def.decode_value(encoded_value)
231
+
232
+
233
+ def _create_server_changes():
234
+ return ServerChanges({}, collections.defaultdict(set))
@@ -0,0 +1,102 @@
1
+ import typing
2
+
3
+ import lmdb
4
+
5
+ from hat.event.backends.lmdb import common
6
+ from hat.event.backends.lmdb import environment
7
+
8
+
9
+ class Changes(typing.NamedTuple):
10
+ last_event_ids: dict[common.ServerId, common.EventId]
11
+ last_timestamps: dict[common.ServerId, common.Timestamp]
12
+
13
+
14
+ def ext_create(env: environment.Environment,
15
+ txn: lmdb.Transaction,
16
+ version: str,
17
+ identifier: str | None
18
+ ) -> 'SystemDb':
19
+ db = SystemDb()
20
+ db._env = env
21
+ db._changes = Changes({}, {})
22
+
23
+ _ext_validate_settings(env, txn, version, identifier)
24
+
25
+ db._last_event_ids = dict(
26
+ env.ext_read(txn, common.DbType.SYSTEM_LAST_EVENT_ID))
27
+
28
+ db._last_timestamps = dict(
29
+ env.ext_read(txn, common.DbType.SYSTEM_LAST_TIMESTAMP))
30
+
31
+ return db
32
+
33
+
34
+ class SystemDb:
35
+
36
+ def get_last_event_id(self,
37
+ server_id: common.ServerId
38
+ ) -> common.EventId:
39
+ if server_id in self._last_event_ids:
40
+ return self._last_event_ids[server_id]
41
+
42
+ return common.EventId(server=server_id,
43
+ session=0,
44
+ instance=0)
45
+
46
+ def set_last_event_id(self, event_id: common.EventId):
47
+ self._changes.last_event_ids[event_id.server] = event_id
48
+ self._last_event_ids[event_id.server] = event_id
49
+
50
+ def get_last_timestamp(self,
51
+ server_id: common.ServerId
52
+ ) -> common.Timestamp:
53
+ if server_id in self._last_timestamps:
54
+ return self._last_timestamps[server_id]
55
+
56
+ return common.min_timestamp
57
+
58
+ def set_last_timestamp(self,
59
+ server_id: common.ServerId,
60
+ timestamp: common.Timestamp):
61
+ self._changes.last_timestamps[server_id] = timestamp
62
+ self._last_timestamps[server_id] = timestamp
63
+
64
+ def create_changes(self) -> Changes:
65
+ changes, self._changes = self._changes, Changes({}, {})
66
+ return changes
67
+
68
+ def ext_write(self,
69
+ txn: lmdb.Transaction,
70
+ changes: Changes):
71
+ self._env.ext_write(txn, common.DbType.SYSTEM_LAST_EVENT_ID,
72
+ changes.last_event_ids.items())
73
+
74
+ self._env.ext_write(txn, common.DbType.SYSTEM_LAST_TIMESTAMP,
75
+ changes.last_timestamps.items())
76
+
77
+
78
+ def _ext_validate_settings(env, txn, version, identifier):
79
+ settings = dict(env.ext_read(txn, common.DbType.SYSTEM_SETTINGS))
80
+
81
+ if common.SettingsId.VERSION not in settings:
82
+ settings[common.SettingsId.VERSION] = version
83
+
84
+ elif settings[common.SettingsId.VERSION] != version:
85
+ raise Exception('invalid version')
86
+
87
+ else:
88
+ settings.pop(common.SettingsId.VERSION)
89
+
90
+ if identifier is None:
91
+ settings.pop(common.SettingsId.IDENTIFIER, None)
92
+
93
+ elif common.SettingsId.IDENTIFIER not in settings:
94
+ settings[common.SettingsId.IDENTIFIER] = identifier
95
+
96
+ elif settings[common.SettingsId.IDENTIFIER] != identifier:
97
+ raise Exception('invalid identifier')
98
+
99
+ else:
100
+ settings.pop(common.SettingsId.IDENTIFIER)
101
+
102
+ env.ext_write(txn, common.DbType.SYSTEM_SETTINGS, settings.items())