"""Infrastructure for typed Zeek events.""" from .brokertypes import ( Boolean, Set, String, Type, Vector, ZeekEvent, from_py, ) from .logs import LOG from .types import ( SerializableZeekType, ) class Event(SerializableZeekType): NAME = None # Name of the event, e.g. "Management::Controller::API::deploy_request" ARG_NAMES = [] # Names of the arguments, e.g. "reqid" ARG_TYPES = [] # Types in Python, e.g. str def __init__(self, *args): """Creates a Zeek event object. This expects the number of arguments contextualized above. The event name is not required since it's defined implicitly via the event class receiving the arguments. Raises: TypeError: when the given arguments, or number of arguments, don't match the expected ARG_TYPES or their number. """ if len(args) != len(self.ARG_NAMES): raise TypeError( f"event argument length mismatch: have {len(args)}, expected {len(self.ARG_NAMES)}", ) self.args = [] for idx, arg in enumerate(args): # If the argument's type matches the required Broker type, we're done. if isinstance(arg, self.ARG_TYPES[idx]): self.args.append(arg) continue try: # When creating an event it can be convenient for the caller to # pass Python-native types. See if we can create brokertypes # types from them, to match the types actually specified when we # created the event classes. maybe_arg = from_py(arg) except TypeError as err: raise TypeError( f"event argument type mismatch: argument " f"{idx+1} is {type(arg)}, {err}", ) from err # Again: if we now have a type match, we're done. if isinstance(maybe_arg, self.ARG_TYPES[idx]): self.args.append(maybe_arg) continue raise TypeError( f"event argument type mismatch: argument " f"{idx+1} is {type(arg)}, should be {self.ARG_TYPES[idx]}", ) def __getattr__(self, name): """Allow attribute-like access to event arguments.""" try: idx = self.ARG_NAMES.index(name) return self.args[idx] except ValueError as err: raise AttributeError( f'event type {self.NAME} has no "{name}" argument', ) from err def __str__(self): # A list of pairs (argument name, typename) zeek_style_args = zip(self.ARG_NAMES, [str(type(arg)) for arg in self.args]) # That list, with each item now a string ":