Skip to content

Commit

Permalink
Extract password command (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinHjelmare authored Oct 11, 2021
1 parent 7723c6c commit 4e5d33b
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 19 deletions.
32 changes: 15 additions & 17 deletions aiovlc/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
from typing import Literal

from .const import LOGGER
from .exceptions import AuthError, CommandError, ConnectError, ConnectReadError
from .exceptions import CommandError, ConnectError, ConnectReadError
from .model.command import (
Add,
Clear,
Command,
Enqueue,
GetLength,
GetLengthOutput,
Expand All @@ -19,6 +20,7 @@
Info,
InfoOutput,
Next,
Password,
Pause,
Play,
Prev,
Expand Down Expand Up @@ -114,29 +116,25 @@ async def write(self, command: str) -> None:
async def login(self) -> None:
"""Login."""
await self.read("Password: ")
command_string = f"{self.password}\n"
await self.write(command_string)
for _ in range(2):
command_output = (await self.read("\n")).strip("\r\n")
if command_output: # discard empty line once.
break
parsed_output = command_output.lower()
if "wrong password" in parsed_output:
raise AuthError("Failed to login to VLC.")
if "welcome" not in parsed_output:
raise CommandError(f"Unexpected password response: {command_output}")
if "> " in command_output:
password_output = await Password(self.password).send(self)
if "> " in password_output.response:
return
# Read until prompt
await self.read("> ")

async def send_command(self, command_string: str) -> list[str]:
async def send_command(self, command: Command) -> list[str]:
"""Send a command and return the output."""
command_string = command.build_command()

async with self._command_lock:
LOGGER.debug("Sending command: %s", command_string.strip())
if command.log_command:
LOGGER.debug("Sending command: %s", command_string.strip())
await self.write(command_string)
command_output = (await self.read("> ")).split("\r\n")[:-1]
LOGGER.debug("Command output: %s", command_output)
raw_output = await self.read(command.read_terminator)

command_output = raw_output.split("\r\n")[:-1]
LOGGER.debug("Command output: %s", command_output)

if command_output:
if re.match(
r"Unknown command `.*'\. Type `help' for help\.", command_output[0]
Expand Down
50 changes: 48 additions & 2 deletions aiovlc/model/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,35 @@
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Generic, Literal, TypeVar

from ..exceptions import CommandParameterError, CommandParseError
from ..exceptions import (
AuthError,
CommandError,
CommandParameterError,
CommandParseError,
)

if TYPE_CHECKING:
from ..client import Client

T = TypeVar("T")
DEFAULT_COMMAND_READ_TERMINATOR = "> "


@dataclass
class Command(Generic[T]):
"""Represent a VLC command."""

log_command: bool = field(init=False, default=True)
prefix: str = field(init=False)
read_terminator: str = field(init=False, default=DEFAULT_COMMAND_READ_TERMINATOR)

async def send(self, client: Client) -> T:
"""Send the command."""
return await self._send(client)

async def _send(self, client: Client) -> T:
"""Send the command."""
output = await client.send_command(self.build_command())
output = await client.send_command(self)
return self.parse_output(output)

def build_command(self) -> str:
Expand Down Expand Up @@ -169,6 +177,44 @@ def parse_output(self, output: list[str]) -> InfoOutput:
return InfoOutput(data=data)


@dataclass
class PasswordOutput(CommandOutput):
"""Represent the password command output."""

response: str


@dataclass
class Password(Command[PasswordOutput]):
"""Represent the password command."""

log_command = False
prefix = ""
password: str
read_terminator = "\n"

def build_command(self) -> str:
"""Return the full command string."""
return f"{self.prefix}{self.password}\n"

def parse_output(self, output: list[str]) -> PasswordOutput:
"""Parse command output."""
response: str = ""
for line in output:
if not line:
continue
response = line
parsed_output = response.lower()
if "wrong password" in parsed_output:
raise AuthError("Failed to login to VLC.")
if "welcome" not in parsed_output:
raise CommandError(f"Unexpected password response: {response}")

if not response:
raise CommandError("Empty password response")
return PasswordOutput(response)


@dataclass
class Next(Command[None]):
"""Represent the next command."""
Expand Down

0 comments on commit 4e5d33b

Please sign in to comment.