blob: a0544c7d46f12ecc5a4013c44cf4d1fd1f6a1044 [file] [log] [blame]
#
# Copyright (c) 2020 Project CHIP Authors
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import asyncio
import builtins
import ctypes
from ..clusters.ClusterObjects import ClusterCommand
from ..clusters.Command import (AsyncCommandTransaction, CommandPath, _OnCommandSenderDoneCallback, _OnCommandSenderErrorCallback,
_OnCommandSenderResponseCallback)
from ..native import PyChipError
from .library_handle import get_webrtc_provider_handle
class WebRTCProviderCommand:
"""Sends WebRTC provider commands `ProvideOffer`/`SolicitOffer` using WebRTC Provider Client.
python is simply too slow on its own to upsert the webrtc session struct after receiving
`ProvideOfferResponse`/`SolicitOfferResponse`, by which time webrtc requestor server could
have returned `NOT_FOUND` status for requestor commands. So we need to do response handling
in C++. Hence the need for separate command sender for such commands with custom response
handling. This class handles that.
"""
def __init__(self):
lib = get_webrtc_provider_handle()
self._handle = lib.pychip_webrtc_provider_client_create()
lib.pychip_webrtc_provider_client_init_commandsender_callbacks(
self._handle, _OnCommandSenderResponseCallback, _OnCommandSenderErrorCallback, _OnCommandSenderDoneCallback
)
def __del__(self):
get_webrtc_provider_handle().pychip_webrtc_provider_client_destroy(self._handle)
async def send_webrtc_provider_command(self, endpoint: int, cmd: ClusterCommand, *args, **kwargs):
return await self._SendCommand(
commandPath=CommandPath(EndpointId=endpoint, ClusterId=cmd.cluster_id, CommandId=cmd.command_id), payload=cmd
)
async def _SendCommand(self, commandPath: CommandPath, payload: ClusterCommand, responseType=None) -> PyChipError:
eventLoop = asyncio.get_running_loop()
future = eventLoop.create_future()
if (responseType is not None) and (not issubclass(responseType, ClusterCommand)):
raise ValueError("responseType must be a ClusterCommand or None")
handle = get_webrtc_provider_handle()
transaction = AsyncCommandTransaction(future, eventLoop, responseType)
payloadTLV = payload.ToTLV()
ctypes.pythonapi.Py_IncRef(ctypes.py_object(transaction))
res = await builtins.chipStack.CallAsyncWithResult(
lambda: handle.pychip_webrtc_provider_client_send_command(
self._handle,
ctypes.py_object(transaction),
commandPath.EndpointId,
commandPath.ClusterId,
commandPath.CommandId,
payloadTLV,
len(payloadTLV),
)
)
if not res.is_success:
ctypes.pythonapi.Py_DecRef(ctypes.py_object(transaction))
res.raise_on_error()
return await future
def init(self, node_id: int, fabric_index: int, endpoint: int):
lib = get_webrtc_provider_handle()
lib.pychip_webrtc_provider_client_init(self._handle, node_id, fabric_index, endpoint)