File: events.py

package info (click to toggle)
python-proton-vpn-api-core 0.39.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 892 kB
  • sloc: python: 6,582; makefile: 8
file content (147 lines) | stat: -rw-r--r-- 4,351 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"""
VPN connection events to react to.


Copyright (c) 2023 Proton AG

This file is part of Proton VPN.

Proton VPN is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Proton VPN is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with ProtonVPN.  If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Optional, Any

from .enum import StateMachineEventEnum

if TYPE_CHECKING:
    from proton.vpn.connection.vpnconnection import VPNConnection


@dataclass
class ConnectionDetails:
    """Connection details obtained via local agent."""
    device_ip: Optional[str] = None
    device_country: Optional[str] = None
    server_ipv4: Optional[str] = None
    server_ipv6: Optional[str] = None


# pylint: disable=too-few-public-methods

@dataclass
class EventContext:
    """
    Relevant event context.
    Args:
        connection: the VPN connection object that emitted this event.
        reason: optional backend-dependent data providing more context about the event.
        error: an optional exception to be bubbled up while processing the event.
    """
    connection: "VPNConnection"
    connection_details: Optional[ConnectionDetails] = None
    forwarded_port: Optional[int] = None
    reason: Optional[Any] = None
    error: Optional[Exception] = None


class Event:
    """Base event that all the other events should inherit from."""
    type = None

    def __init__(self, context: EventContext = None):
        if self.type is None:
            raise AttributeError("event attribute not defined")

        self.context = context or EventContext(connection=None)

    def check_for_errors(self):
        """Raises an exception if there is one."""
        if self.context.error:
            raise self.context.error


class Initialized(Event):
    """Event that leads to the initial state."""
    type = StateMachineEventEnum.INITIALIZED


class Up(Event):
    """Signals that the VPN connection should be started."""
    type = StateMachineEventEnum.UP


class Down(Event):
    """Signals that the VPN connection should be stopped."""
    type = StateMachineEventEnum.DOWN


class Connected(Event):
    """Signals that the VPN connection was successfully established."""
    type = StateMachineEventEnum.CONNECTED


class Disconnected(Event):
    """Signals that the VPN connection was successfully disconnected by the user."""
    type = StateMachineEventEnum.DISCONNECTED


class Error(Event):
    """Parent class for events signaling VPN disconnection."""


class DeviceDisconnected(Error):
    """Signals that the VPN connection dropped unintentionally."""
    type = StateMachineEventEnum.DEVICE_DISCONNECTED


class Timeout(Error):
    """Signals that a timeout occurred while trying to establish the VPN
    connection."""
    type = StateMachineEventEnum.TIMEOUT


class AuthDenied(Error):
    """Signals that an authentication denied occurred while trying to establish
    the VPN connection."""
    type = StateMachineEventEnum.AUTH_DENIED


class ExpiredCertificate(Error):
    """Signals that the passed certificate has expired and needs to be refreshed."""
    type = StateMachineEventEnum.CERTIFICATE_EXPIRED


class MaximumSessionsReached(Error):
    """Signals that for the given plan the user has too many devices/sessions connected."""
    type = StateMachineEventEnum.MAXIMUM_SESSIONS_REACHED


class TunnelSetupFailed(Error):
    """Signals that there was an error setting up the VPN tunnel."""
    type = StateMachineEventEnum.TUNNEL_SETUP_FAILED


class UnexpectedError(Error):
    """Signals that an unexpected error occurred."""
    type = StateMachineEventEnum.UNEXPECTED_ERROR


_event_types = [
    event_type for event_type in Event.__subclasses__()
    if event_type is not Error  # As error is an abstract class.
]
_event_types.extend(Error.__subclasses__())
EVENT_TYPES = tuple(_event_types)