blob: 0a047d529dd06df9fa3f763f870b409dd86639bc [file]
/**
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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 <string>
#include <variant>
#include "tsutil/ts_bw_format.h"
#include <yaml-cpp/yaml.h>
#include <tscore/ink_uuid.h>
/// JSONRPC 2.0 Client API utility definitions. Only client applications should use these definitions. Internal handlers should not
/// use these definitions. Check @c mgmg2/rpc/jsonrpc/Defs.h instead
/// @brief @c JSONRPC 2.0 message mapping classes.
/// This is a very thin API to deal with encoding/decoding jsonrpc 2.0 messages.
/// More info can be found https://www.jsonrpc.org/specification
namespace shared::rpc
{
struct JSONRPCRequest {
std::string jsonrpc{"2.0"}; //!< Always 2.0 as this is the only version that the server supports.
std::string method; //!< remote method name.
std::string id; //!< optional, only needed for method calls.
YAML::Node params; //!< This is defined by each remote API.
virtual ~JSONRPCRequest() {} ///< Virtual destructor required because virtual methods present.
virtual std::string
get_method() const
{
return this->method;
}
};
struct JSONRPCResponse {
std::string id; //!< Always 2.0 as this is the only version that the server supports.
std::string jsonrpc; //!< Always 2.0
YAML::Node result; //!< Server's response, this could be decoded by using the YAML::convert mechanism. This depends solely on the
//!< server's data. Check docs and schemas.
YAML::Node error; //!< Server's error.
/// Handy function to check if the server sent any error
bool
is_error() const
{
return !error.IsNull();
}
YAML::Node fullMsg;
};
struct JSONRPCError {
int32_t code; //!< High level error code.
std::string message; //!< High level message
// the following data is defined by TS, it will be a key/value pair.
std::vector<std::pair<int32_t, std::string>> data;
friend std::ostream &operator<<(std::ostream &os, const JSONRPCError &err);
};
/**
All of the following definitions have the main purpose to have a object style idiom when dealing with request and responses from/to
the JSONRPC server. This structures will then be used by the YAML codec implementation by using the YAML::convert style.
*/
///
/// @brief Base Client JSONRPC client request.
///
/// This represents a base class that implements the basic jsonrpc 2.0 required fields. We use UUID as an id generator
/// but this was an arbitrary choice, there is no conditions that forces to use this, any random id could work too.
/// When inherit from this class the @c id and the @c jsonrpc fields which are constant in all the request will be automatically
/// generated.
// TODO: fix this as id is optional.
struct ClientRequest : JSONRPCRequest {
using super = JSONRPCRequest;
ClientRequest() { super::id = _idGen.getString(); }
private:
struct IdGenerator {
IdGenerator() { _uuid.initialize(TS_UUID_V4); }
const char *
getString()
{
return _uuid.valid() ? _uuid.getString() : "fix.this.is.not.an.id";
}
ATSUuid _uuid;
};
IdGenerator _idGen;
};
/// @brief Class definition just to make clear that it will be a notification and no ID will be set.
struct ClientRequestNotification : JSONRPCRequest {
ClientRequestNotification() {}
};
/**
* Specific JSONRPC request implementation should be placed here. All this definitions helps for readability and in particular
* to easily emit json(or yaml) from this definitions.
*/
//------------------------------------------------------------------------------------------------------------------------------------
// handy definitions.
static const std::vector<int> CONFIG_REC_TYPES = {1, 16};
static const std::vector<int> METRIC_REC_TYPES = {2, 4, 32};
static constexpr bool NOT_REGEX{false};
static constexpr bool REGEX{true};
///
/// @brief Record lookup API helper class.
///
/// This utility class is used to encapsulate the basic data that contains a record lookup request.
/// Requests that are meant to interact with the admin_lookup_records API should inherit from this class if a special treatment is
/// needed. Otherwise use it directly.
///
struct RecordLookupRequest : ClientRequest {
using super = ClientRequest;
struct Params {
std::string recName;
bool isRegex{false};
std::vector<int> recTypes;
};
std::string
get_method() const override
{
return "admin_lookup_records";
}
template <typename... Args>
void
emplace_rec(Args &&...p)
{
super::params.push_back(Params{std::forward<Args>(p)...});
}
};
struct RecordLookUpResponse {
/// Response Records API mapping utility classes.
/// This utility class is used to hold the decoded response.
struct RecordParamInfo {
std::string name;
int32_t type;
int32_t version;
bool registered;
int32_t rsb;
int32_t order;
int32_t rclass;
bool overridable;
std::string dataType;
std::string currentValue;
std::string defaultValue;
struct ConfigMeta {
int32_t accessType;
int32_t updateStatus;
int32_t updateType;
int32_t checkType;
int32_t source;
std::string checkExpr;
};
struct StatMeta {
int32_t persistType;
};
std::variant<ConfigMeta, StatMeta> meta;
};
/// Record request error mapping class.
struct RecordError {
std::string code;
std::string recordName;
std::string message; //!< optional.
friend std::ostream &operator<<(std::ostream &os, const RecordError &re);
};
std::vector<RecordParamInfo> recordList;
std::vector<RecordError> errorList;
};
//------------------------------------------------------------------------------------------------------------------------------------
inline std::ostream &
operator<<(std::ostream &os, const RecordLookUpResponse::RecordError &re)
{
std::string text;
os << swoc::bwprint(text, "{:16s}: {}\n", "Record Name ", re.recordName);
os << swoc::bwprint(text, "{:16s}: {}\n", "Code", re.code);
if (!re.message.empty()) {
os << swoc::bwprint(text, "{:16s}: {}\n", "Message", re.message);
}
return os;
}
inline std::ostream &
operator<<(std::ostream &os, const JSONRPCError &err)
{
os << "Server Error found:\n";
os << "[" << err.code << "] " << err.message << '\n';
for (auto &&[code, message] : err.data) {
os << "- [" << code << "] " << message << '\n';
}
return os;
}
} // namespace shared::rpc