blob: 301c73a4181955fe52eab0e4333a33e6d28dbbee [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_CHANNEL_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_CHANNEL_H_
#include <iostream>
#include <memory>
#include <string>
#include "binary_messenger.h"
#include "engine_method_result.h"
#include "event_sink.h"
#include "event_stream_handler.h"
namespace flutter {
// A named channel for communicating with the Flutter application using
// asynchronous event streams. Incoming requests for event stream setup are
// decoded from binary on receipt, and C++ responses and events are encoded into
// binary before being transmitted back to Flutter. The MethodCodec used must be
// compatible with the one used by the Flutter application. This can be achieved
// by creating an EventChannel
// ("https://docs.flutter.io/flutter/services/EventChannel-class.html")
// counterpart of this channel on the Dart side.
// The C++ type of stream configuration arguments, events, and error details are
// templated, but only values supported by the specified MethodCodec can be
// used.
template <typename T>
class EventChannel {
public:
// Creates an instance that sends and receives event handler on the channel
// named |name|, encoded with |codec| and dispatched via |messenger|.
EventChannel(BinaryMessenger* messenger,
const std::string& name,
const MethodCodec<T>* codec)
: messenger_(messenger), name_(name), codec_(codec) {}
~EventChannel() = default;
// Prevent copying.
EventChannel(EventChannel const&) = delete;
EventChannel& operator=(EventChannel const&) = delete;
// Registers a stream handler on this channel.
// If no handler has been registered, any incoming stream setup requests will
// be handled silently by providing an empty stream.
void SetStreamHandler(std::unique_ptr<StreamHandler<T>> handler) {
if (!handler) {
messenger_->SetMessageHandler(name_, nullptr);
is_listening_ = false;
return;
}
// std::function requires a copyable lambda, so convert to a shared pointer.
// This is safe since only one copy of the shared_pointer will ever be
// accessed.
std::shared_ptr<StreamHandler<T>> shared_handler(handler.release());
const MethodCodec<T>* codec = codec_;
const std::string channel_name = name_;
const BinaryMessenger* messenger = messenger_;
BinaryMessageHandler binary_handler = [shared_handler, codec, channel_name,
messenger,
this](const uint8_t* message,
const size_t message_size,
BinaryReply reply) {
constexpr char kOnListenMethod[] = "listen";
constexpr char kOnCancelMethod[] = "cancel";
std::unique_ptr<MethodCall<T>> method_call =
codec->DecodeMethodCall(message, message_size);
if (!method_call) {
std::cerr << "Unable to construct method call from message on channel: "
<< channel_name << std::endl;
reply(nullptr, 0);
return;
}
const std::string& method = method_call->method_name();
if (method.compare(kOnListenMethod) == 0) {
if (is_listening_) {
std::unique_ptr<StreamHandlerError<T>> error =
shared_handler->OnCancel(nullptr);
if (error) {
std::cerr << "Failed to cancel existing stream: "
<< (error->error_code) << ", " << (error->error_message)
<< ", " << (error->error_details);
}
}
is_listening_ = true;
std::unique_ptr<std::vector<uint8_t>> result;
auto sink = std::make_unique<EventSinkImplementation>(
messenger, channel_name, codec);
std::unique_ptr<StreamHandlerError<T>> error =
shared_handler->OnListen(method_call->arguments(), std::move(sink));
if (error) {
result = codec->EncodeErrorEnvelope(
error->error_code, error->error_message, error->error_details);
} else {
result = codec->EncodeSuccessEnvelope();
}
reply(result->data(), result->size());
} else if (method.compare(kOnCancelMethod) == 0) {
std::unique_ptr<std::vector<uint8_t>> result;
if (is_listening_) {
std::unique_ptr<StreamHandlerError<T>> error =
shared_handler->OnCancel(method_call->arguments());
if (error) {
result = codec->EncodeErrorEnvelope(
error->error_code, error->error_message, error->error_details);
} else {
result = codec->EncodeSuccessEnvelope();
}
is_listening_ = false;
} else {
result = codec->EncodeErrorEnvelope(
"error", "No active stream to cancel", nullptr);
}
reply(result->data(), result->size());
} else {
reply(nullptr, 0);
}
};
messenger_->SetMessageHandler(name_, std::move(binary_handler));
}
private:
class EventSinkImplementation : public EventSink<T> {
public:
EventSinkImplementation(const BinaryMessenger* messenger,
const std::string& name,
const MethodCodec<T>* codec)
: messenger_(messenger), name_(name), codec_(codec) {}
~EventSinkImplementation() = default;
// Prevent copying.
EventSinkImplementation(EventSinkImplementation const&) = delete;
EventSinkImplementation& operator=(EventSinkImplementation const&) = delete;
private:
const BinaryMessenger* messenger_;
const std::string name_;
const MethodCodec<T>* codec_;
protected:
void SuccessInternal(T* event = nullptr) override {
auto result = codec_->EncodeSuccessEnvelope(event);
messenger_->Send(name_, result->data(), result->size());
}
void ErrorInternal(const std::string& error_code,
const std::string& error_message,
T* error_details) override {
auto result =
codec_->EncodeErrorEnvelope(error_code, error_message, error_details);
messenger_->Send(name_, result->data(), result->size());
}
void EndOfStreamInternal() override { messenger_->Send(name_, nullptr, 0); }
};
BinaryMessenger* messenger_;
const std::string name_;
const MethodCodec<T>* codec_;
bool is_listening_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_CHANNEL_H_