Passed
Push — main ( aae69a...152cdf )
by Jochen
02:03
created

syslog2irc.routing   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 81
Duplicated Lines 0 %

Test Coverage

Coverage 86.11%

Importance

Changes 0
Metric Value
eloc 47
dl 0
loc 81
ccs 31
cts 36
cp 0.8611
rs 10
c 0
b 0
f 0
wmc 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A Router.__init__() 0 6 1
A Router.enable_channel() 0 17 2
A Router.get_channel_names_for_port() 0 2 1
A Router.is_channel_enabled() 0 2 1

2 Functions

Rating   Name   Duplication   Size   Complexity  
A map_channel_names_to_ports() 0 8 3
A map_ports_to_channel_names() 0 5 2
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 collections import defaultdict
12 1
from dataclasses import dataclass
13 1
import logging
14 1
from typing import Any, Dict, Optional, Set
15
16 1
from .network import format_port, Port
17
18
19 1
logger = logging.getLogger(__name__)
20
21
22 1
@dataclass(frozen=True)
23
class Route:
24
    """A route from a syslog message receiver port to an IRC channel."""
25
26 1
    syslog_port: Port
27 1
    irc_channel_name: str
28
29
30 1
class Router:
31
    """Map syslog port numbers to IRC channel names."""
32
33 1
    def __init__(self, ports_to_channel_names: Dict[Port, Set[str]]) -> None:
34 1
        self.ports_to_channel_names = ports_to_channel_names
35 1
        self.channel_names_to_ports = map_channel_names_to_ports(
36
            ports_to_channel_names
37
        )
38 1
        self.enabled_channels: Set[str] = set()
39
40 1
    def enable_channel(
41
        self, sender: Any, *, channel_name: Optional[str] = None
42
    ) -> None:
43 1
        ports = self.channel_names_to_ports.get(channel_name, set())
44 1
        if not ports:
45 1
            logger.warning(
46
                'No syslog ports routed to IRC channel %s, '
47
                'will not forward to it.',
48
                channel_name,
49
            )
50 1
            return
51
52 1
        self.enabled_channels.add(channel_name)
53 1
        logger.info(
54
            'Enabled forwarding to IRC channel %s from syslog port(s) %s.',
55
            channel_name,
56
            ', '.join(map(format_port, sorted(ports))),
57
        )
58
59 1
    def is_channel_enabled(self, channel: str) -> bool:
60 1
        return channel in self.enabled_channels
61
62 1
    def get_channel_names_for_port(self, port: Port) -> Set[str]:
63
        return self.ports_to_channel_names[port]
64
65
66 1
def map_ports_to_channel_names(routes: Set[Route]) -> Dict[Port, Set[str]]:
67
    ports_to_channel_names = defaultdict(set)
68
    for route in routes:
69
        ports_to_channel_names[route.syslog_port].add(route.irc_channel_name)
70
    return dict(ports_to_channel_names)
71
72
73 1
def map_channel_names_to_ports(
74
    ports_to_channel_names: Dict[Port, Set[str]]
75
) -> Dict[str, Set[Port]]:
76 1
    channel_names_to_ports = defaultdict(set)
77 1
    for port, channel_names in ports_to_channel_names.items():
78 1
        for channel_name in channel_names:
79 1
            channel_names_to_ports[channel_name].add(port)
80
    return dict(channel_names_to_ports)
81