hat.event.manager.main

  1from collections.abc import Collection
  2from pathlib import Path
  3import argparse
  4import asyncio
  5import contextlib
  6import sys
  7
  8from hat import aio
  9from hat import json
 10from hat.drivers import net
 11
 12from hat.event import eventer
 13from hat.event.manager import common
 14from hat.event.manager import rest
 15from hat.event.manager import server
 16
 17
 18def create_argument_parser() -> argparse.ArgumentParser:
 19    parser = argparse.ArgumentParser()
 20    parser.add_argument(
 21        '--host', type=str, default='127.0.0.1',
 22        help="server host name (default '127.0.0.1')")
 23    parser.add_argument(
 24        '--port', type=int, default='23012',
 25        help="server TCP port (default 23012)")
 26    parser.add_argument(
 27        '--client-name', metavar='NAME', type=str, default='manager',
 28        help="client name (default 'manager')")
 29    parser.add_argument(
 30        '--client-token', metavar='TOKEN', type=str, default=None,
 31        help="client token")
 32    subparsers = parser.add_subparsers(
 33        title='actions', dest='action', required=True)
 34
 35    register_parser = subparsers.add_parser(
 36        'register', description="register new event")
 37    register_parser.add_argument(
 38        '--source-timestamp', metavar='TIMESTAMP', type=_parse_timestamp,
 39        default=None,
 40        help="source timestamp")
 41    register_parser.add_argument(
 42        '--payload-type', metavar='TYPE',
 43        choices=['json', 'yaml', 'toml', 'binary', 'none'],
 44        default=None,
 45        help="payload type")
 46    register_parser.add_argument(
 47        '--binary-type', metavar='TYPE', type=str, default='',
 48        help="binary payload type (default '')")
 49    register_parser.add_argument(
 50        '--payload-path', metavar='PATH', type=Path, default=Path('-'),
 51        help="payload file path or '-' for stdin (default '-')")
 52    register_parser.add_argument(
 53        'event_type', metavar='EVENT_TYPE', type=_parse_event_type,
 54        help="event type where segments are delimited by '/'")
 55
 56    query_parser = subparsers.add_parser(
 57        'query', description="query events")
 58    query_subparsers = query_parser.add_subparsers(
 59        title='query types', dest='query_type', required=True)
 60
 61    query_latest_parser = query_subparsers.add_parser(
 62        'latest', description="query latest events")
 63    query_latest_parser.add_argument(
 64        '--event-types', metavar='EVENT_TYPE', type=_parse_event_type,
 65        default=None, nargs='*',
 66        help='query event types')
 67
 68    query_timeseries_parser = query_subparsers.add_parser(
 69        'timeseries', description="query timeseries events")
 70    query_timeseries_parser.add_argument(
 71        '--event-types', metavar='EVENT_TYPE', type=_parse_event_type,
 72        default=None, nargs='*',
 73        help='query event types')
 74    query_timeseries_parser.add_argument(
 75        '--t-from', metavar='TIMESTAMP', type=_parse_timestamp, default=None,
 76        help="from timestamp")
 77    query_timeseries_parser.add_argument(
 78        '--t-to', metavar='TIMESTAMP', type=_parse_timestamp, default=None,
 79        help="to timestamp")
 80    query_timeseries_parser.add_argument(
 81        '--source-t-from', metavar='TIMESTAMP', type=_parse_timestamp,
 82        default=None,
 83        help="from source timestamp")
 84    query_timeseries_parser.add_argument(
 85        '--source-t-to', metavar='TIMESTAMP', type=_parse_timestamp,
 86        default=None,
 87        help="to source timestamp")
 88    query_timeseries_parser.add_argument(
 89        '--order', type=_parse_order, choices=[i.name for i in common.Order],
 90        default=common.Order.DESCENDING,
 91        help="order (default 'DESCENDING')")
 92    query_timeseries_parser.add_argument(
 93        '--order-by', type=_parse_order_by,
 94        choices=[i.name for i in common.OrderBy],
 95        default=common.OrderBy.TIMESTAMP,
 96        help="order (default 'TIMESTAMP')")
 97    query_timeseries_parser.add_argument(
 98        '--max-results', metavar='N', type=int, default=None,
 99        help="maximum number of results")
100    query_timeseries_parser.add_argument(
101        '--last-event-id', metavar='SERVER_ID,SESSION_ID,INSTANCE_ID',
102        type=_parse_event_id, default=None,
103        help="last event id")
104
105    query_server_parser = query_subparsers.add_parser(
106        'server', description="query server events")
107    query_server_parser.add_argument(
108        '--persisted', action='store_true',
109        help="persisted events")
110    query_server_parser.add_argument(
111        '--max-results', metavar='N', type=int, default=None,
112        help="maximum number of results")
113    query_server_parser.add_argument(
114        '--last-event-id', metavar='SERVER_ID,SESSION_ID,INSTANCE_ID',
115        type=_parse_event_id, default=None,
116        help="last event id")
117    query_server_parser.add_argument(
118        'server_id', metavar='SERVER_ID', type=int,
119        help="server id")
120
121    subscribe_parser = subparsers.add_parser(
122        'subscribe', description="watch newly registered events")
123    subscribe_parser.add_argument(
124        '--server-id', type=int, default=None,
125        help="server id")
126    subscribe_parser.add_argument(
127        '--persisted', action='store_true',
128        help="persisted events")
129    subscribe_parser.add_argument(
130        'event_types', metavar='EVENT_TYPE', type=_parse_event_type, nargs='*',
131        help='query event type')
132
133    server_parser = subparsers.add_parser(
134        'server', description="run manager server with web ui")
135    server_parser.add_argument(
136        '--server-id', type=int, default=None,
137        help="server id")
138    server_parser.add_argument(
139        '--persisted', action='store_true',
140        help="persisted events")
141    server_parser.add_argument(
142        'event_types', metavar='EVENT_TYPE', type=_parse_event_type, nargs='*',
143        help='query event type')
144    server_parser.add_argument(
145        '--http-host', type=str, default='127.0.0.1',
146        help="listening host name (default '127.0.0.1')")
147    server_parser.add_argument(
148        '--http-port', type=int, default=23025,
149        help="listening TCP port (default 23025)")
150
151    rest_parser = subparsers.add_parser(
152        'rest', description="run manager rest api server")
153    rest_parser.add_argument(
154        '--http-host', type=str, default='127.0.0.1',
155        help="listening host name (default '127.0.0.1')")
156    rest_parser.add_argument(
157        '--http-port', type=int, default=23017,
158        help="listening TCP port (default 23017)")
159
160    return parser
161
162
163def main():
164    parser = create_argument_parser()
165    args = parser.parse_args()
166
167    addr = net.TcpAddress(args.host, args.port)
168
169    if args.action == 'register':
170        register_event = common.RegisterEvent(
171            type=args.event_type,
172            source_timestamp=args.source_timestamp,
173            payload=_read_payload(payload_type=args.payload_type,
174                                  binary_type=args.binary_type,
175                                  path=args.payload_path))
176
177        co = register(addr=addr,
178                      client_name=args.client_name,
179                      client_token=args.client_token,
180                      register_event=register_event)
181
182    elif args.action == 'query':
183        if args.query_type == 'latest':
184            params = common.QueryLatestParams(
185                event_types=args.event_types)
186
187        elif args.query_type == 'timeseries':
188            params = common.QueryTimeseriesParams(
189                event_types=args.event_types,
190                t_from=args.t_from,
191                t_to=args.t_to,
192                source_t_from=args.source_t_from,
193                source_t_to=args.source_t_to,
194                order=args.order,
195                order_by=args.order_by,
196                max_results=args.max_results,
197                last_event_id=args.last_event_id)
198
199        elif args.query_type == 'server':
200            params = common.QueryTimeseriesParams(
201                server_id=args.server_id,
202                persisted=args.persisted,
203                max_results=args.max_results,
204                last_event_id=args.last_event_id)
205
206        else:
207            raise ValueError('unsupported query type')
208
209        co = query(addr=addr,
210                   client_name=args.client_name,
211                   client_token=args.client_token,
212                   params=params)
213
214    elif args.action == 'subscribe':
215        subscriptions = args.event_types or [('*', )]
216
217        co = subscribe(addr=addr,
218                       client_name=args.client_name,
219                       client_token=args.client_token,
220                       subscriptions=subscriptions,
221                       server_id=args.server_id,
222                       persisted=args.persisted)
223
224    elif args.action == 'server':
225        subscriptions = args.event_types or [('*', )]
226        http_addr = net.TcpAddress(args.http_host, args.http_port)
227
228        co = server.run(addr=addr,
229                        client_name=args.client_name,
230                        client_token=args.client_token,
231                        subscriptions=subscriptions,
232                        server_id=args.server_id,
233                        persisted=args.persisted,
234                        http_addr=http_addr)
235
236    elif args.action == 'rest':
237        http_addr = net.TcpAddress(args.http_host, args.http_port)
238
239        co = rest.run(addr=addr,
240                      client_name=args.client_name,
241                      client_token=args.client_token,
242                      http_addr=http_addr)
243
244    else:
245        raise ValueError('unsupported action')
246
247    aio.init_asyncio()
248    with contextlib.suppress(asyncio.CancelledError):
249        return aio.run_asyncio(co)
250
251
252async def register(addr: net.StreamAddress,
253                   client_name: str,
254                   client_token: str | None,
255                   register_event: common.RegisterEvent):
256    client = await eventer.connect(addr=addr,
257                                   client_name=client_name,
258                                   client_token=client_token)
259
260    try:
261        result = await client.register([register_event])
262
263        if result is None:
264            return 1
265
266    finally:
267        await aio.uncancellable(client.async_close())
268
269
270async def query(addr: net.StreamAddress,
271                client_name: str,
272                client_token: str | None,
273                params: common.QueryParams):
274    client = await eventer.connect(addr=addr,
275                                   client_name=client_name,
276                                   client_token=client_token)
277
278    try:
279        result = await client.query(params)
280
281        result_json = common.query_result_to_json(result)
282        print(json.encode(result_json))
283
284    finally:
285        await aio.uncancellable(client.async_close())
286
287
288async def subscribe(addr: net.StreamAddress,
289                    client_name: str,
290                    client_token: str | None,
291                    subscriptions: Collection[common.EventType],
292                    server_id: int | None,
293                    persisted: bool):
294
295    def on_events(client, events):
296        events_json = [common.event_to_json(event) for event in events]
297        print(json.encode(events_json))
298
299    client = await eventer.connect(addr=addr,
300                                   client_name=client_name,
301                                   client_token=client_token,
302                                   subscriptions=subscriptions,
303                                   server_id=server_id,
304                                   persisted=persisted,
305                                   events_cb=on_events)
306
307    try:
308        await client.wait_closing()
309
310    finally:
311        await aio.uncancellable(client.async_close())
312
313
314def _parse_timestamp(t):
315    if t == 'now':
316        return common.now()
317
318    return common.timestamp_from_float(float(t))
319
320
321def _parse_event_type(event_type):
322    return tuple(event_type.split('/'))
323
324
325def _parse_event_id(event_id):
326    return common.EventId(event_id.split(','))
327
328
329def _parse_order(order):
330    return common.Order[order]
331
332
333def _parse_order_by(order_by):
334    return common.OrderBy[order_by]
335
336
337def _read_payload(payload_type, binary_type, path):
338    if payload_type == 'none':
339        return
340
341    if path == Path('-'):
342        if payload_type == 'json' or payload_type is None:
343            json_format = json.Format.JSON
344
345        elif payload_type == 'yaml':
346            json_format = json.Format.YAML
347
348        elif payload_type == 'toml':
349            json_format = json.Format.TOML
350
351        elif payload_type == 'binary':
352            json_format = None
353
354        else:
355            raise ValueError('unsupported payload type')
356
357        if json_format is None or json_format == json.Format.TOML:
358            stdin, sys.stdin = sys.stdin.detach(), None
359
360        else:
361            stdin = sys.stdin
362
363        if json_format:
364            data = json.decode_stream(stdin, json_format)
365            return common.EventPayloadJson(data)
366
367        else:
368            data = stdin.read()
369            return common.EventPayloadBinary(type=binary_type,
370                                             data=data)
371
372    if payload_type is None:
373        try:
374            json_format = json.get_file_format(path)
375
376        except ValueError:
377            json_format = None
378
379    elif payload_type == 'json':
380        json_format = json.Format.JSON
381
382    elif payload_type == 'yaml':
383        json_format = json.Format.YAML
384
385    elif payload_type == 'toml':
386        json_format = json.Format.TOML
387
388    elif payload_type == 'binary':
389        json_format = None
390
391    else:
392        raise ValueError('unsupported payload type')
393
394    if json_format:
395        data = json.decode_file(path, json_format)
396        return common.EventPayloadJson(data)
397
398    data = path.read_bytes()
399    return common.EventPayloadBinary(type=binary_type,
400                                     data=data)
401
402
403if __name__ == '__main__':
404    sys.argv[0] = 'hat-event-manager'
405    sys.exit(main())
def create_argument_parser() -> argparse.ArgumentParser:
 19def create_argument_parser() -> argparse.ArgumentParser:
 20    parser = argparse.ArgumentParser()
 21    parser.add_argument(
 22        '--host', type=str, default='127.0.0.1',
 23        help="server host name (default '127.0.0.1')")
 24    parser.add_argument(
 25        '--port', type=int, default='23012',
 26        help="server TCP port (default 23012)")
 27    parser.add_argument(
 28        '--client-name', metavar='NAME', type=str, default='manager',
 29        help="client name (default 'manager')")
 30    parser.add_argument(
 31        '--client-token', metavar='TOKEN', type=str, default=None,
 32        help="client token")
 33    subparsers = parser.add_subparsers(
 34        title='actions', dest='action', required=True)
 35
 36    register_parser = subparsers.add_parser(
 37        'register', description="register new event")
 38    register_parser.add_argument(
 39        '--source-timestamp', metavar='TIMESTAMP', type=_parse_timestamp,
 40        default=None,
 41        help="source timestamp")
 42    register_parser.add_argument(
 43        '--payload-type', metavar='TYPE',
 44        choices=['json', 'yaml', 'toml', 'binary', 'none'],
 45        default=None,
 46        help="payload type")
 47    register_parser.add_argument(
 48        '--binary-type', metavar='TYPE', type=str, default='',
 49        help="binary payload type (default '')")
 50    register_parser.add_argument(
 51        '--payload-path', metavar='PATH', type=Path, default=Path('-'),
 52        help="payload file path or '-' for stdin (default '-')")
 53    register_parser.add_argument(
 54        'event_type', metavar='EVENT_TYPE', type=_parse_event_type,
 55        help="event type where segments are delimited by '/'")
 56
 57    query_parser = subparsers.add_parser(
 58        'query', description="query events")
 59    query_subparsers = query_parser.add_subparsers(
 60        title='query types', dest='query_type', required=True)
 61
 62    query_latest_parser = query_subparsers.add_parser(
 63        'latest', description="query latest events")
 64    query_latest_parser.add_argument(
 65        '--event-types', metavar='EVENT_TYPE', type=_parse_event_type,
 66        default=None, nargs='*',
 67        help='query event types')
 68
 69    query_timeseries_parser = query_subparsers.add_parser(
 70        'timeseries', description="query timeseries events")
 71    query_timeseries_parser.add_argument(
 72        '--event-types', metavar='EVENT_TYPE', type=_parse_event_type,
 73        default=None, nargs='*',
 74        help='query event types')
 75    query_timeseries_parser.add_argument(
 76        '--t-from', metavar='TIMESTAMP', type=_parse_timestamp, default=None,
 77        help="from timestamp")
 78    query_timeseries_parser.add_argument(
 79        '--t-to', metavar='TIMESTAMP', type=_parse_timestamp, default=None,
 80        help="to timestamp")
 81    query_timeseries_parser.add_argument(
 82        '--source-t-from', metavar='TIMESTAMP', type=_parse_timestamp,
 83        default=None,
 84        help="from source timestamp")
 85    query_timeseries_parser.add_argument(
 86        '--source-t-to', metavar='TIMESTAMP', type=_parse_timestamp,
 87        default=None,
 88        help="to source timestamp")
 89    query_timeseries_parser.add_argument(
 90        '--order', type=_parse_order, choices=[i.name for i in common.Order],
 91        default=common.Order.DESCENDING,
 92        help="order (default 'DESCENDING')")
 93    query_timeseries_parser.add_argument(
 94        '--order-by', type=_parse_order_by,
 95        choices=[i.name for i in common.OrderBy],
 96        default=common.OrderBy.TIMESTAMP,
 97        help="order (default 'TIMESTAMP')")
 98    query_timeseries_parser.add_argument(
 99        '--max-results', metavar='N', type=int, default=None,
100        help="maximum number of results")
101    query_timeseries_parser.add_argument(
102        '--last-event-id', metavar='SERVER_ID,SESSION_ID,INSTANCE_ID',
103        type=_parse_event_id, default=None,
104        help="last event id")
105
106    query_server_parser = query_subparsers.add_parser(
107        'server', description="query server events")
108    query_server_parser.add_argument(
109        '--persisted', action='store_true',
110        help="persisted events")
111    query_server_parser.add_argument(
112        '--max-results', metavar='N', type=int, default=None,
113        help="maximum number of results")
114    query_server_parser.add_argument(
115        '--last-event-id', metavar='SERVER_ID,SESSION_ID,INSTANCE_ID',
116        type=_parse_event_id, default=None,
117        help="last event id")
118    query_server_parser.add_argument(
119        'server_id', metavar='SERVER_ID', type=int,
120        help="server id")
121
122    subscribe_parser = subparsers.add_parser(
123        'subscribe', description="watch newly registered events")
124    subscribe_parser.add_argument(
125        '--server-id', type=int, default=None,
126        help="server id")
127    subscribe_parser.add_argument(
128        '--persisted', action='store_true',
129        help="persisted events")
130    subscribe_parser.add_argument(
131        'event_types', metavar='EVENT_TYPE', type=_parse_event_type, nargs='*',
132        help='query event type')
133
134    server_parser = subparsers.add_parser(
135        'server', description="run manager server with web ui")
136    server_parser.add_argument(
137        '--server-id', type=int, default=None,
138        help="server id")
139    server_parser.add_argument(
140        '--persisted', action='store_true',
141        help="persisted events")
142    server_parser.add_argument(
143        'event_types', metavar='EVENT_TYPE', type=_parse_event_type, nargs='*',
144        help='query event type')
145    server_parser.add_argument(
146        '--http-host', type=str, default='127.0.0.1',
147        help="listening host name (default '127.0.0.1')")
148    server_parser.add_argument(
149        '--http-port', type=int, default=23025,
150        help="listening TCP port (default 23025)")
151
152    rest_parser = subparsers.add_parser(
153        'rest', description="run manager rest api server")
154    rest_parser.add_argument(
155        '--http-host', type=str, default='127.0.0.1',
156        help="listening host name (default '127.0.0.1')")
157    rest_parser.add_argument(
158        '--http-port', type=int, default=23017,
159        help="listening TCP port (default 23017)")
160
161    return parser
def main():
164def main():
165    parser = create_argument_parser()
166    args = parser.parse_args()
167
168    addr = net.TcpAddress(args.host, args.port)
169
170    if args.action == 'register':
171        register_event = common.RegisterEvent(
172            type=args.event_type,
173            source_timestamp=args.source_timestamp,
174            payload=_read_payload(payload_type=args.payload_type,
175                                  binary_type=args.binary_type,
176                                  path=args.payload_path))
177
178        co = register(addr=addr,
179                      client_name=args.client_name,
180                      client_token=args.client_token,
181                      register_event=register_event)
182
183    elif args.action == 'query':
184        if args.query_type == 'latest':
185            params = common.QueryLatestParams(
186                event_types=args.event_types)
187
188        elif args.query_type == 'timeseries':
189            params = common.QueryTimeseriesParams(
190                event_types=args.event_types,
191                t_from=args.t_from,
192                t_to=args.t_to,
193                source_t_from=args.source_t_from,
194                source_t_to=args.source_t_to,
195                order=args.order,
196                order_by=args.order_by,
197                max_results=args.max_results,
198                last_event_id=args.last_event_id)
199
200        elif args.query_type == 'server':
201            params = common.QueryTimeseriesParams(
202                server_id=args.server_id,
203                persisted=args.persisted,
204                max_results=args.max_results,
205                last_event_id=args.last_event_id)
206
207        else:
208            raise ValueError('unsupported query type')
209
210        co = query(addr=addr,
211                   client_name=args.client_name,
212                   client_token=args.client_token,
213                   params=params)
214
215    elif args.action == 'subscribe':
216        subscriptions = args.event_types or [('*', )]
217
218        co = subscribe(addr=addr,
219                       client_name=args.client_name,
220                       client_token=args.client_token,
221                       subscriptions=subscriptions,
222                       server_id=args.server_id,
223                       persisted=args.persisted)
224
225    elif args.action == 'server':
226        subscriptions = args.event_types or [('*', )]
227        http_addr = net.TcpAddress(args.http_host, args.http_port)
228
229        co = server.run(addr=addr,
230                        client_name=args.client_name,
231                        client_token=args.client_token,
232                        subscriptions=subscriptions,
233                        server_id=args.server_id,
234                        persisted=args.persisted,
235                        http_addr=http_addr)
236
237    elif args.action == 'rest':
238        http_addr = net.TcpAddress(args.http_host, args.http_port)
239
240        co = rest.run(addr=addr,
241                      client_name=args.client_name,
242                      client_token=args.client_token,
243                      http_addr=http_addr)
244
245    else:
246        raise ValueError('unsupported action')
247
248    aio.init_asyncio()
249    with contextlib.suppress(asyncio.CancelledError):
250        return aio.run_asyncio(co)
async def register( addr: hat.drivers.net.stream.TcpAddress | pathlib.Path, client_name: str, client_token: str | None, register_event: hat.event.common.RegisterEvent):
253async def register(addr: net.StreamAddress,
254                   client_name: str,
255                   client_token: str | None,
256                   register_event: common.RegisterEvent):
257    client = await eventer.connect(addr=addr,
258                                   client_name=client_name,
259                                   client_token=client_token)
260
261    try:
262        result = await client.register([register_event])
263
264        if result is None:
265            return 1
266
267    finally:
268        await aio.uncancellable(client.async_close())
async def query( addr: hat.drivers.net.stream.TcpAddress | pathlib.Path, client_name: str, client_token: str | None, params: hat.event.common.QueryLatestParams | hat.event.common.QueryTimeseriesParams | hat.event.common.QueryServerParams):
271async def query(addr: net.StreamAddress,
272                client_name: str,
273                client_token: str | None,
274                params: common.QueryParams):
275    client = await eventer.connect(addr=addr,
276                                   client_name=client_name,
277                                   client_token=client_token)
278
279    try:
280        result = await client.query(params)
281
282        result_json = common.query_result_to_json(result)
283        print(json.encode(result_json))
284
285    finally:
286        await aio.uncancellable(client.async_close())
async def subscribe( addr: hat.drivers.net.stream.TcpAddress | pathlib.Path, client_name: str, client_token: str | None, subscriptions: Collection[tuple[str, ...]], server_id: int | None, persisted: bool):
289async def subscribe(addr: net.StreamAddress,
290                    client_name: str,
291                    client_token: str | None,
292                    subscriptions: Collection[common.EventType],
293                    server_id: int | None,
294                    persisted: bool):
295
296    def on_events(client, events):
297        events_json = [common.event_to_json(event) for event in events]
298        print(json.encode(events_json))
299
300    client = await eventer.connect(addr=addr,
301                                   client_name=client_name,
302                                   client_token=client_token,
303                                   subscriptions=subscriptions,
304                                   server_id=server_id,
305                                   persisted=persisted,
306                                   events_cb=on_events)
307
308    try:
309        await client.wait_closing()
310
311    finally:
312        await aio.uncancellable(client.async_close())