Add td_api::JsonValue support.
GitOrigin-RevId: b79580a42f72c195c7c76d213f277702ee035907
This commit is contained in:
parent
c4c9707f7a
commit
e2b8b72541
@ -379,6 +379,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/HashtagHints.cpp
|
||||
td/telegram/InlineQueriesManager.cpp
|
||||
td/telegram/InputMessageText.cpp
|
||||
td/telegram/JsonValue.cpp
|
||||
td/telegram/LanguagePackManager.cpp
|
||||
td/telegram/Location.cpp
|
||||
td/telegram/Logging.cpp
|
||||
@ -502,6 +503,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/HashtagHints.h
|
||||
td/telegram/InlineQueriesManager.h
|
||||
td/telegram/InputMessageText.h
|
||||
td/telegram/JsonValue.h
|
||||
td/telegram/LanguagePackManager.h
|
||||
td/telegram/Location.h
|
||||
td/telegram/logevent/LogEvent.h
|
||||
|
@ -1825,19 +1825,43 @@ notificationGroup id:int32 chat_id:int53 total_count:int32 notifications:vector<
|
||||
|
||||
//@class OptionValue @description Represents the value of an option
|
||||
|
||||
//@description Boolean option @value The value of the option
|
||||
//@description Represents a boolean option @value The value of the option
|
||||
optionValueBoolean value:Bool = OptionValue;
|
||||
|
||||
//@description An unknown option or an option which has a default value
|
||||
//@description Represents an unknown option or an option which has a default value
|
||||
optionValueEmpty = OptionValue;
|
||||
|
||||
//@description An integer option @value The value of the option
|
||||
//@description Represents an integer option @value The value of the option
|
||||
optionValueInteger value:int32 = OptionValue;
|
||||
|
||||
//@description A string option @value The value of the option
|
||||
//@description Represents a string option @value The value of the option
|
||||
optionValueString value:string = OptionValue;
|
||||
|
||||
|
||||
//@description Represents one member of a JSON object @key Member's key @value Member's value
|
||||
jsonObjectMember key:string value:JsonValue = JsonObjectMember;
|
||||
|
||||
//@class JsonValue @description Represents a JSON value
|
||||
|
||||
//@description Represents a null JSON value
|
||||
jsonValueNull = JsonValue;
|
||||
|
||||
//@description Represents a boolean JSON value @value The value
|
||||
jsonValueBoolean value:Bool = JsonValue;
|
||||
|
||||
//@description Represents a numeric JSON value @value The value
|
||||
jsonValueNumber value:double = JsonValue;
|
||||
|
||||
//@description Represents a string JSON value @value The value
|
||||
jsonValueString value:string = JsonValue;
|
||||
|
||||
//@description Represents a JSON array @values The list of array elements
|
||||
jsonValueArray values:vector<JsonValue> = JsonValue;
|
||||
|
||||
//@description Represents a JSON object @members The list of object members
|
||||
jsonValueObject members:vector<jsonObjectMember> = JsonValue;
|
||||
|
||||
|
||||
//@class UserPrivacySettingRule @description Represents a single rule for managing privacy settings
|
||||
|
||||
//@description A rule to allow all users to do something
|
||||
@ -2728,6 +2752,12 @@ cleanFileName file_name:string = Text;
|
||||
//@language_pack_database_path Path to the language pack database in which strings are stored @localization_target Localization target to which the language pack belongs @language_pack_id Language pack identifier @key Language pack key of the string to be returned
|
||||
getLanguagePackString language_pack_database_path:string localization_target:string language_pack_id:string key:string = LanguagePackStringValue;
|
||||
|
||||
//@description Converts a JSON-serialized string to corresponding JsonValue object. This is an offline method. Can be called before authorization. Can be called synchronously @json The JSON-serialized string
|
||||
getJsonValue json:string = JsonValue;
|
||||
|
||||
//@description Converts a JsonValue object to corresponding JSON-serialized string. This is an offline method. Can be called before authorization. Can be called synchronously @json_value The JsonValue object
|
||||
getJsonString json_value:JsonValue = Text;
|
||||
|
||||
|
||||
//@description Sends an inline query to a bot and returns its results. Returns an error with code 502 if the bot fails to answer the query before the query timeout expires @bot_user_id The identifier of the target bot
|
||||
//@chat_id Identifier of the chat, where the query was sent @user_location Location of the user, only if needed @query Text of the query @offset Offset of the first entry to return
|
||||
|
Binary file not shown.
@ -88,8 +88,8 @@ void gen_from_json_constructor(StringBuilder &sb, const T *constructor, bool is_
|
||||
for (auto &arg : constructor->args) {
|
||||
sb << " {\n";
|
||||
sb << " TRY_RESULT(value, get_json_object_field(from, \"" << tl::simple::gen_cpp_name(arg.name)
|
||||
<< "\", JsonValue::Type::Null, true));\n";
|
||||
sb << " if (value.type() != JsonValue::Type::Null) {\n";
|
||||
<< "\", td::JsonValue::Type::Null, true));\n";
|
||||
sb << " if (value.type() != td::JsonValue::Type::Null) {\n";
|
||||
if (arg.type->type == tl::simple::Type::Bytes) {
|
||||
sb << " TRY_STATUS(from_json_bytes(to." << tl::simple::gen_cpp_field_name(arg.name) << ", value));\n";
|
||||
} else {
|
||||
|
103
td/telegram/JsonValue.cpp
Normal file
103
td/telegram/JsonValue.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/telegram/JsonValue.h"
|
||||
|
||||
#include "td/utils/JsonBuilder.h"
|
||||
#include "td/utils/misc.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
static td_api::object_ptr<td_api::JsonValue> get_json_value_object(const JsonValue &json_value);
|
||||
|
||||
static td_api::object_ptr<td_api::jsonObjectMember> get_json_value_member_object(
|
||||
const std::pair<MutableSlice, JsonValue> &json_value_member) {
|
||||
return td_api::make_object<td_api::jsonObjectMember>(json_value_member.first.str(),
|
||||
get_json_value_object(json_value_member.second));
|
||||
}
|
||||
|
||||
static td_api::object_ptr<td_api::JsonValue> get_json_value_object(const JsonValue &json_value) {
|
||||
switch (json_value.type()) {
|
||||
case JsonValue::Type::Null:
|
||||
return td_api::make_object<td_api::jsonValueNull>();
|
||||
case JsonValue::Type::Boolean:
|
||||
return td_api::make_object<td_api::jsonValueBoolean>(json_value.get_boolean());
|
||||
case JsonValue::Type::Number:
|
||||
return td_api::make_object<td_api::jsonValueNumber>(to_double(json_value.get_number()));
|
||||
case JsonValue::Type::String:
|
||||
return td_api::make_object<td_api::jsonValueString>(json_value.get_string().str());
|
||||
case JsonValue::Type::Array:
|
||||
return td_api::make_object<td_api::jsonValueArray>(transform(json_value.get_array(), get_json_value_object));
|
||||
case JsonValue::Type::Object:
|
||||
return td_api::make_object<td_api::jsonValueObject>(
|
||||
transform(json_value.get_object(), get_json_value_member_object));
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Result<td_api::object_ptr<td_api::JsonValue>> get_json_value(MutableSlice json) {
|
||||
TRY_RESULT(json_value, json_decode(json));
|
||||
return get_json_value_object(json_value);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class JsonableJsonValue : public Jsonable {
|
||||
public:
|
||||
explicit JsonableJsonValue(const td_api::JsonValue *json_value) : json_value_(json_value) {
|
||||
}
|
||||
void store(JsonValueScope *scope) const {
|
||||
if (json_value_ == nullptr) {
|
||||
*scope << JsonNull();
|
||||
return;
|
||||
}
|
||||
switch (json_value_->get_id()) {
|
||||
case td_api::jsonValueNull::ID:
|
||||
*scope << JsonNull();
|
||||
break;
|
||||
case td_api::jsonValueBoolean::ID:
|
||||
*scope << static_cast<const td_api::jsonValueBoolean *>(json_value_)->value_;
|
||||
break;
|
||||
case td_api::jsonValueNumber::ID:
|
||||
*scope << static_cast<const td_api::jsonValueNumber *>(json_value_)->value_;
|
||||
break;
|
||||
case td_api::jsonValueString::ID:
|
||||
*scope << static_cast<const td_api::jsonValueString *>(json_value_)->value_;
|
||||
break;
|
||||
case td_api::jsonValueArray::ID: {
|
||||
auto array = scope->enter_array();
|
||||
for (auto &value : static_cast<const td_api::jsonValueArray *>(json_value_)->values_) {
|
||||
array << JsonableJsonValue(value.get());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case td_api::jsonValueObject::ID: {
|
||||
auto object = scope->enter_object();
|
||||
for (auto &member : static_cast<const td_api::jsonValueObject *>(json_value_)->members_) {
|
||||
if (member != nullptr) {
|
||||
object << ctie(member->key_, JsonableJsonValue(member->value_.get()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const td_api::JsonValue *json_value_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
string get_json_string(const td_api::JsonValue *json_value) {
|
||||
return json_encode<string>(JsonableJsonValue(json_value));
|
||||
}
|
||||
|
||||
} // namespace td
|
21
td/telegram/JsonValue.h
Normal file
21
td/telegram/JsonValue.h
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/td_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
Result<td_api::object_ptr<td_api::JsonValue>> get_json_value(MutableSlice json);
|
||||
|
||||
string get_json_string(const td_api::JsonValue *json_value);
|
||||
|
||||
} // namespace td
|
@ -38,6 +38,7 @@
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/HashtagHints.h"
|
||||
#include "td/telegram/InlineQueriesManager.h"
|
||||
#include "td/telegram/JsonValue.h"
|
||||
#include "td/telegram/LanguagePackManager.h"
|
||||
#include "td/telegram/Logging.h"
|
||||
#include "td/telegram/MessageEntity.h"
|
||||
@ -3119,6 +3120,8 @@ bool Td::is_synchronous_request(int32 id) {
|
||||
case td_api::getFileExtension::ID:
|
||||
case td_api::cleanFileName::ID:
|
||||
case td_api::getLanguagePackString::ID:
|
||||
case td_api::getJsonValue::ID:
|
||||
case td_api::getJsonString::ID:
|
||||
case td_api::setLogStream::ID:
|
||||
case td_api::getLogStream::ID:
|
||||
case td_api::setLogVerbosityLevel::ID:
|
||||
@ -3322,6 +3325,8 @@ td_api::object_ptr<td_api::Object> Td::static_request(td_api::object_ptr<td_api:
|
||||
case td_api::getFileMimeType::ID:
|
||||
case td_api::getFileExtension::ID:
|
||||
case td_api::cleanFileName::ID:
|
||||
case td_api::getJsonValue::ID:
|
||||
case td_api::getJsonString::ID:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -6771,7 +6776,7 @@ void Td::on_request(uint64 id, const td_api::getTextEntities &request) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, td_api::parseTextEntities &request) {
|
||||
void Td::on_request(uint64 id, const td_api::parseTextEntities &request) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@ -6791,6 +6796,14 @@ void Td::on_request(uint64 id, const td_api::getLanguagePackString &request) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getJsonValue &request) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getJsonString &request) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::setLogStream &request) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -6873,6 +6886,22 @@ td_api::object_ptr<td_api::Object> Td::do_static_request(const td_api::getLangua
|
||||
request.language_pack_database_path_, request.localization_target_, request.language_pack_id_, request.key_);
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::Object> Td::do_static_request(td_api::getJsonValue &request) {
|
||||
if (!check_utf8(request.json_)) {
|
||||
return make_error(400, "JSON has invalid encoding");
|
||||
}
|
||||
auto result = get_json_value(request.json_);
|
||||
if (result.is_error()) {
|
||||
return make_error(400, result.error().message());
|
||||
} else {
|
||||
return result.move_as_ok();
|
||||
}
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::Object> Td::do_static_request(const td_api::getJsonString &request) {
|
||||
return td_api::make_object<td_api::text>(get_json_string(request.json_value_.get()));
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::Object> Td::do_static_request(td_api::setLogStream &request) {
|
||||
auto result = Logging::set_current_stream(std::move(request.log_stream_));
|
||||
if (result.is_ok()) {
|
||||
|
@ -910,7 +910,7 @@ class Td final : public NetQueryCallback {
|
||||
|
||||
void on_request(uint64 id, const td_api::getTextEntities &request);
|
||||
|
||||
void on_request(uint64 id, td_api::parseTextEntities &request);
|
||||
void on_request(uint64 id, const td_api::parseTextEntities &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getFileMimeType &request);
|
||||
|
||||
@ -920,6 +920,10 @@ class Td final : public NetQueryCallback {
|
||||
|
||||
void on_request(uint64 id, const td_api::getLanguagePackString &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getJsonValue &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getJsonString &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::setLogStream &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getLogStream &request);
|
||||
@ -958,6 +962,8 @@ class Td final : public NetQueryCallback {
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getFileExtension &request);
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::cleanFileName &request);
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getLanguagePackString &request);
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(td_api::getJsonValue &request);
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getJsonString &request);
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(td_api::setLogStream &request);
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::getLogStream &request);
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::setLogVerbosityLevel &request);
|
||||
|
@ -2382,11 +2382,40 @@ class CliClient final : public Actor {
|
||||
} else if (op == "ptehs") {
|
||||
execute(make_tl_object<td_api::parseTextEntities>(args, make_tl_object<td_api::textParseModeHTML>()));
|
||||
} else if (op == "gfmt") {
|
||||
send_request(make_tl_object<td_api::getFileMimeType>(trim(args)));
|
||||
execute(make_tl_object<td_api::getFileMimeType>(trim(args)));
|
||||
} else if (op == "gfe") {
|
||||
send_request(make_tl_object<td_api::getFileExtension>(trim(args)));
|
||||
execute(make_tl_object<td_api::getFileExtension>(trim(args)));
|
||||
} else if (op == "cfn") {
|
||||
send_request(make_tl_object<td_api::cleanFileName>(args));
|
||||
execute(make_tl_object<td_api::cleanFileName>(args));
|
||||
} else if (op == "gjv") {
|
||||
execute(td_api::make_object<td_api::getJsonValue>(args));
|
||||
} else if (op == "gjs") {
|
||||
execute(td_api::make_object<td_api::getJsonString>());
|
||||
execute(td_api::make_object<td_api::getJsonString>(td_api::make_object<td_api::jsonValueNull>()));
|
||||
execute(td_api::make_object<td_api::getJsonString>(td_api::make_object<td_api::jsonValueBoolean>(true)));
|
||||
execute(td_api::make_object<td_api::getJsonString>(td_api::make_object<td_api::jsonValueNumber>(123456789123.0)));
|
||||
execute(
|
||||
td_api::make_object<td_api::getJsonString>(td_api::make_object<td_api::jsonValueString>(string("aba\x00"
|
||||
"caba",
|
||||
8))));
|
||||
|
||||
auto inner_array = td_api::make_object<td_api::jsonValueArray>();
|
||||
inner_array->values_.push_back(td_api::make_object<td_api::jsonValueBoolean>(false));
|
||||
auto array = td_api::make_object<td_api::jsonValueArray>();
|
||||
array->values_.push_back(nullptr);
|
||||
array->values_.push_back(std::move(inner_array));
|
||||
array->values_.push_back(td_api::make_object<td_api::jsonValueNull>());
|
||||
array->values_.push_back(td_api::make_object<td_api::jsonValueNumber>(-1));
|
||||
execute(td_api::make_object<td_api::getJsonString>(std::move(array)));
|
||||
|
||||
auto object = td_api::make_object<td_api::jsonValueObject>();
|
||||
object->members_.push_back(
|
||||
td_api::make_object<td_api::jsonObjectMember>("", td_api::make_object<td_api::jsonValueString>("test")));
|
||||
object->members_.push_back(td_api::make_object<td_api::jsonObjectMember>("a", nullptr));
|
||||
object->members_.push_back(nullptr);
|
||||
object->members_.push_back(
|
||||
td_api::make_object<td_api::jsonObjectMember>("a", td_api::make_object<td_api::jsonValueNull>()));
|
||||
execute(td_api::make_object<td_api::getJsonString>(std::move(object)));
|
||||
} else {
|
||||
op_not_found_count++;
|
||||
}
|
||||
|
@ -344,17 +344,17 @@ Result<JsonValue> do_json_decode(Parser &parser, int32 max_depth) {
|
||||
if (parser.skip_start_with("false")) {
|
||||
return JsonValue::create_boolean(false);
|
||||
}
|
||||
return Status::Error("Starts with 'f' -- false expected");
|
||||
return Status::Error("Token starts with 'f' -- false expected");
|
||||
case 't':
|
||||
if (parser.skip_start_with("true")) {
|
||||
return JsonValue::create_boolean(true);
|
||||
}
|
||||
return Status::Error("Starts with 't' -- true expected");
|
||||
return Status::Error("Token starts with 't' -- true expected");
|
||||
case 'n':
|
||||
if (parser.skip_start_with("null")) {
|
||||
return JsonValue();
|
||||
}
|
||||
return Status::Error("Starts with 'n' -- null expected");
|
||||
return Status::Error("Token starts with 'n' -- null expected");
|
||||
case '"': {
|
||||
TRY_RESULT(slice, json_string_decode(parser));
|
||||
return JsonValue::create_string(slice);
|
||||
@ -368,7 +368,7 @@ Result<JsonValue> do_json_decode(Parser &parser, int32 max_depth) {
|
||||
}
|
||||
while (true) {
|
||||
if (parser.empty()) {
|
||||
return Status::Error("Unexpected end");
|
||||
return Status::Error("Unexpected string end");
|
||||
}
|
||||
TRY_RESULT(value, do_json_decode(parser, max_depth - 1));
|
||||
res.emplace_back(std::move(value));
|
||||
@ -381,7 +381,10 @@ Result<JsonValue> do_json_decode(Parser &parser, int32 max_depth) {
|
||||
parser.skip_whitespaces();
|
||||
continue;
|
||||
}
|
||||
return Status::Error("Unexpected symbol");
|
||||
if (parser.empty()) {
|
||||
return Status::Error("Unexpected string end");
|
||||
}
|
||||
return Status::Error("Unexpected symbol while parsing JSON Array");
|
||||
}
|
||||
return JsonValue::create_array(std::move(res));
|
||||
}
|
||||
@ -394,7 +397,7 @@ Result<JsonValue> do_json_decode(Parser &parser, int32 max_depth) {
|
||||
}
|
||||
while (true) {
|
||||
if (parser.empty()) {
|
||||
return Status::Error("Unexpected end");
|
||||
return Status::Error("Unexpected string end");
|
||||
}
|
||||
TRY_RESULT(key, json_string_decode(parser));
|
||||
parser.skip_whitespaces();
|
||||
@ -412,7 +415,10 @@ Result<JsonValue> do_json_decode(Parser &parser, int32 max_depth) {
|
||||
parser.skip_whitespaces();
|
||||
continue;
|
||||
}
|
||||
return Status::Error("Unexpected symbol");
|
||||
if (parser.empty()) {
|
||||
return Status::Error("Unexpected string end");
|
||||
}
|
||||
return Status::Error("Unexpected symbol while parsing JSON Object");
|
||||
}
|
||||
return JsonValue::make_object(std::move(res));
|
||||
}
|
||||
@ -434,7 +440,7 @@ Result<JsonValue> do_json_decode(Parser &parser, int32 max_depth) {
|
||||
return JsonValue::create_number(num);
|
||||
}
|
||||
case 0:
|
||||
return Status::Error("Unexpected end");
|
||||
return Status::Error("Unexpected string end");
|
||||
default: {
|
||||
char next = parser.peek_char();
|
||||
if (0 < next && next < 127) {
|
||||
|
@ -723,8 +723,8 @@ Status json_string_skip(Parser &parser) TD_WARN_UNUSED_RESULT;
|
||||
Result<JsonValue> do_json_decode(Parser &parser, int32 max_depth) TD_WARN_UNUSED_RESULT;
|
||||
Status do_json_skip(Parser &parser, int32 max_depth) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
inline Result<JsonValue> json_decode(MutableSlice from) {
|
||||
Parser parser(from);
|
||||
inline Result<JsonValue> json_decode(MutableSlice json) {
|
||||
Parser parser(json);
|
||||
const int32 DEFAULT_MAX_DEPTH = 100;
|
||||
auto result = do_json_decode(parser, DEFAULT_MAX_DEPTH);
|
||||
if (result.is_ok()) {
|
||||
|
Reference in New Issue
Block a user