blob: 769a125b0d51cb6ec1d5d0003f340474661dbf05 [file] [log] [blame]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2023 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Custom data types."""
from __future__ import annotations
import enum
import ipaddress
from dataclasses import dataclass
import fuchsia_controller_py as fuchsia_controller
class LEVEL(enum.StrEnum):
"""Logging level that need to specified to log a message onto device"""
INFO = "Info"
WARNING = "Warning"
ERROR = "Error"
class TRANSPORT(enum.StrEnum):
"""Different Host-(Fuchsia)Target interaction transports supported."""
# use SL4F for Host-(Fuchsia)Target interactions.
SL4F = "sl4f"
# use Fuchsia-Controller for Host-(Fuchsia)Target interactions.
FUCHSIA_CONTROLLER = "fuchsia-controller"
# prioritize Fuchsia-Controller over SL4F for Host-(Fuchsia)Target interactions.
FUCHSIA_CONTROLLER_PREFERRED = "fuchsia-controller-preferred"
@dataclass(frozen=True)
class IpPort:
"""Dataclass that holds IP Address and Port
Args:
ip: Ip Address
port: Port Number
"""
ip: ipaddress.IPv4Address | ipaddress.IPv6Address
port: int | None
def __post_init__(self) -> None:
"""Validates ip and port args.
Raises:
ValueError
"""
if self.port is not None and self.port < 1:
raise ValueError(
f"port number: {self.port} was not a positive integer"
)
def __str__(self) -> str:
host: str = f"{self.ip}"
if isinstance(self.ip, ipaddress.IPv6Address):
host = f"[{host}]"
if self.port:
return f"{host}:{self.port}"
else:
return f"{host}"
@staticmethod
def create_using_ip_and_port(ip_port: str) -> IpPort:
"""Factory method to create IpPort object using str that has both ip
and port values.
Args:
ip_port: IP address and port of the fuchsia device. This is of
one the following formats:
{ipv4_address}:{port}
[{ipv6_address}]:{port}
{ipv6_address}:{port}
Returns:
A valid IpPort
Raises:
ValueError
"""
try:
# If we have something of form
# 192.168.1.1:8888 ==> ["192.168.1.1", "8888"]
# If we have something of form
# [::1]:8888 ==> ["[::1]", "8888"]
arr: list[str] = ip_port.rsplit(":", 1)
if len(arr) != 1 and len(arr) != 2:
raise ValueError(
f"Value: {ip_port} was not a valid IpPort (needs "
f"IP Address and optional Port)"
)
addr_part: str = arr[0]
# Remove [] that might be surrounding an IPv6 address
addr_part = addr_part.replace("[", "").replace("]", "")
port = None
if len(arr) == 2:
port_part: str = arr[1]
port = int(port_part)
if port < 1:
raise ValueError(
f"For IpPort: {ip_port}, port number: {port} was "
f"not a positive integer)"
)
return IpPort(ipaddress.ip_address(addr_part), port)
except ValueError as e:
raise e
@staticmethod
def create_using_ip(ip: str) -> IpPort:
"""Factory method to create IpPort object using str that has ip address.
Args:
ip: IP address and port of the fuchsia device. This is of
one the following formats:
{ipv4_address}
[{ipv6_address}]
{ipv6_address}
Returns:
A valid IpPort
Raises:
ValueError
"""
try:
# Remove [] that might be surrounding an IPv6 address
ip = ip.replace("[", "").replace("]", "")
return IpPort(ipaddress.ip_address(ip), None)
except ValueError as e:
raise e
@dataclass(frozen=True)
class TargetSshAddress(IpPort):
"""Dataclass that holds target's ssh address information.
Args:
ip: Target's SSH IP Address
port: Target's SSH port
"""
@dataclass(frozen=True)
class Sl4fServerAddress(IpPort):
"""Dataclass that holds sl4f server address information.
Args:
ip: IP Address of SL4F server
port: Port where SL4F server is listening for SL4F requests
"""
@dataclass(frozen=True)
class FFXConfig:
"""Dataclass that holds FFX config information.
Args:
binary_path: absolute path to the FFX binary.
isolate_dir: Directory that will be passed to `--isolate-dir`
arg of FFX
logs_dir: Directory that will be passed to `--config log.dir`
arg of FFX
logs_level: logs level that will be passed to `--config log.level`
arg of FFX
enable_mdns: Whether or not mdns need to be enabled. This will be
passed to `--config discovery.mdns.enabled` arg of FFX
subtools_search_path: A path of where ffx should
look for plugins.
"""
binary_path: str
isolate_dir: fuchsia_controller.IsolateDir
logs_dir: str
logs_level: str
mdns_enabled: bool
subtools_search_path: str | None
def __str__(self) -> str:
return (
f"binary_path={self.binary_path}, "
f"isolate_dir={self.isolate_dir.directory()}, "
f"logs_dir={self.logs_dir}, "
f"logs_level={self.logs_level}, "
f"mdns_enabled={self.mdns_enabled}, "
f"subtools_search_path={self.subtools_search_path}, "
)
@dataclass(frozen=True)
class FidlEndpoint:
"""Dataclass that holds FIDL end point information.
Args:
moniker: moniker pointing to the FIDL end point
protocol: protocol name of the FIDL end point
"""
moniker: str
protocol: str