1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 11:34:18 +00:00

Dictnetwork seems to be working

This commit is contained in:
Steffo 2019-05-22 02:20:20 +02:00
parent c0a698e8a3
commit b4b2f74fb2
9 changed files with 77 additions and 51 deletions

View file

@ -1,17 +0,0 @@
from . import audio, \
bots, \
commands, \
database, \
network, \
utils, \
error
version = "5.0a7"
__all__ = ["audio",
"bots",
"commands",
"database",
"network",
"utils",
"error"]

View file

@ -3,7 +3,7 @@ import asyncio
import youtube_dl import youtube_dl
import ffmpeg import ffmpeg
from ..utils import Command, Call, NetworkHandler, asyncify from ..utils import Command, Call, NetworkHandler, asyncify
from ..network import Message, RequestSuccessful from ..network import Request, Data
from ..error import TooManyFoundError, NoneFoundError from ..error import TooManyFoundError, NoneFoundError
from ..audio import RoyalPCMAudio, YtdlInfo from ..audio import RoyalPCMAudio, YtdlInfo
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
@ -13,14 +13,16 @@ if typing.TYPE_CHECKING:
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
class PlayMessage(Message): class PlayMessage(Data):
def __init__(self, url: str, guild_name: typing.Optional[str] = None): def __init__(self, url: str, guild_name: typing.Optional[str] = None):
super().__init__()
self.url: str = url self.url: str = url
self.guild_name: typing.Optional[str] = guild_name self.guild_name: typing.Optional[str] = guild_name
class PlaySuccessful(RequestSuccessful): class PlaySuccessful(Data):
def __init__(self, info_list: typing.List[YtdlInfo]): def __init__(self, info_list: typing.List[YtdlInfo]):
super().__init__()
self.info_list: typing.List[YtdlInfo] = info_list self.info_list: typing.List[YtdlInfo] = info_list

View file

@ -1,6 +1,6 @@
"""Royalnet realated classes.""" """Royalnet realated classes."""
from .data import Data, Request
from .packages import Package from .package import Package
from .royalnetlink import RoyalnetLink, NetworkError, NotConnectedError, NotIdentifiedError, ConnectionClosedError from .royalnetlink import RoyalnetLink, NetworkError, NotConnectedError, NotIdentifiedError, ConnectionClosedError
from .royalnetserver import RoyalnetServer from .royalnetserver import RoyalnetServer
from .royalnetconfig import RoyalnetConfig from .royalnetconfig import RoyalnetConfig
@ -12,4 +12,6 @@ __all__ = ["RoyalnetLink",
"Package", "Package",
"RoyalnetServer", "RoyalnetServer",
"RoyalnetConfig", "RoyalnetConfig",
"ConnectionClosedError"] "ConnectionClosedError",
"Data",
"Request"]

25
royalnet/network/data.py Normal file
View file

@ -0,0 +1,25 @@
class Data:
"""Royalnet data. All fields in this class will be converted to a dict when about to be sent."""
def __init__(self):
pass
def to_dict(self):
return self.__dict__
class Request(Data):
"""A Royalnet request. It contains the name of the requested handler, in addition to the data."""
def __init__(self, handler: str, data: dict):
super().__init__()
self.handler: str = handler
self.data: dict = data
@staticmethod
def from_dict(d: dict):
return Request(**d)
def __eq__(self, other):
if isinstance(other, Request):
return self.handler == other.handler and self.data == other.data
return False

View file

@ -1,7 +0,0 @@
from ..utils import classdictjanitor
class Message:
"""A Royalnet message. All fields of this class will be converted in a dict."""
# idk use classdictjanitor

View file

@ -4,7 +4,8 @@ import typing
class Package: class Package:
"""A Royalnet package, the data type with which a :py:class:`royalnet.network.RoyalnetLink` communicates with a :py:class:`royalnet.network.RoyalnetServer` or another link. """ """A Royalnet package, the data type with which a :py:class:`royalnet.network.RoyalnetLink` communicates with a :py:class:`royalnet.network.RoyalnetServer` or another link.
Contains info about the source and the destination."""
def __init__(self, def __init__(self,
data: dict, data: dict,

View file

@ -6,7 +6,7 @@ import math
import numbers import numbers
import logging as _logging import logging as _logging
import typing import typing
from .packages import Package from .package import Package
default_loop = asyncio.get_event_loop() default_loop = asyncio.get_event_loop()
log = _logging.getLogger(__name__) log = _logging.getLogger(__name__)
@ -24,6 +24,10 @@ class ConnectionClosedError(Exception):
"""The :py:class:`royalnet.network.RoyalnetLink`'s connection was closed unexpectedly. The link can't be used anymore.""" """The :py:class:`royalnet.network.RoyalnetLink`'s connection was closed unexpectedly. The link can't be used anymore."""
class InvalidServerResponseError(Exception):
"""The :py:class:`royalnet.network.RoyalnetServer` sent invalid data to the :py:class:`royalnet.network.RoyalnetLink`."""
class NetworkError(Exception): class NetworkError(Exception):
def __init__(self, error_data: dict, *args): def __init__(self, error_data: dict, *args):
super().__init__(*args) super().__init__(*args)
@ -100,7 +104,8 @@ class RoyalnetLink:
log.info(f"Connection to {self.master_uri} was closed.") log.info(f"Connection to {self.master_uri} was closed.")
# What to do now? Let's just reraise. # What to do now? Let's just reraise.
raise ConnectionClosedError() raise ConnectionClosedError()
assert package.destination == self.nid if self.identify_event.is_set() and package.destination != self.nid:
raise InvalidServerResponseError("Package is not addressed to this RoyalnetLink.")
log.debug(f"Received package: {package}") log.debug(f"Received package: {package}")
return package return package
@ -109,10 +114,13 @@ class RoyalnetLink:
log.info(f"Identifying to {self.master_uri}...") log.info(f"Identifying to {self.master_uri}...")
await self.websocket.send(f"Identify {self.nid}:{self.link_type}:{self.secret}") await self.websocket.send(f"Identify {self.nid}:{self.link_type}:{self.secret}")
response: Package = await self.receive() response: Package = await self.receive()
assert response.source == "<server>" if not response.source == "<server>":
if "error" in response.data: raise InvalidServerResponseError("Received a non-service package before identification.")
raise ConnectionClosedError(f"Identification error: {response.data['error']}") if "type" not in response.data:
assert "success" in response.data raise InvalidServerResponseError("Missing 'type' in response data")
if response.data["type"] == "error":
raise ConnectionClosedError(f"Identification error: {response.data['type']}")
assert response.data["type"] == "success"
self.identify_event.set() self.identify_event.set()
log.info(f"Identified successfully!") log.info(f"Identified successfully!")

View file

@ -5,7 +5,7 @@ import datetime
import uuid import uuid
import asyncio import asyncio
import logging as _logging import logging as _logging
from .packages import Package from .package import Package
default_loop = asyncio.get_event_loop() default_loop = asyncio.get_event_loop()
log = _logging.getLogger(__name__) log = _logging.getLogger(__name__)
@ -52,22 +52,22 @@ class RoyalnetServer:
matching = [client for client in self.identified_clients if client.link_type == link_type] matching = [client for client in self.identified_clients if client.link_type == link_type]
return matching or [] return matching or []
async def listener(self, websocket: websockets.server.WebSocketServerProtocol): async def listener(self, websocket: websockets.server.WebSocketServerProtocol, path):
log.info(f"{websocket.remote_address} connected to the server.") log.info(f"{websocket.remote_address} connected to the server.")
connected_client = ConnectedClient(websocket) connected_client = ConnectedClient(websocket)
# Wait for identification # Wait for identification
identify_msg = await websocket.recv() identify_msg = await websocket.recv()
log.debug(f"{websocket.remote_address} identified itself with: {identify_msg}.") log.debug(f"{websocket.remote_address} identified itself with: {identify_msg}.")
if not isinstance(identify_msg, str): if not isinstance(identify_msg, str):
await websocket.send(connected_client.send_service("error", "Invalid identification message (not a str)")) await connected_client.send_service("error", "Invalid identification message (not a str)")
return return
identification = re.match(r"Identify ([^:\s]+):([^:\s]+):([^:\s]+)", identify_msg) identification = re.match(r"Identify ([^:\s]+):([^:\s]+):([^:\s]+)", identify_msg)
if identification is None: if identification is None:
await websocket.send(connected_client.send_service("error", "Invalid identification message (regex failed)")) await connected_client.send_service("error", "Invalid identification message (regex failed)")
return return
secret = identification.group(3) secret = identification.group(3)
if secret != self.required_secret: if secret != self.required_secret:
await websocket.send(connected_client.send_service("error", "Invalid secret")) await connected_client.send_service("error", "Invalid secret")
return return
# Identification successful # Identification successful
connected_client.nid = identification.group(1) connected_client.nid = identification.group(1)

View file

@ -1,7 +1,15 @@
import pytest import pytest
import uuid import uuid
import asyncio import asyncio
from royalnet.network import Package, RoyalnetLink, RoyalnetServer, ConnectionClosedError import logging
from royalnet.network import Package, RoyalnetLink, RoyalnetServer, ConnectionClosedError, Request
log = logging.root
stream_handler = logging.StreamHandler()
stream_handler.formatter = logging.Formatter("{asctime}\t{name}\t{levelname}\t{message}", style="{")
log.addHandler(stream_handler)
log.setLevel(logging.WARNING)
@pytest.fixture @pytest.fixture
@ -11,8 +19,7 @@ def async_loop():
loop.close() loop.close()
@pytest.mark.skip("Not a test") async def echo_request_handler(message):
def echo_request_handler(message):
return message return message
@ -27,19 +34,24 @@ def test_package_serialization():
assert pkg == Package.from_json_bytes(pkg.to_json_bytes()) assert pkg == Package.from_json_bytes(pkg.to_json_bytes())
def test_request_creation():
request = Request("pytest", {"testing": "is fun", "bugs": "are less fun"})
assert request == Request.from_dict(request.to_dict())
def test_links(async_loop: asyncio.AbstractEventLoop): def test_links(async_loop: asyncio.AbstractEventLoop):
address, port = "127.0.0.1", 1234 address, port = "127.0.0.1", 1235
master = RoyalnetServer(address, port, "test") master = RoyalnetServer(address, port, "test")
async_loop.run_until_complete(master.start()) async_loop.run_until_complete(master.start())
# Test invalid secret # Test invalid secret
wrong_secret_link = RoyalnetLink("ws://127.0.0.1:1234", "invalid", "test", echo_request_handler, loop=async_loop) wrong_secret_link = RoyalnetLink("ws://127.0.0.1:1235", "invalid", "test", echo_request_handler, loop=async_loop)
with pytest.raises(ConnectionClosedError): with pytest.raises(ConnectionClosedError):
async_loop.run_until_complete(wrong_secret_link.run()) async_loop.run_until_complete(wrong_secret_link.run())
# Test regular connection # Test regular connection
link1 = RoyalnetLink("ws://127.0.0.1:1234", "test", "one", echo_request_handler, loop=async_loop) link1 = RoyalnetLink("ws://127.0.0.1:1235", "test", "one", echo_request_handler, loop=async_loop)
link1_run_task = async_loop.create_task(link1.run()) async_loop.create_task(link1.run())
link2 = RoyalnetLink("ws://127.0.0.1:1234", "test", "two", echo_request_handler, loop=async_loop) link2 = RoyalnetLink("ws://127.0.0.1:1235", "test", "two", echo_request_handler, loop=async_loop)
link2_run_task = async_loop.create_task(link2.run()) async_loop.create_task(link2.run())
message = {"ciao": "ciao"} message = {"ciao": "ciao"}
response = async_loop.run_until_complete(link1.request(message, "two")) response = async_loop.run_until_complete(link1.request(message, "two"))
assert message == response assert message == response