Passed
Push — main ( 34b5d7...c26449 )
by Jochen
06:29
created

syslog2irc.routing.map_ports_to_channel_names()   A

Complexity

Conditions 2

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nop 1
dl 0
loc 5
ccs 5
cts 5
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
"""
2
syslog2irc.routing
3
~~~~~~~~~~~~~~~~~~
4
5
Routing of syslog messages to IRC channels by the port they arrive on.
6
7
:Copyright: 2007-2021 Jochen Kupperschmidt
8
:License: MIT, see LICENSE for details.
9
"""
10
11 1
from __future__ import annotations
12 1
from collections import defaultdict
13 1
from dataclasses import dataclass
14 1
import logging
15 1
from typing import Any, Optional
16
17 1
from .network import format_port, Port
18
19
20 1
logger = logging.getLogger(__name__)
21
22
23 1
@dataclass(frozen=True)
24
class Route:
25
    """A route from a syslog message receiver port to an IRC channel."""
26
27 1
    syslog_port: Port
28 1
    irc_channel_name: str
29
30
31 1
class Router:
32
    """Map syslog port numbers to IRC channel names."""
33
34 1
    def __init__(self, routes: set[Route]) -> None:
35 1
        self.ports_to_channel_names = map_ports_to_channel_names(routes)
36 1
        self.channel_names_to_ports = map_channel_names_to_ports(
37
            self.ports_to_channel_names
38
        )
39 1
        self.enabled_channels: set[str] = set()
40
41 1
    def enable_channel(
42
        self, sender: Any, *, channel_name: Optional[str] = None
43
    ) -> None:
44 1
        ports = self.channel_names_to_ports.get(channel_name, set())
45 1
        if not ports:
46 1
            logger.warning(
47
                'No syslog ports routed to IRC channel %s, '
48
                'will not forward to it.',
49
                channel_name,
50
            )
51 1
            return
52
53 1
        self.enabled_channels.add(channel_name)
54 1
        logger.info(
55
            'Enabled forwarding to IRC channel %s from syslog port(s) %s.',
56
            channel_name,
57
            ', '.join(map(format_port, sorted(ports))),
58
        )
59
60 1
    def is_channel_enabled(self, channel: str) -> bool:
61 1
        return channel in self.enabled_channels
62
63 1
    def get_channel_names_for_port(self, port: Port) -> set[str]:
64
        return self.ports_to_channel_names[port]
65
66
67 1
def map_ports_to_channel_names(routes: set[Route]) -> dict[Port, set[str]]:
68 1
    ports_to_channel_names = defaultdict(set)
69 1
    for route in routes:
70 1
        ports_to_channel_names[route.syslog_port].add(route.irc_channel_name)
71 1
    return dict(ports_to_channel_names)
72
73
74 1
def map_channel_names_to_ports(
75
    ports_to_channel_names: dict[Port, set[str]]
76
) -> dict[str, set[Port]]:
77 1
    channel_names_to_ports = defaultdict(set)
78 1
    for port, channel_names in ports_to_channel_names.items():
79 1
        for channel_name in channel_names:
80 1
            channel_names_to_ports[channel_name].add(port)
81
    return dict(channel_names_to_ports)
82