mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
206 lines
7.8 KiB
C++
206 lines
7.8 KiB
C++
// 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.
|
|
|
|
#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h"
|
|
|
|
#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h"
|
|
|
|
#include <gmodule.h>
|
|
|
|
static constexpr char kMethodKey[] = "method";
|
|
static constexpr char kArgsKey[] = "args";
|
|
|
|
struct _FlJsonMethodCodec {
|
|
FlMethodCodec parent_instance;
|
|
|
|
FlJsonMessageCodec* codec;
|
|
};
|
|
|
|
G_DEFINE_TYPE(FlJsonMethodCodec,
|
|
fl_json_method_codec,
|
|
fl_method_codec_get_type())
|
|
|
|
static void fl_json_method_codec_dispose(GObject* object) {
|
|
FlJsonMethodCodec* self = FL_JSON_METHOD_CODEC(object);
|
|
|
|
g_clear_object(&self->codec);
|
|
|
|
G_OBJECT_CLASS(fl_json_method_codec_parent_class)->dispose(object);
|
|
}
|
|
|
|
// Implements FlMethodCodec::encode_method_call.
|
|
static GBytes* fl_json_method_codec_encode_method_call(FlMethodCodec* codec,
|
|
const gchar* name,
|
|
FlValue* args,
|
|
GError** error) {
|
|
FlJsonMethodCodec* self = FL_JSON_METHOD_CODEC(codec);
|
|
|
|
g_autoptr(FlValue) message = fl_value_new_map();
|
|
fl_value_set_take(message, fl_value_new_string(kMethodKey),
|
|
fl_value_new_string(name));
|
|
fl_value_set_take(message, fl_value_new_string(kArgsKey),
|
|
args != nullptr ? fl_value_ref(args) : fl_value_new_null());
|
|
|
|
return fl_message_codec_encode_message(FL_MESSAGE_CODEC(self->codec), message,
|
|
error);
|
|
}
|
|
|
|
// Implements FlMethodCodec::decode_method_call.
|
|
static gboolean fl_json_method_codec_decode_method_call(FlMethodCodec* codec,
|
|
GBytes* message,
|
|
gchar** name,
|
|
FlValue** args,
|
|
GError** error) {
|
|
FlJsonMethodCodec* self = FL_JSON_METHOD_CODEC(codec);
|
|
|
|
g_autoptr(FlValue) value = fl_message_codec_decode_message(
|
|
FL_MESSAGE_CODEC(self->codec), message, error);
|
|
if (value == nullptr)
|
|
return FALSE;
|
|
|
|
if (fl_value_get_type(value) != FL_VALUE_TYPE_MAP) {
|
|
g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
|
|
"Expected JSON map in method resonse, got %d instead",
|
|
fl_value_get_type(value));
|
|
return FALSE;
|
|
}
|
|
|
|
FlValue* method_value = fl_value_lookup_string(value, kMethodKey);
|
|
if (method_value == nullptr) {
|
|
g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
|
|
"Missing JSON method field in method resonse");
|
|
return FALSE;
|
|
}
|
|
if (fl_value_get_type(method_value) != FL_VALUE_TYPE_STRING) {
|
|
g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
|
|
"Expected JSON string for method name, got %d instead",
|
|
fl_value_get_type(method_value));
|
|
return FALSE;
|
|
}
|
|
FlValue* args_value = fl_value_lookup_string(value, kArgsKey);
|
|
|
|
*name = g_strdup(fl_value_get_string(method_value));
|
|
*args = args_value != nullptr ? fl_value_ref(args_value) : nullptr;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Implements FlMethodCodec::encode_success_envelope.
|
|
static GBytes* fl_json_method_codec_encode_success_envelope(
|
|
FlMethodCodec* codec,
|
|
FlValue* result,
|
|
GError** error) {
|
|
FlJsonMethodCodec* self = FL_JSON_METHOD_CODEC(codec);
|
|
|
|
g_autoptr(FlValue) message = fl_value_new_list();
|
|
fl_value_append_take(
|
|
message, result != nullptr ? fl_value_ref(result) : fl_value_new_null());
|
|
|
|
return fl_message_codec_encode_message(FL_MESSAGE_CODEC(self->codec), message,
|
|
error);
|
|
}
|
|
|
|
// Implements FlMethodCodec::encode_error_envelope.
|
|
static GBytes* fl_json_method_codec_encode_error_envelope(
|
|
FlMethodCodec* codec,
|
|
const gchar* code,
|
|
const gchar* error_message,
|
|
FlValue* details,
|
|
GError** error) {
|
|
FlJsonMethodCodec* self = FL_JSON_METHOD_CODEC(codec);
|
|
|
|
g_autoptr(FlValue) message = fl_value_new_list();
|
|
fl_value_append_take(message, fl_value_new_string(code));
|
|
fl_value_append_take(message, error_message != nullptr
|
|
? fl_value_new_string(error_message)
|
|
: fl_value_new_null());
|
|
fl_value_append_take(message, details != nullptr ? fl_value_ref(details)
|
|
: fl_value_new_null());
|
|
|
|
return fl_message_codec_encode_message(FL_MESSAGE_CODEC(self->codec), message,
|
|
error);
|
|
}
|
|
|
|
// Implements FlMethodCodec::decode_response.
|
|
static FlMethodResponse* fl_json_method_codec_decode_response(
|
|
FlMethodCodec* codec,
|
|
GBytes* message,
|
|
GError** error) {
|
|
FlJsonMethodCodec* self = FL_JSON_METHOD_CODEC(codec);
|
|
|
|
g_autoptr(FlValue) value = fl_message_codec_decode_message(
|
|
FL_MESSAGE_CODEC(self->codec), message, error);
|
|
if (value == nullptr)
|
|
return nullptr;
|
|
|
|
if (fl_value_get_type(value) != FL_VALUE_TYPE_LIST) {
|
|
g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
|
|
"Expected JSON list in method resonse, got %d instead",
|
|
fl_value_get_type(value));
|
|
return nullptr;
|
|
}
|
|
|
|
size_t length = fl_value_get_length(value);
|
|
if (length == 1) {
|
|
return FL_METHOD_RESPONSE(
|
|
fl_method_success_response_new(fl_value_get_list_value(value, 0)));
|
|
} else if (length == 3) {
|
|
FlValue* code_value = fl_value_get_list_value(value, 0);
|
|
if (fl_value_get_type(code_value) != FL_VALUE_TYPE_STRING) {
|
|
g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
|
|
"Error code wrong type");
|
|
return nullptr;
|
|
}
|
|
const gchar* code = fl_value_get_string(code_value);
|
|
|
|
FlValue* message_value = fl_value_get_list_value(value, 1);
|
|
if (fl_value_get_type(message_value) != FL_VALUE_TYPE_STRING &&
|
|
fl_value_get_type(message_value) != FL_VALUE_TYPE_NULL) {
|
|
g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
|
|
"Error message wrong type");
|
|
return nullptr;
|
|
}
|
|
const gchar* message =
|
|
fl_value_get_type(message_value) == FL_VALUE_TYPE_STRING
|
|
? fl_value_get_string(message_value)
|
|
: nullptr;
|
|
|
|
FlValue* args = fl_value_get_list_value(value, 2);
|
|
if (fl_value_get_type(args) == FL_VALUE_TYPE_NULL)
|
|
args = nullptr;
|
|
|
|
return FL_METHOD_RESPONSE(
|
|
fl_method_error_response_new(code, message, args));
|
|
} else {
|
|
g_set_error(error, FL_MESSAGE_CODEC_ERROR, FL_MESSAGE_CODEC_ERROR_FAILED,
|
|
"Got response envelope of length %zi, expected 1 (success) or "
|
|
"3 (error)",
|
|
length);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
static void fl_json_method_codec_class_init(FlJsonMethodCodecClass* klass) {
|
|
G_OBJECT_CLASS(klass)->dispose = fl_json_method_codec_dispose;
|
|
FL_METHOD_CODEC_CLASS(klass)->encode_method_call =
|
|
fl_json_method_codec_encode_method_call;
|
|
FL_METHOD_CODEC_CLASS(klass)->decode_method_call =
|
|
fl_json_method_codec_decode_method_call;
|
|
FL_METHOD_CODEC_CLASS(klass)->encode_success_envelope =
|
|
fl_json_method_codec_encode_success_envelope;
|
|
FL_METHOD_CODEC_CLASS(klass)->encode_error_envelope =
|
|
fl_json_method_codec_encode_error_envelope;
|
|
FL_METHOD_CODEC_CLASS(klass)->decode_response =
|
|
fl_json_method_codec_decode_response;
|
|
}
|
|
|
|
static void fl_json_method_codec_init(FlJsonMethodCodec* self) {
|
|
self->codec = fl_json_message_codec_new();
|
|
}
|
|
|
|
G_MODULE_EXPORT FlJsonMethodCodec* fl_json_method_codec_new() {
|
|
return static_cast<FlJsonMethodCodec*>(
|
|
g_object_new(fl_json_method_codec_get_type(), nullptr));
|
|
}
|