| 4 | |
| 5 | |
| 6 | class BaseOutputModule(BaseModule): |
| 7 | accept_dupes = True |
| 8 | _type = "output" |
| 9 | scope_distance_modifier = None |
| 10 | _stats_exclude = True |
| 11 | _shuffle_incoming_queue = False |
| 12 | |
| 13 | def human_event_str(self, event): |
| 14 | event_type = f"[{event.type}]" |
| 15 | event_tags = "" |
| 16 | if getattr(event, "tags", []): |
| 17 | event_tags = f"\t({', '.join(sorted(getattr(event, 'tags', [])))})" |
| 18 | event_str = f"{event_type:<20}\t{event.data_human}\t{event.module_sequence}{event_tags}" |
| 19 | return event_str |
| 20 | |
| 21 | def _event_precheck(self, event): |
| 22 | reason = "precheck succeeded" |
| 23 | # special signal event types |
| 24 | if event.type in ("FINISHED",): |
| 25 | return True, "its type is FINISHED" |
| 26 | if self.errored: |
| 27 | return False, "module is in error state" |
| 28 | # exclude non-watched types |
| 29 | if not any(t in self.get_watched_events() for t in ("*", event.type)): |
| 30 | return False, "its type is not in watched_events" |
| 31 | if self.target_only: |
| 32 | if "target" not in event.tags: |
| 33 | return False, "it did not meet target_only filter criteria" |
| 34 | |
| 35 | ### begin output-module specific ### |
| 36 | |
| 37 | # force-output certain events to the graph |
| 38 | if self._is_graph_important(event): |
| 39 | return True, "event is critical to the graph" |
| 40 | |
| 41 | # omit certain event types |
| 42 | if event._omit: |
| 43 | if event.type in self.get_watched_events(): |
| 44 | reason = "its type is explicitly in watched_events" |
| 45 | self.debug(f"Allowing omitted event: {event} because {reason}") |
| 46 | else: |
| 47 | return False, "its type is omitted in the config" |
| 48 | |
| 49 | # internal events like those from speculate, ipneighbor |
| 50 | # or events that are over our report distance |
| 51 | if event._internal: |
| 52 | return False, "event is internal and output modules don't accept internal events" |
| 53 | |
| 54 | return True, reason |
| 55 | |
| 56 | async def _event_postcheck(self, event): |
| 57 | acceptable, reason = await super()._event_postcheck(event) |
| 58 | if acceptable and not event._stats_recorded and event.type not in ("FINISHED",): |
| 59 | event._stats_recorded = True |
| 60 | self.scan.stats.event_produced(event) |
| 61 | return acceptable, reason |
| 62 | |
| 63 | def is_incoming_duplicate(self, event, add=False): |
no outgoing calls
searching dependent graphs…