/* * * Copyright (c) 2023 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. */ #pragma once #include "core/BaseCluster.h" #include "core/Endpoint.h" #include "lib/support/logging/CHIPLogging.h" namespace matter { namespace casting { namespace core { template using CommandSuccessCallbackType = std::function; using CommandFailureCallbackType = std::function; template struct CommandContext; template class Command { public: Command(memory::Weak endpoint) { this->mEndpoint = endpoint; } /** * @brief Invokes this command on the associated Endpoint and corresponding Cluster * * @param request request data corresponding to this command invocation * @param successCb Called on command execution success, with responseData * @param failureCb Called on command execution failure * @param timedInvokeTimeoutMs command timeout */ void Invoke(RequestType request, void * context, CommandSuccessCallbackType successCb, CommandFailureCallbackType failureCb, const chip::Optional & timedInvokeTimeoutMs) { memory::Strong endpoint = this->GetEndpoint().lock(); if (endpoint) { CommandContext * commandContext = new CommandContext(endpoint, request, context, successCb, failureCb, timedInvokeTimeoutMs); endpoint->GetCastingPlayer()->FindOrEstablishSession( commandContext, // FindOrEstablishSession success handler [](void * _context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) { CommandContext * _commandContext = static_cast *>(_context); ChipLogProgress(AppServer, "::Invoke() Found or established session"); // Invoke command MediaClusterBase cluster(exchangeMgr, sessionHandle, _commandContext->mEndpoint->GetId()); CHIP_ERROR err = cluster.template InvokeCommand( _commandContext->mRequest, _commandContext, // Command success handler [](void * __context, const typename RequestType::ResponseType & response) { CommandContext * __commandContext = static_cast *>(__context); ChipLogProgress(AppServer, "::Invoke() response success"); __commandContext->mSuccessCb(__commandContext->mClientContext, response); delete __commandContext; }, // Command failure handler [](void * __context, CHIP_ERROR error) { CommandContext * __commandContext = static_cast *>(__context); ChipLogError(AppServer, "::Invoke() failure response on EndpointId: %d with error: " "%" CHIP_ERROR_FORMAT, __commandContext->mEndpoint->GetId(), error.Format()); __commandContext->mFailureCb(__commandContext->mClientContext, error); delete __commandContext; }, _commandContext->mTimedInvokeTimeoutMs); // error in invoking the command if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "::Invoke() failure in invoking command on EndpointId: %d with error: " "%" CHIP_ERROR_FORMAT, _commandContext->mEndpoint->GetId(), err.Format()); _commandContext->mFailureCb(_commandContext->mClientContext, err); delete _commandContext; } }, // FindOrEstablishSession failure handler [](void * _context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) { CommandContext * _commandContext = static_cast *>(_context); ChipLogError(AppServer, "::Invoke() failure in retrieving session info for peerId.nodeId: " "0x" ChipLogFormatX64 ", peer.fabricIndex: %d with error: %" CHIP_ERROR_FORMAT, ChipLogValueX64(peerId.GetNodeId()), peerId.GetFabricIndex(), error.Format()); _commandContext->mFailureCb(_commandContext->mClientContext, error); delete _commandContext; }); } else { ChipLogError(AppServer, "::Invoke() failure in retrieving Endpoint"); failureCb(context, CHIP_ERROR_INCORRECT_STATE); } } protected: memory::Weak GetEndpoint() const { return mEndpoint.lock(); } memory::Weak mEndpoint; }; /** * @brief Context object used by the Command class during the Invoke API's execution */ template struct CommandContext { CommandContext(memory::Strong endpoint, RequestType request, void * context, CommandSuccessCallbackType successCb, CommandFailureCallbackType failureCb, const chip::Optional & timedInvokeTimeoutMs) : mSuccessCb(successCb), mFailureCb(failureCb) { mEndpoint = endpoint; mRequest = request; mClientContext = context; mTimedInvokeTimeoutMs = timedInvokeTimeoutMs; } memory::Strong mEndpoint; RequestType mRequest; void * mClientContext; CommandSuccessCallbackType mSuccessCb; CommandFailureCallbackType mFailureCb; chip::Optional mTimedInvokeTimeoutMs; }; } // namespace core } // namespace casting } // namespace matter