# Generated by the protocol buffer compiler.  DO NOT EDIT!
# sources: blickfeld/system/services/firmware.proto, blickfeld/system/services/network.proto, blickfeld/system/services/scan_pattern.proto
# plugin: python-betterproto
import asyncio
from dataclasses import dataclass
from typing import (
    TYPE_CHECKING,
    AsyncIterable,
    AsyncIterator,
    Dict,
    Iterable,
    Iterator,
    Optional,
    Union,
)

import blickfeld_qb2.betterproto as betterproto
import blickfeld_qb2.betterproto.lib.google.protobuf as betterproto_lib_google_protobuf
import grpclib
from blickfeld_qb2.betterproto.grpc.grpclib_server import ServiceBase

from .. import (
    config as _config__,
    data as _data__,
)


if TYPE_CHECKING:
    import grpclib.server
    from blickfeld_qb2.betterproto.grpc.grpclib_client import MetadataLike
    from grpclib.metadata import Deadline


@dataclass(eq=False, repr=False)
class FirmwareUploadRequest(betterproto.Message):
    """
    This request is sent multiple times to upload a full complete bundle. End
    the stream with the last chunk of the bundle.
    """

    binary_chunk: bytes = betterproto.bytes_field(1)
    """
    Binary chunk of firmware bundle. The chunk size should not exceed 1 MB. For
    a firmware bundle with a size of 500 MB, at least 500 chunks / messages are
    required.
    """


@dataclass(eq=False, repr=False)
class FirmwareUploadResponse(betterproto.Message):
    """
    The uploaded firmware bundle is validated after the upload and its firmware
    info is returned.
    """

    info: "_data__.FirmwareInfo" = betterproto.message_field(1)
    """Firmware info with version and release information"""


@dataclass(eq=False, repr=False)
class FirmwareInstallRequest(betterproto.Message):
    """
    This request contains some optional configuration parameters for the
    install step.
    """

    pass


@dataclass(eq=False, repr=False)
class FirmwareInstallResponse(betterproto.Message):
    """Continous status message which reports the installation progress."""

    status: "_data__.FirmwareStatus" = betterproto.message_field(1)
    """Progress is defined in Status.Installation.Progress."""


@dataclass(eq=False, repr=False)
class FirmwareUploadAndInstallRequest(betterproto.Message):
    """
    Please refer to <<_blickfeld_system_services_FirmwareUploadRequest,
    FirmwareUploadRequest>>.
    """

    binary_chunk: bytes = betterproto.bytes_field(1)
    """
    Please refer to <<_blickfeld_system_services_FirmwareUploadRequest,
    FirmwareUploadRequest>>.
    """


@dataclass(eq=False, repr=False)
class FirmwareUploadAndInstallResponse(betterproto.Message):
    """
    Please refer to <<_blickfeld_system_services_FirmwareInstallResponse,
    FirmwareInstallResponse>>.
    """

    status: "_data__.FirmwareStatus" = betterproto.message_field(1)
    """
    Please refer to <<_blickfeld_system_services_FirmwareInstallResponse,
    FirmwareInstallResponse>>.
    """


@dataclass(eq=False, repr=False)
class FirmwareGetStatusResponse(betterproto.Message):
    """Response with snapshot of current status."""

    status: "_data__.FirmwareStatus" = betterproto.message_field(1)
    """Current firmware status"""


@dataclass(eq=False, repr=False)
class FirmwareWatchStatusResponse(betterproto.Message):
    """Continuous response with status"""

    status: "_data__.FirmwareStatus" = betterproto.message_field(1)
    """Current firmware status"""


@dataclass(eq=False, repr=False)
class NetworkValidateRequest(betterproto.Message):
    """Request to validate method"""

    config: "_config__.Network" = betterproto.message_field(1)
    """Configuration which should be validated"""


@dataclass(eq=False, repr=False)
class NetworkValidateResponse(betterproto.Message):
    """Response to validate method"""

    status: "_data__.NetworkStatus" = betterproto.message_field(1)
    """Status message with allocated IP addresses"""


@dataclass(eq=False, repr=False)
class NetworkGetMacAddressesResponse(betterproto.Message):
    """Response with mac addresses"""

    ethernet: str = betterproto.string_field(1)
    """Mac address of ethernet / LAN interface"""

    wireless: str = betterproto.string_field(2)
    """Mac address of wireless / WiFi interface"""


@dataclass(eq=False, repr=False)
class ScanPatternGetResponse(betterproto.Message):
    name: str = betterproto.string_field(1)
    scan_pattern: "_config__.ScanPattern" = betterproto.message_field(2)


@dataclass(eq=False, repr=False)
class ScanPatternSetRequest(betterproto.Message):
    name: str = betterproto.string_field(1, group="type_oneof")
    scan_pattern: "_config__.ScanPattern" = betterproto.message_field(
        2, group="type_oneof"
    )


@dataclass(eq=False, repr=False)
class ScanPatternListResponse(betterproto.Message):
    named_scan_patterns: Dict[str, "_config__.ScanPattern"] = betterproto.map_field(
        1, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE
    )


@dataclass(eq=False, repr=False)
class ScanPatternStoreRequest(betterproto.Message):
    name: str = betterproto.string_field(1)
    scan_pattern: "_config__.ScanPattern" = betterproto.message_field(2)


@dataclass(eq=False, repr=False)
class ScanPatternDeleteRequest(betterproto.Message):
    name: str = betterproto.string_field(1)


class Firmware(betterproto.ServiceStub):
    """
    The firmware service offers methods to fetch the currently installed
    firmware, upgrade it, downgrade it and also configure auto-update
    mechanisms.
    """

    async def async_upload(
        self,
        request_iterator: Union[
            AsyncIterable["FirmwareUploadRequest"], Iterable["FirmwareUploadRequest"]
        ],
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "FirmwareUploadResponse":
        """
        Upload the firmware bundle from the client to the device. Fails if the
        uploaded firmware bundle is not valid.
        """

        return await self._stream_unary(
            "/blickfeld.system.services.Firmware/Upload",
            request_iterator,
            FirmwareUploadRequest,
            FirmwareUploadResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def upload(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "FirmwareUploadResponse":
        """
        Upload the firmware bundle from the client to the device. Fails if the
        uploaded firmware bundle is not valid.
        """

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_upload(
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_install(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> AsyncIterator["FirmwareInstallResponse"]:
        """
        Trigger the installation process of an uploaded firmware. A status
        stream with the installation progress is returned and ends with
        installation completion.
        """

        request = FirmwareInstallRequest()

        async for response in self._unary_stream(
            "/blickfeld.system.services.Firmware/Install",
            request,
            FirmwareInstallResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        ):
            yield response

    def install(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> Iterator["FirmwareInstallResponse"]:
        """
        Trigger the installation process of an uploaded firmware. A status
        stream with the installation progress is returned and ends with
        installation completion.
        """

        loop = asyncio.get_event_loop()
        ait = self.async_install(
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        ).__aiter__()

        async def get_next():
            try:
                obj = await ait.__anext__()
                return False, obj
            except StopAsyncIteration:
                return True, None

        while True:
            done, obj = loop.run_until_complete(get_next())
            if done:
                break
            yield obj

    async def async_upload_and_install(
        self,
        request_iterator: Union[
            AsyncIterable["FirmwareUploadAndInstallRequest"],
            Iterable["FirmwareUploadAndInstallRequest"],
        ],
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> AsyncIterator["FirmwareUploadAndInstallResponse"]:
        """Combines the Upload and Install steps in a single method."""

        async for response in self._stream_stream(
            "/blickfeld.system.services.Firmware/UploadAndInstall",
            request_iterator,
            FirmwareUploadAndInstallRequest,
            FirmwareUploadAndInstallResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        ):
            yield response

    def upload_and_install(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> Iterator["FirmwareUploadAndInstallResponse"]:
        """Combines the Upload and Install steps in a single method."""

        loop = asyncio.get_event_loop()
        ait = self.async_upload_and_install(
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        ).__aiter__()

        async def get_next():
            try:
                obj = await ait.__anext__()
                return False, obj
            except StopAsyncIteration:
                return True, None

        while True:
            done, obj = loop.run_until_complete(get_next())
            if done:
                break
            yield obj

    async def async_get_status(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "FirmwareGetStatusResponse":
        """
        Get the current firmware status which includes the currently installed
        firmware but also ongoing or failed installations.
        """

        request = betterproto_lib_google_protobuf.Empty()

        return await self._unary_unary(
            "/blickfeld.system.services.Firmware/GetStatus",
            request,
            FirmwareGetStatusResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def get_status(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "FirmwareGetStatusResponse":
        """
        Get the current firmware status which includes the currently installed
        firmware but also ongoing or failed installations.
        """

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_get_status(
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_watch_status(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> AsyncIterator["FirmwareWatchStatusResponse"]:
        """
        Continously watch the status stream and get updates on changes. This
        can be used to attach to an ongoing installation.
        """

        request = betterproto_lib_google_protobuf.Empty()

        async for response in self._unary_stream(
            "/blickfeld.system.services.Firmware/WatchStatus",
            request,
            FirmwareWatchStatusResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        ):
            yield response

    def watch_status(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> Iterator["FirmwareWatchStatusResponse"]:
        """
        Continously watch the status stream and get updates on changes. This
        can be used to attach to an ongoing installation.
        """

        loop = asyncio.get_event_loop()
        ait = self.async_watch_status(
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        ).__aiter__()

        async def get_next():
            try:
                obj = await ait.__anext__()
                return False, obj
            except StopAsyncIteration:
                return True, None

        while True:
            done, obj = loop.run_until_complete(get_next())
            if done:
                break
            yield obj


class Network(betterproto.ServiceStub):
    """
    The network service allows to setup network configuration of Qb2 device.
    The exact structure of configuration settings is defined by "Network"
    protocol message. Service provides "SetConfig()" and "GetConfig()" API
    which allow to apply and read out configuration settings at run-time. The
    "GetStatus()" API brings configuration and statistical information about
    currently active network connection.
    """

    async def async_get_status(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "_data__.NetworkStatus":
        """Brings information about currently active connection"""

        request = betterproto_lib_google_protobuf.Empty()

        return await self._unary_unary(
            "/blickfeld.system.services.Network/GetStatus",
            request,
            _data__.NetworkStatus,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def get_status(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "_data__.NetworkStatus":
        """Brings information about currently active connection"""

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_get_status(
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_set_config(
        self,
        *,
        hostname: str = "",
        dhcp: bool = False,
        manual: "NetworkStatic" = None,
        link_local: bool = False,
        wireless: "NetworkWireless" = None,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "betterproto_lib_google_protobuf.Empty":
        """Applies specified network configuration"""

        request = _config__.Network()
        request.hostname = hostname
        request.dhcp = dhcp
        if manual is not None:
            request.manual = manual
        request.link_local = link_local
        if wireless is not None:
            request.wireless = wireless

        return await self._unary_unary(
            "/blickfeld.system.services.Network/SetConfig",
            request,
            betterproto_lib_google_protobuf.Empty,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def set_config(
        self,
        *,
        hostname: str = "",
        dhcp: bool = False,
        manual: "NetworkStatic" = None,
        link_local: bool = False,
        wireless: "NetworkWireless" = None,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "betterproto_lib_google_protobuf.Empty":
        """Applies specified network configuration"""

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_set_config(
                hostname=hostname,
                dhcp=dhcp,
                manual=manual,
                link_local=link_local,
                wireless=wireless,
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_get_config(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "_config__.Network":
        """Reads out provided network configuration"""

        request = betterproto_lib_google_protobuf.Empty()

        return await self._unary_unary(
            "/blickfeld.system.services.Network/GetConfig",
            request,
            _config__.Network,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def get_config(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "_config__.Network":
        """Reads out provided network configuration"""

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_get_config(
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_validate(
        self,
        *,
        config: "_config__.Network" = None,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "NetworkValidateResponse":
        """
        Validates the network configuration by applying it shortly. If DHCP is
        configured, it checks if it can acquire an IPv4 address. For static IP
        address, the validation only works for wireless networks. It then,
        still cannot allocate a manual IP address if the credentials are wrong.
        [NOTE] The validation does not yet separate error messages for
        misconfigured wireless credentials or wrongly configured DHCP server.
        Thus, the issue is not necessarily on the device side.
        """

        request = NetworkValidateRequest()
        if config is not None:
            request.config = config

        return await self._unary_unary(
            "/blickfeld.system.services.Network/Validate",
            request,
            NetworkValidateResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def validate(
        self,
        *,
        config: "_config__.Network" = None,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "NetworkValidateResponse":
        """
        Validates the network configuration by applying it shortly. If DHCP is
        configured, it checks if it can acquire an IPv4 address. For static IP
        address, the validation only works for wireless networks. It then,
        still cannot allocate a manual IP address if the credentials are wrong.
        [NOTE] The validation does not yet separate error messages for
        misconfigured wireless credentials or wrongly configured DHCP server.
        Thus, the issue is not necessarily on the device side.
        """

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_validate(
                config=config,
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_get_mac_addresses(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "NetworkGetMacAddressesResponse":
        """Get MAC addresses of the available interfaces"""

        request = betterproto_lib_google_protobuf.Empty()

        return await self._unary_unary(
            "/blickfeld.system.services.Network/GetMacAddresses",
            request,
            NetworkGetMacAddressesResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def get_mac_addresses(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "NetworkGetMacAddressesResponse":
        """Get MAC addresses of the available interfaces"""

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_get_mac_addresses(
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )


class ScanPattern(betterproto.ServiceStub):
    async def async_get(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "ScanPatternGetResponse":
        """Gets scan pattern configuration settings"""

        request = betterproto_lib_google_protobuf.Empty()

        return await self._unary_unary(
            "/blickfeld.system.services.ScanPattern/Get",
            request,
            ScanPatternGetResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def get(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "ScanPatternGetResponse":
        """Gets scan pattern configuration settings"""

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_get(
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_set(
        self,
        *,
        name: str = "",
        scan_pattern: "_config__.ScanPattern" = None,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "betterproto_lib_google_protobuf.Empty":
        """Sets scan pattern cofiguration settings"""

        request = ScanPatternSetRequest()
        request.name = name
        if scan_pattern is not None:
            request.scan_pattern = scan_pattern

        return await self._unary_unary(
            "/blickfeld.system.services.ScanPattern/Set",
            request,
            betterproto_lib_google_protobuf.Empty,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def set(
        self,
        *,
        name: str = "",
        scan_pattern: "_config__.ScanPattern" = None,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "betterproto_lib_google_protobuf.Empty":
        """Sets scan pattern cofiguration settings"""

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_set(
                name=name,
                scan_pattern=scan_pattern,
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_list(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "ScanPatternListResponse":
        """Return list of named scan patterns"""

        request = betterproto_lib_google_protobuf.Empty()

        return await self._unary_unary(
            "/blickfeld.system.services.ScanPattern/List",
            request,
            ScanPatternListResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def list(
        self,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None,
    ) -> "ScanPatternListResponse":
        """Return list of named scan patterns"""

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_list(
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_store(
        self,
        *,
        name: str = "",
        scan_pattern: "_config__.ScanPattern" = None,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "betterproto_lib_google_protobuf.Empty":
        """Store scan pattern"""

        request = ScanPatternStoreRequest()
        request.name = name
        if scan_pattern is not None:
            request.scan_pattern = scan_pattern

        return await self._unary_unary(
            "/blickfeld.system.services.ScanPattern/Store",
            request,
            betterproto_lib_google_protobuf.Empty,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def store(
        self,
        *,
        name: str = "",
        scan_pattern: "_config__.ScanPattern" = None,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "betterproto_lib_google_protobuf.Empty":
        """Store scan pattern"""

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_store(
                name=name,
                scan_pattern=scan_pattern,
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )

    async def async_delete(
        self,
        *,
        name: str = "",
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "betterproto_lib_google_protobuf.Empty":
        """Delete stored scan pattern"""

        request = ScanPatternDeleteRequest()
        request.name = name

        return await self._unary_unary(
            "/blickfeld.system.services.ScanPattern/Delete",
            request,
            betterproto_lib_google_protobuf.Empty,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )

    def delete(
        self,
        *,
        name: str = "",
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "betterproto_lib_google_protobuf.Empty":
        """Delete stored scan pattern"""

        loop = asyncio.get_event_loop()
        return loop.run_until_complete(
            self.async_delete(
                name=name,
                timeout=timeout,
                deadline=deadline,
                metadata=metadata,
            )
        )
