Skip to content

Commit 5ca5e26

Browse files
Add FlEventChannel (#21316)
Related to #65270
1 parent 6bc70e4 commit 5ca5e26

File tree

7 files changed

+832
-0
lines changed

7 files changed

+832
-0
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_dart_project_private.h
12921292
FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc
12931293
FILE: ../../../flutter/shell/platform/linux/fl_engine.cc
12941294
FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h
1295+
FILE: ../../../flutter/shell/platform/linux/fl_event_channel.cc
1296+
FILE: ../../../flutter/shell/platform/linux/fl_event_channel_test.cc
12951297
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc
12961298
FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec_test.cc
12971299
FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec.cc
@@ -1343,6 +1345,7 @@ FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec
13431345
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h
13441346
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h
13451347
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine.h
1348+
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_event_channel.h
13461349
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h
13471350
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h
13481351
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_message_codec.h

shell/platform/linux/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ _public_headers = [
4747
"public/flutter_linux/fl_binary_messenger.h",
4848
"public/flutter_linux/fl_dart_project.h",
4949
"public/flutter_linux/fl_engine.h",
50+
"public/flutter_linux/fl_event_channel.h",
5051
"public/flutter_linux/fl_json_message_codec.h",
5152
"public/flutter_linux/fl_json_method_codec.h",
5253
"public/flutter_linux/fl_message_codec.h",
@@ -92,6 +93,7 @@ source_set("flutter_linux_sources") {
9293
"fl_binary_messenger.cc",
9394
"fl_dart_project.cc",
9495
"fl_engine.cc",
96+
"fl_event_channel.cc",
9597
"fl_json_message_codec.cc",
9698
"fl_json_method_codec.cc",
9799
"fl_key_event_plugin.cc",
@@ -154,6 +156,7 @@ executable("flutter_linux_unittests") {
154156
"fl_binary_codec_test.cc",
155157
"fl_binary_messenger_test.cc",
156158
"fl_dart_project_test.cc",
159+
"fl_event_channel_test.cc",
157160
"fl_json_message_codec_test.cc",
158161
"fl_json_method_codec_test.cc",
159162
"fl_key_event_plugin_test.cc",
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_event_channel.h"
6+
7+
#include <gmodule.h>
8+
9+
#include "flutter/shell/platform/linux/fl_method_codec_private.h"
10+
11+
static constexpr char kListenMethod[] = "listen";
12+
static constexpr char kCancelMethod[] = "cancel";
13+
static constexpr char kEventRequestError[] = "error";
14+
15+
struct _FlEventChannel {
16+
GObject parent_instance;
17+
18+
// Messenger to communicate on.
19+
FlBinaryMessenger* messenger;
20+
21+
// Channel name.
22+
gchar* name;
23+
24+
// Codec to en/decode messages.
25+
FlMethodCodec* codec;
26+
27+
// Function called when the stream is listened to / cancelled.
28+
FlEventChannelHandler listen_handler;
29+
FlEventChannelHandler cancel_handler;
30+
gpointer handler_data;
31+
GDestroyNotify handler_data_destroy_notify;
32+
};
33+
34+
struct _FlEventChannelResponseHandle {
35+
GObject parent_instance;
36+
37+
FlBinaryMessengerResponseHandle* response_handle;
38+
};
39+
40+
// Added here to stop the compiler from optimising this function away.
41+
G_MODULE_EXPORT GType fl_event_channel_get_type();
42+
43+
G_DEFINE_TYPE(FlEventChannel, fl_event_channel, G_TYPE_OBJECT)
44+
45+
// Handle method calls from the Dart side of the channel.
46+
static FlMethodErrorResponse* handle_method_call(FlEventChannel* self,
47+
const gchar* name,
48+
FlValue* args) {
49+
FlEventChannelHandler handler;
50+
if (g_strcmp0(name, kListenMethod) == 0) {
51+
handler = self->listen_handler;
52+
} else if (g_strcmp0(name, kCancelMethod) == 0) {
53+
handler = self->cancel_handler;
54+
} else {
55+
g_autofree gchar* message =
56+
g_strdup_printf("Unknown event channel request '%s'", name);
57+
return fl_method_error_response_new(kEventRequestError, message, nullptr);
58+
}
59+
60+
// If not handled, just accept requests.
61+
if (handler == nullptr) {
62+
return nullptr;
63+
}
64+
65+
return handler(self, args, self->handler_data);
66+
}
67+
68+
// Called when a binary message is received on this channel.
69+
static void message_cb(FlBinaryMessenger* messenger,
70+
const gchar* channel,
71+
GBytes* message,
72+
FlBinaryMessengerResponseHandle* response_handle,
73+
gpointer user_data) {
74+
FlEventChannel* self = FL_EVENT_CHANNEL(user_data);
75+
76+
g_autofree gchar* name = nullptr;
77+
g_autoptr(GError) error = nullptr;
78+
g_autoptr(FlValue) args = nullptr;
79+
if (!fl_method_codec_decode_method_call(self->codec, message, &name, &args,
80+
&error)) {
81+
g_warning("Failed to decode message on event channel %s: %s", self->name,
82+
error->message);
83+
fl_binary_messenger_send_response(messenger, response_handle, nullptr,
84+
nullptr);
85+
return;
86+
}
87+
88+
g_autoptr(FlMethodErrorResponse) response =
89+
handle_method_call(self, name, args);
90+
91+
g_autoptr(GBytes) data = nullptr;
92+
if (response == nullptr) {
93+
g_autoptr(GError) codec_error = nullptr;
94+
data = fl_method_codec_encode_success_envelope(self->codec, nullptr,
95+
&codec_error);
96+
if (data == nullptr) {
97+
g_warning("Failed to encode event channel %s success response: %s",
98+
self->name, codec_error->message);
99+
}
100+
} else {
101+
g_autoptr(GError) codec_error = nullptr;
102+
data = fl_method_codec_encode_error_envelope(
103+
self->codec, fl_method_error_response_get_code(response),
104+
fl_method_error_response_get_message(response),
105+
fl_method_error_response_get_details(response), &codec_error);
106+
if (data == nullptr) {
107+
g_warning("Failed to encode event channel %s error response: %s",
108+
self->name, codec_error->message);
109+
}
110+
}
111+
112+
if (!fl_binary_messenger_send_response(messenger, response_handle, data,
113+
&error)) {
114+
g_warning("Failed to send event channel response: %s", error->message);
115+
}
116+
}
117+
118+
// Removes handlers and their associated data.
119+
static void remove_handlers(FlEventChannel* self) {
120+
if (self->handler_data_destroy_notify != nullptr) {
121+
self->handler_data_destroy_notify(self->handler_data);
122+
}
123+
self->listen_handler = nullptr;
124+
self->cancel_handler = nullptr;
125+
self->handler_data = nullptr;
126+
self->handler_data_destroy_notify = nullptr;
127+
}
128+
129+
// Called when the channel handler is closed.
130+
static void channel_closed_cb(gpointer user_data) {
131+
g_autoptr(FlEventChannel) self = FL_EVENT_CHANNEL(user_data);
132+
remove_handlers(self);
133+
}
134+
135+
static void fl_event_channel_dispose(GObject* object) {
136+
FlEventChannel* self = FL_EVENT_CHANNEL(object);
137+
138+
if (self->messenger != nullptr) {
139+
fl_binary_messenger_set_message_handler_on_channel(
140+
self->messenger, self->name, nullptr, nullptr, nullptr);
141+
}
142+
143+
g_clear_object(&self->messenger);
144+
g_clear_pointer(&self->name, g_free);
145+
g_clear_object(&self->codec);
146+
147+
remove_handlers(self);
148+
149+
G_OBJECT_CLASS(fl_event_channel_parent_class)->dispose(object);
150+
}
151+
152+
static void fl_event_channel_class_init(FlEventChannelClass* klass) {
153+
G_OBJECT_CLASS(klass)->dispose = fl_event_channel_dispose;
154+
}
155+
156+
static void fl_event_channel_init(FlEventChannel* self) {}
157+
158+
G_MODULE_EXPORT FlEventChannel* fl_event_channel_new(
159+
FlBinaryMessenger* messenger,
160+
const gchar* name,
161+
FlMethodCodec* codec) {
162+
g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
163+
g_return_val_if_fail(name != nullptr, nullptr);
164+
g_return_val_if_fail(FL_IS_METHOD_CODEC(codec), nullptr);
165+
166+
FlEventChannel* self =
167+
FL_EVENT_CHANNEL(g_object_new(fl_event_channel_get_type(), nullptr));
168+
169+
self->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger));
170+
self->name = g_strdup(name);
171+
self->codec = FL_METHOD_CODEC(g_object_ref(codec));
172+
173+
fl_binary_messenger_set_message_handler_on_channel(
174+
self->messenger, self->name, message_cb, g_object_ref(self),
175+
channel_closed_cb);
176+
177+
return self;
178+
}
179+
180+
G_MODULE_EXPORT void fl_event_channel_set_stream_handlers(
181+
FlEventChannel* self,
182+
FlEventChannelHandler listen_handler,
183+
FlEventChannelHandler cancel_handler,
184+
gpointer user_data,
185+
GDestroyNotify destroy_notify) {
186+
g_return_if_fail(FL_IS_EVENT_CHANNEL(self));
187+
188+
remove_handlers(self);
189+
self->listen_handler = listen_handler;
190+
self->cancel_handler = cancel_handler;
191+
self->handler_data = user_data;
192+
self->handler_data_destroy_notify = destroy_notify;
193+
}
194+
195+
G_MODULE_EXPORT gboolean fl_event_channel_send(FlEventChannel* self,
196+
FlValue* event,
197+
GCancellable* cancellable,
198+
GError** error) {
199+
g_return_val_if_fail(FL_IS_EVENT_CHANNEL(self), FALSE);
200+
g_return_val_if_fail(event != nullptr, FALSE);
201+
202+
g_autoptr(GBytes) data =
203+
fl_method_codec_encode_success_envelope(self->codec, event, error);
204+
if (data == nullptr) {
205+
return FALSE;
206+
}
207+
208+
fl_binary_messenger_send_on_channel(self->messenger, self->name, data,
209+
cancellable, nullptr, nullptr);
210+
211+
return TRUE;
212+
}
213+
214+
G_MODULE_EXPORT gboolean fl_event_channel_send_error(FlEventChannel* self,
215+
const gchar* code,
216+
const gchar* message,
217+
FlValue* details,
218+
GCancellable* cancellable,
219+
GError** error) {
220+
g_return_val_if_fail(FL_IS_EVENT_CHANNEL(self), FALSE);
221+
g_return_val_if_fail(code != nullptr, FALSE);
222+
g_return_val_if_fail(message != nullptr, FALSE);
223+
224+
g_autoptr(GBytes) data = fl_method_codec_encode_error_envelope(
225+
self->codec, code, message, details, error);
226+
if (data == nullptr) {
227+
return FALSE;
228+
}
229+
230+
fl_binary_messenger_send_on_channel(self->messenger, self->name, data,
231+
cancellable, nullptr, nullptr);
232+
233+
return TRUE;
234+
}
235+
236+
G_MODULE_EXPORT gboolean
237+
fl_event_channel_send_end_of_stream(FlEventChannel* self,
238+
GCancellable* cancellable,
239+
GError** error) {
240+
g_return_val_if_fail(FL_IS_EVENT_CHANNEL(self), FALSE);
241+
fl_binary_messenger_send_on_channel(self->messenger, self->name, nullptr,
242+
cancellable, nullptr, nullptr);
243+
return TRUE;
244+
}

0 commit comments

Comments
 (0)