Passed
Push — main ( 96f09a...0ede53 )
by
unknown
01:17 queued 12s
created

pyscord.core.gateway   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 42
dl 0
loc 148
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A GatewayDispatch.from_string() 0 15 1
A Dispatcher.close() 0 7 1
A Dispatcher.handler_manager() 0 14 1
A Dispatcher.__init__() 0 4 1
A GatewayDispatch.__init__() 0 15 1
A Dispatcher.run() 0 10 1
A GatewayDispatch.__str__() 0 7 1
A Dispatcher.__main() 0 11 3
1
# -*- coding: utf-8 -*-
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
# MIT License
3
#
4
# Copyright (c) 2021 Pyscord
5
#
6
# Permission is hereby granted, free of charge, to any person obtaining a copy
7
# of this software and associated documentation files (the "Software"), to deal
8
# in the Software without restriction, including without limitation the rights
9
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
# copies of the Software, and to permit persons to whom the Software is
11
# furnished to do so, subject to the following conditions:
12
#
13
# The above copyright notice and this permission notice shall be included in all
14
# copies or substantial portions of the Software.
15
#
16
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
# SOFTWARE.
23
from __future__ import annotations
24
25
from asyncio import get_event_loop
26
from json import dumps, loads
27
from typing import Dict, Union, Any
28
29
from websockets import connect
0 ignored issues
show
Bug introduced by
The name connect does not seem to exist in module websockets.
Loading history...
30
31
from pyscord._config import GatewayConfig
32
33
34
# TODO: Implement logging
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
35
36
37
class GatewayDispatch:
38
    """
39
    Represents a websocket message.
40
    """
41
42
    def __init__(self, op: int, data: Dict[str, Any], seq: int, name: str):
43
        """
44
        Instantiate a new GatewayDispatch object.
45
46
        :param op: The discord opcode which represents what the message
47
                    means.
48
        :param data: The event data that has been sent/received.
49
        :param seq: The sequence number of a message, which can be used
50
                    for resuming sessions and heartbeats.
51
        :param name: The event name for the payload.
52
        """
53
        self.op: int = op
1 ignored issue
show
Coding Style Naming introduced by
Attribute name "op" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
54
        self.data: Dict = data
55
        self.seq: int = seq
56
        self.event_name: str = name
57
58
    def __str__(self) -> str:
59
        """
60
        :return The string representation of the GatewayDispatch object.
61
        This object can be used to send a websocket message to the gateway.
62
        """
63
        return dumps(
64
            dict(op=self.op, d=self.data, s=self.seq, t=self.event_name))
65
66
    @classmethod
67
    def from_string(cls, payload: str) -> GatewayDispatch:
68
        """
69
        Parses a given payload from a string format and returns a
70
        GatewayDispatch.
71
72
        :param payload: The payload to parse.
73
        :return: A proper GatewayDispatch object.
74
        """
75
        payload: Dict[str, Union[int, str, Dict[str, Any]]] = loads(payload)
76
        return cls(
77
            payload.get("op"),
78
            payload.get("d"),
79
            payload.get("s"),
80
            payload.get("t")
81
        )
82
83
84
class Dispatcher:
85
    """
86
    The Dispatcher handles all interactions with the discord websocket
87
    API. This also contains the main event loop, and handles the heartbeat.
88
89
    Running the dispatcher will create a connection with the
90
    Discord WebSocket API on behalf of the provided token. This token
91
    must be a bot token. (Which can be found on
92
    `/developers/applications/<bot_id>/bot`)
93
    """
94
95
    # TODO: Add intents argument
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
96
    # TODO: Add handlers argument
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
97
    def __init__(self, token: str):
98
        # TODO: Write docs for __init__.
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
99
        self.__token = token
100
        self.__keep_alive = True
101
102
    # TODO: Implement socket typehint
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
103
    async def handler_manager(self, socket, payload: GatewayDispatch):
104
        """
105
        This manages all handles for given OP codes.
106
        This method gets invoked for every message that is received from
107
        Discord.
108
109
        :param socket: The current socket, which can be used to interact
110
                with the Discord API.
111
        :param payload: The received payload from Discord.
112
        """
113
        # TODO: Implement heartbeat
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
114
        # TODO: Implement given handlers.
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
115
        # TODO: Implement logging
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
116
        pass
0 ignored issues
show
Unused Code introduced by
Unnecessary pass statement
Loading history...
117
118
    async def __main(self):
119
        """
120
        The main event loop. This handles all interactions with the
121
        websocket API.
122
        """
123
        # TODO: Implement logging
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
124
        async with connect(GatewayConfig.uri()) as socket:
125
            while self.__keep_alive:
126
                await self.handler_manager(
127
                    socket,
128
                    GatewayDispatch.from_string(await socket.recv()))
129
130
    def run(self):
131
        """
132
        Instantiate the dispatcher, this will create a connection to the
133
        Discord websocket API on behalf of the client who's token has
134
        been passed.
135
        """
136
        # TODO: Implement logging
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
137
        loop = get_event_loop()
138
        loop.run_until_complete(self.__main())
139
        loop.close()
140
141
    def close(self):
142
        """
143
        Stop the dispatcher from listening and responding to gateway
144
        events. This should let the client close on itself.
145
        """
146
        # TODO: Implement logging
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
147
        self.__keep_alive = False
148