mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-11 15:39:36 -05:00
Improve debugabbility of JSON API
JSON API server uses standardized error handling based on std::error_condition for a few method, this improve debugabbility both from library size and from API client side JSON API auth token are now more flexible, now the only proibition is using colon character ':' in user name Implemented TO_JSON operation for std::error_condition Avoid unkown serial job handling code duplication via fatalUnknownSerialJob Usability improvement in t_RsLogger Disable compilation of now unused is_alphanumeric
This commit is contained in:
parent
9c65836503
commit
5dbbe1ffd7
@ -1 +1 @@
|
||||
Subproject commit c064abd74b27e1cc440917e9dbac800316bb8470
|
||||
Subproject commit 879d5dfe8dcd8995be753120cf1b8bab4dd2ec82
|
@ -73,6 +73,8 @@ JsonApiServer::corsOptionsHeaders =
|
||||
{ "Content-Length", "0" }
|
||||
};
|
||||
|
||||
/* static */const RsJsonApiErrorCategory JsonApiServer::sErrorCategory;
|
||||
|
||||
#define INITIALIZE_API_CALL_JSON_CONTEXT \
|
||||
RsGenericSerializer::SerializeContext cReq( \
|
||||
nullptr, 0, \
|
||||
@ -127,18 +129,16 @@ JsonApiServer::corsOptionsHeaders =
|
||||
bool RsJsonApi::parseToken(
|
||||
const std::string& clear_token, std::string& user,std::string& passwd )
|
||||
{
|
||||
uint32_t colonIndex = 0;
|
||||
uint32_t colonCounter = 0;
|
||||
auto colonIndex = std::string::npos;
|
||||
const auto tkLen = clear_token.length();
|
||||
|
||||
for(uint32_t i=0; i < tkLen && colonCounter < 2; ++i)
|
||||
if(clear_token[i] == ':') { ++colonCounter; colonIndex = i; }
|
||||
else if(!librs::util::is_alphanumeric(clear_token[i])) return false;
|
||||
for(uint32_t i=0; i < tkLen; ++i)
|
||||
if(clear_token[i] == ':') colonIndex = i;
|
||||
|
||||
if(colonCounter != 1) return false;
|
||||
user = clear_token.substr(0, colonIndex);
|
||||
|
||||
user = clear_token.substr(0, colonIndex);
|
||||
passwd = clear_token.substr(colonIndex + 1);
|
||||
if(colonIndex < tkLen)
|
||||
passwd = clear_token.substr(colonIndex + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -405,10 +405,22 @@ void JsonApiServer::registerHandler(
|
||||
|
||||
if(requiresAutentication)
|
||||
resource->set_authentication_handler(
|
||||
[this](
|
||||
[this, path](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const std::function<void (const std::shared_ptr<rb::Session>)>& callback )
|
||||
{
|
||||
const auto authFail =
|
||||
[&path, &session](int status) -> RsWarn::stream_type&
|
||||
{
|
||||
/* Capture session by reference as it is cheaper then copying
|
||||
* shared_ptr by value which is not needed in this case */
|
||||
|
||||
session->close(status, corsOptionsHeaders);
|
||||
return RsWarn() << "JsonApiServer authentication handler "
|
||||
"blocked an attempt to call JSON API "
|
||||
"authenticated method: " << path;
|
||||
};
|
||||
|
||||
if(session->get_request()->get_method() == "OPTIONS")
|
||||
{
|
||||
callback(session);
|
||||
@ -417,7 +429,8 @@ void JsonApiServer::registerHandler(
|
||||
|
||||
if(!rsLoginHelper->isLoggedIn())
|
||||
{
|
||||
session->close(rb::CONFLICT, corsOptionsHeaders);
|
||||
authFail(rb::CONFLICT) << " before RetroShare login"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -429,15 +442,26 @@ void JsonApiServer::registerHandler(
|
||||
|
||||
if(authToken != "Basic")
|
||||
{
|
||||
session->close(rb::UNAUTHORIZED, corsOptionsHeaders);
|
||||
authFail(rb::UNAUTHORIZED)
|
||||
<< " with wrong Authorization header: "
|
||||
<< authHeader.str() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::getline(authHeader, authToken, ' ');
|
||||
authToken = decodeToken(authToken);
|
||||
|
||||
if(isAuthTokenValid(authToken)) callback(session);
|
||||
else session->close(rb::UNAUTHORIZED, corsOptionsHeaders);
|
||||
std::error_condition ec;
|
||||
if(isAuthTokenValid(authToken, ec)) callback(session);
|
||||
else
|
||||
{
|
||||
std::string tUser;
|
||||
parseToken(authToken, tUser, RS_DEFAULT_STORAGE_PARAM(std::string));
|
||||
authFail(rb::UNAUTHORIZED)
|
||||
<< " user: " << tUser
|
||||
<< " error: " << ec.value() << " " << ec.message()
|
||||
<< std::endl;
|
||||
}
|
||||
} );
|
||||
|
||||
mResources.push_back(resource);
|
||||
@ -447,24 +471,62 @@ void JsonApiServer::setNewAccessRequestCallback(
|
||||
const std::function<bool (const std::string&, const std::string&)>& callback )
|
||||
{ mNewAccessRequestCallback = callback; }
|
||||
|
||||
bool JsonApiServer::requestNewTokenAutorization(
|
||||
/*static*/ std::error_condition JsonApiServer::badApiCredientalsFormat(
|
||||
const std::string& user, const std::string& passwd )
|
||||
{
|
||||
if(rsLoginHelper->isLoggedIn() && mNewAccessRequestCallback(user, passwd))
|
||||
return authorizeUser(user, passwd);
|
||||
if(user.find(':') < std::string::npos)
|
||||
return RsJsonApiErrorNum::API_USER_CONTAIN_COLON;
|
||||
|
||||
return false;
|
||||
if(user.empty())
|
||||
RsWarn() << __PRETTY_FUNCTION__ << " User is empty, are you sure "
|
||||
<< "this what you wanted?" << std::endl;
|
||||
|
||||
if(passwd.empty())
|
||||
RsWarn() << __PRETTY_FUNCTION__ << " Password is empty, are you sure "
|
||||
<< "this what you wanted?" << std::endl;
|
||||
|
||||
return std::error_condition();
|
||||
}
|
||||
|
||||
bool JsonApiServer::isAuthTokenValid(const std::string& token)
|
||||
std::error_condition JsonApiServer::requestNewTokenAutorization(
|
||||
const std::string& user, const std::string& passwd )
|
||||
{
|
||||
auto ec = badApiCredientalsFormat(user, passwd);
|
||||
if(ec) return ec;
|
||||
|
||||
if(!rsLoginHelper->isLoggedIn())
|
||||
return RsJsonApiErrorNum::CANNOT_EXECUTE_BEFORE_RS_LOGIN;
|
||||
|
||||
if(mNewAccessRequestCallback(user, passwd))
|
||||
return authorizeUser(user, passwd);
|
||||
|
||||
return RsJsonApiErrorNum::AUTHORIZATION_REQUEST_DENIED;
|
||||
}
|
||||
|
||||
bool JsonApiServer::isAuthTokenValid(
|
||||
const std::string& token, std::error_condition& error )
|
||||
{
|
||||
RS_STACK_MUTEX(configMutex);
|
||||
|
||||
const auto failure = [&error](RsJsonApiErrorNum e) -> bool
|
||||
{
|
||||
error = e;
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto success = [&error]()
|
||||
{
|
||||
error.clear();
|
||||
return true;
|
||||
};
|
||||
|
||||
std::string user,passwd;
|
||||
if(!parseToken(token,user,passwd)) return false;
|
||||
if(!parseToken(token, user, passwd))
|
||||
return failure(RsJsonApiErrorNum::TOKEN_FORMAT_INVALID);
|
||||
|
||||
auto it = mAuthTokenStorage.mAuthorizedTokens.find(user);
|
||||
if(it == mAuthTokenStorage.mAuthorizedTokens.end()) return false;
|
||||
if(it == mAuthTokenStorage.mAuthorizedTokens.end())
|
||||
return failure(RsJsonApiErrorNum::UNKNOWN_API_USER);
|
||||
|
||||
// attempt avoiding +else CRYPTO_memcmp+ being optimized away
|
||||
int noOptimiz = 1;
|
||||
@ -476,12 +538,16 @@ bool JsonApiServer::isAuthTokenValid(const std::string& token)
|
||||
if( passwd.size() == it->second.size() &&
|
||||
( noOptimiz = CRYPTO_memcmp(
|
||||
passwd.data(), it->second.data(), it->second.size() ) ) == 0 )
|
||||
return true;
|
||||
return success();
|
||||
// Make token size guessing harder
|
||||
else noOptimiz = CRYPTO_memcmp(passwd.data(), passwd.data(), passwd.size());
|
||||
|
||||
// attempt avoiding +else CRYPTO_memcmp+ being optimized away
|
||||
return static_cast<uint32_t>(noOptimiz) + 1 == 0;
|
||||
/* At this point we are sure password is wrong, and one could think to
|
||||
* plainly `return false` still this ugly and apparently unuseful extra
|
||||
* calculation is here to avoid `else CRYPTO_memcmp` being optimized away,
|
||||
* so a pontential attacker cannot guess password size based on timing */
|
||||
return static_cast<uint32_t>(noOptimiz) + 1 == 0 ?
|
||||
success() : failure(RsJsonApiErrorNum::WRONG_API_PASSWORD);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> JsonApiServer::getAuthorizedTokens()
|
||||
@ -509,22 +575,11 @@ void JsonApiServer::connectToConfigManager(p3ConfigMgr& cfgmgr)
|
||||
loadConfiguration(hash);
|
||||
}
|
||||
|
||||
bool JsonApiServer::authorizeUser(
|
||||
std::error_condition JsonApiServer::authorizeUser(
|
||||
const std::string& user, const std::string& passwd )
|
||||
{
|
||||
if(!librs::util::is_alphanumeric(user))
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__ << " User name is not alphanumeric"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(passwd.empty())
|
||||
{
|
||||
RsWarn() << __PRETTY_FUNCTION__ << " Password is empty, are you sure "
|
||||
<< "this what you wanted?" << std::endl;
|
||||
return false;
|
||||
}
|
||||
auto ec = badApiCredientalsFormat(user, passwd);
|
||||
if(ec) return ec;
|
||||
|
||||
RS_STACK_MUTEX(configMutex);
|
||||
|
||||
@ -534,7 +589,7 @@ bool JsonApiServer::authorizeUser(
|
||||
p = passwd;
|
||||
IndicateConfigChanged();
|
||||
}
|
||||
return true;
|
||||
return ec;
|
||||
}
|
||||
|
||||
/*static*/ std::string JsonApiServer::decodeToken(const std::string& radix64_token)
|
||||
@ -668,3 +723,29 @@ void JsonApiServer::run()
|
||||
extra = RS_EXTRA_VERSION;
|
||||
human = RS_HUMAN_READABLE_VERSION;
|
||||
}
|
||||
|
||||
|
||||
//std::error_code make_error_code(RsJsonApiErrorCode e)
|
||||
//{ return std::error_code(static_cast<int>(e), rsJsonApi->errorCategory()); }
|
||||
|
||||
std::error_condition make_error_condition(RsJsonApiErrorNum e)
|
||||
{
|
||||
return std::error_condition(static_cast<int>(e), rsJsonApi->errorCategory());
|
||||
}
|
||||
|
||||
|
||||
std::error_condition RsJsonApiErrorCategory::default_error_condition(int ev) const noexcept
|
||||
{
|
||||
switch(static_cast<RsJsonApiErrorNum>(ev))
|
||||
{
|
||||
case RsJsonApiErrorNum::TOKEN_FORMAT_INVALID: // fallthrough
|
||||
case RsJsonApiErrorNum::UNKNOWN_API_USER: // fallthrough
|
||||
case RsJsonApiErrorNum::WRONG_API_PASSWORD: // fallthrough
|
||||
case RsJsonApiErrorNum::AUTHORIZATION_REQUEST_DENIED:
|
||||
return std::errc::permission_denied;
|
||||
case RsJsonApiErrorNum::API_USER_CONTAIN_COLON:
|
||||
return std::errc::invalid_argument;
|
||||
default:
|
||||
return std::error_condition(ev, *this);
|
||||
}
|
||||
}
|
||||
|
@ -90,9 +90,8 @@ public:
|
||||
void connectToConfigManager(p3ConfigMgr& cfgmgr) override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
virtual bool authorizeUser(
|
||||
const std::string& alphanumeric_user,
|
||||
const std::string& alphanumeric_passwd ) override;
|
||||
virtual std::error_condition authorizeUser(
|
||||
const std::string& user, const std::string& passwd ) override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
std::map<std::string,std::string> getAuthorizedTokens() override;
|
||||
@ -101,10 +100,13 @@ public:
|
||||
bool revokeAuthToken(const std::string& user) override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
bool isAuthTokenValid(const std::string& token) override;
|
||||
bool isAuthTokenValid(
|
||||
const std::string& token,
|
||||
std::error_condition& error = RS_DEFAULT_STORAGE_PARAM(std::error_condition)
|
||||
) override;
|
||||
|
||||
/// @see RsJsonAPI
|
||||
bool requestNewTokenAutorization(
|
||||
std::error_condition requestNewTokenAutorization(
|
||||
const std::string& user, const std::string& password ) override;
|
||||
|
||||
/// @see RsJsonApi
|
||||
@ -143,10 +145,19 @@ public:
|
||||
const std::function<bool(const std::string&, const std::string&)>&
|
||||
callback );
|
||||
|
||||
/// @see RsJsonApi
|
||||
const std::error_category& errorCategory() override
|
||||
{ return sErrorCategory; }
|
||||
|
||||
protected:
|
||||
/// @see RsThread
|
||||
void onStopRequested() override;
|
||||
|
||||
static const RsJsonApiErrorCategory sErrorCategory;
|
||||
|
||||
static std::error_condition badApiCredientalsFormat(
|
||||
const std::string& user, const std::string& passwd );
|
||||
|
||||
private:
|
||||
/// @see RsThread
|
||||
void run() override;
|
||||
|
@ -25,9 +25,11 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <system_error>
|
||||
|
||||
#include "util/rsmemory.h"
|
||||
|
||||
class p3ConfigMgr;
|
||||
class JsonApiResourceProvider;
|
||||
class RsJsonApi;
|
||||
|
||||
/**
|
||||
@ -36,6 +38,55 @@ class RsJsonApi;
|
||||
*/
|
||||
extern RsJsonApi* rsJsonApi;
|
||||
|
||||
enum class RsJsonApiErrorNum : int32_t
|
||||
{
|
||||
TOKEN_FORMAT_INVALID = 2004,
|
||||
UNKNOWN_API_USER = 2005,
|
||||
WRONG_API_PASSWORD = 2006,
|
||||
API_USER_CONTAIN_COLON = 2007,
|
||||
AUTHORIZATION_REQUEST_DENIED = 2008,
|
||||
CANNOT_EXECUTE_BEFORE_RS_LOGIN = 2009
|
||||
};
|
||||
|
||||
struct RsJsonApiErrorCategory: std::error_category
|
||||
{
|
||||
const char* name() const noexcept override
|
||||
{ return "RetroShare JSON API"; }
|
||||
|
||||
std::string message(int ev) const override
|
||||
{
|
||||
switch (static_cast<RsJsonApiErrorNum>(ev))
|
||||
{
|
||||
case RsJsonApiErrorNum::TOKEN_FORMAT_INVALID:
|
||||
return "Invalid token format, must be alphanumeric_user:password";
|
||||
case RsJsonApiErrorNum::UNKNOWN_API_USER:
|
||||
return "Unknown API user";
|
||||
case RsJsonApiErrorNum::WRONG_API_PASSWORD:
|
||||
return "Wrong API password";
|
||||
case RsJsonApiErrorNum::API_USER_CONTAIN_COLON:
|
||||
return "API user cannot contain colon character";
|
||||
case RsJsonApiErrorNum::AUTHORIZATION_REQUEST_DENIED:
|
||||
return "User denied new token autorization";
|
||||
case RsJsonApiErrorNum::CANNOT_EXECUTE_BEFORE_RS_LOGIN:
|
||||
return "This operation cannot be executed bedore RetroShare login";
|
||||
default:
|
||||
return "Error message for error:" + std::to_string(ev) +
|
||||
" not available";
|
||||
}
|
||||
}
|
||||
|
||||
std::error_condition default_error_condition(int ev) const noexcept override;
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct is_error_condition_enum<RsJsonApiErrorNum>: true_type {};
|
||||
error_condition make_error_condition(RsJsonApiErrorNum e);
|
||||
}
|
||||
|
||||
class p3ConfigMgr;
|
||||
class JsonApiResourceProvider;
|
||||
|
||||
class RsJsonApi
|
||||
{
|
||||
public:
|
||||
@ -124,9 +175,9 @@ public:
|
||||
* @jsonapi{development,unauthenticated}
|
||||
* @param[in] user user name to authorize
|
||||
* @param[in] password password for the new user
|
||||
* @return true if authorization succeded, false otherwise.
|
||||
* @return if an error occurred details about it.
|
||||
*/
|
||||
virtual bool requestNewTokenAutorization(
|
||||
virtual std::error_condition requestNewTokenAutorization(
|
||||
const std::string& user, const std::string& password) = 0;
|
||||
|
||||
/** Split a token in USER:PASSWORD format into user and password */
|
||||
@ -135,14 +186,13 @@ public:
|
||||
std::string& user, std::string& passwd );
|
||||
|
||||
/**
|
||||
* Add new API auth (user,passwd) token to the authorized set.
|
||||
* Add new API auth user, passwd to the authorized set.
|
||||
* @jsonapi{development}
|
||||
* @param[in] user user name to autorize, must be alphanumerinc
|
||||
* @param[in] password password for the user, must be alphanumerinc
|
||||
* @return true if the token has been added to authorized, false if error
|
||||
* occurred
|
||||
* @param[in] user user name to autorize, must not contain ':'
|
||||
* @param[in] password password for the user
|
||||
* @return if some error occurred return details about it
|
||||
*/
|
||||
virtual bool authorizeUser(
|
||||
virtual std::error_condition authorizeUser(
|
||||
const std::string& user, const std::string& password ) = 0;
|
||||
|
||||
/**
|
||||
@ -164,9 +214,13 @@ public:
|
||||
* @brief Check if given JSON API auth token is authorized
|
||||
* @jsonapi{development,unauthenticated}
|
||||
* @param[in] token decoded
|
||||
* @return tru if authorized, false otherwise
|
||||
* @param[out] error optional storage for error details
|
||||
* @return true if authorized, false otherwise
|
||||
*/
|
||||
virtual bool isAuthTokenValid(const std::string& token) = 0;
|
||||
virtual bool isAuthTokenValid(
|
||||
const std::string& token,
|
||||
std::error_condition& error = RS_DEFAULT_STORAGE_PARAM(std::error_condition)
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* @brief Write version information to given paramethers
|
||||
@ -180,5 +234,9 @@ public:
|
||||
static void version( uint32_t& major, uint32_t& minor, uint32_t& mini,
|
||||
std::string& extra, std::string& human );
|
||||
|
||||
/** @brief Return a reference to service error category */
|
||||
virtual const std::error_category& errorCategory() = 0;
|
||||
|
||||
virtual ~RsJsonApi() = default;
|
||||
};
|
||||
|
||||
|
@ -768,3 +768,37 @@ bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RsTypeSerializer::ErrConditionWrapper::serial_process(
|
||||
RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx )
|
||||
{
|
||||
switch(j)
|
||||
{
|
||||
case RsGenericSerializer::SIZE_ESTIMATE: // fallthrough
|
||||
case RsGenericSerializer::DESERIALIZE: // fallthrough
|
||||
case RsGenericSerializer::SERIALIZE: // fallthrough
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " SerializeJob: " << j
|
||||
<< "is not supported on std::error_condition " << std::endl;
|
||||
print_stacktrace();
|
||||
exit(-2);
|
||||
case RsGenericSerializer::PRINT: // fallthrough
|
||||
case RsGenericSerializer::TO_JSON:
|
||||
{
|
||||
constexpr RsGenericSerializer::SerializeJob rj =
|
||||
RsGenericSerializer::TO_JSON;
|
||||
|
||||
int32_t tNum = mec.value();
|
||||
RsTypeSerializer::serial_process(rj, ctx, tNum, "errorNumber");
|
||||
|
||||
std::string tStr = mec.category().name();
|
||||
RsTypeSerializer::serial_process(rj, ctx, tStr, "errorCategory");
|
||||
|
||||
tStr = mec.message();
|
||||
RsTypeSerializer::serial_process(rj, ctx, tStr, "errorMessage");
|
||||
break;
|
||||
}
|
||||
default: RsTypeSerializer::fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,12 @@
|
||||
*******************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <typeinfo> // for typeid
|
||||
#include <type_traits>
|
||||
#include <errno.h>
|
||||
#include <system_error>
|
||||
|
||||
|
||||
#include "serialiser/rsserial.h"
|
||||
#include "serialiser/rstlvbase.h"
|
||||
#include "serialiser/rstlvlist.h"
|
||||
@ -34,11 +40,6 @@
|
||||
#include "util/rsjson.h"
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
#include <typeinfo> // for typeid
|
||||
#include <type_traits>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
/* INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set}<T>
|
||||
* Can't use a template function because T is needed for const_cast */
|
||||
#define RsTypeSerializer_PRIVATE_TO_JSON_ARRAY() do \
|
||||
@ -132,7 +133,12 @@ struct RsTypeSerializer
|
||||
|
||||
/// Generic types
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_same<RsTlvItem,T>::value || !(std::is_base_of<RsSerializable,T>::value || std::is_enum<T>::value || std::is_base_of<RsTlvItem,T>::value )>::type
|
||||
typename
|
||||
std::enable_if< std::is_same<RsTlvItem,T>::value || !(
|
||||
std::is_base_of<RsSerializable,T>::value ||
|
||||
std::is_enum<T>::value ||
|
||||
std::is_base_of<RsTlvItem,T>::value ||
|
||||
std::is_same<std::error_condition,T>::value ) >::type
|
||||
static /*void*/ serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
T& member, const std::string& member_name )
|
||||
@ -160,11 +166,7 @@ struct RsTypeSerializer
|
||||
ctx.mOk &= (ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING)
|
||||
&& from_JSON(member_name, member, ctx.mJson);
|
||||
break;
|
||||
default:
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: "
|
||||
<< static_cast<std::underlying_type<decltype(j)>::type>(j)
|
||||
<< std::endl;
|
||||
exit(EINVAL);
|
||||
default: fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,11 +202,7 @@ struct RsTypeSerializer
|
||||
(ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING)
|
||||
&& from_JSON(member_name, type_id, member, ctx.mJson);
|
||||
break;
|
||||
default:
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: "
|
||||
<< static_cast<std::underlying_type<decltype(j)>::type>(j)
|
||||
<< std::endl;
|
||||
exit(EINVAL);
|
||||
default: fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,11 +360,7 @@ struct RsTypeSerializer
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: "
|
||||
<< static_cast<std::underlying_type<decltype(j)>::type>(j)
|
||||
<< std::endl;
|
||||
exit(EINVAL);
|
||||
default: fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
||||
@ -441,12 +435,7 @@ struct RsTypeSerializer
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: "
|
||||
<< static_cast<std::underlying_type<decltype(j)>::type>(j)
|
||||
<< std::endl;
|
||||
exit(EINVAL);
|
||||
break;
|
||||
default: fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,7 +494,7 @@ struct RsTypeSerializer
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(push_back);
|
||||
break;
|
||||
default: break;
|
||||
default: fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,7 +553,7 @@ struct RsTypeSerializer
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(insert);
|
||||
break;
|
||||
default: break;
|
||||
default: fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
||||
@ -620,7 +609,7 @@ struct RsTypeSerializer
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(push_back);
|
||||
break;
|
||||
default: break;
|
||||
default: fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
||||
@ -663,7 +652,7 @@ struct RsTypeSerializer
|
||||
&& (v = t_RsFlags32<N>(f), true);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
default: fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
||||
@ -772,18 +761,15 @@ struct RsTypeSerializer
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: "
|
||||
<< static_cast<std::underlying_type<decltype(j)>::type>(j)
|
||||
<< std::endl;
|
||||
exit(EINVAL);
|
||||
break;
|
||||
default: fatalUnknownSerialJob(j);
|
||||
}
|
||||
}
|
||||
|
||||
/// RsTlvItem derivatives only
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_base_of<RsTlvItem,T>::value && !std::is_same<RsTlvItem,T>::value>::type
|
||||
typename std::enable_if<
|
||||
std::is_base_of<RsTlvItem,T>::value && !std::is_same<RsTlvItem,T>::value
|
||||
>::type
|
||||
static /*void*/ serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
T& member,
|
||||
@ -792,6 +778,21 @@ struct RsTypeSerializer
|
||||
serial_process(j, ctx, static_cast<RsTlvItem&>(member), memberName);
|
||||
}
|
||||
|
||||
/** std::error_condition
|
||||
* supports only TO_JSON ErrConditionWrapper::serial_process will explode
|
||||
* at runtime if a different SerializeJob is passed down */
|
||||
template<typename T>
|
||||
typename std::enable_if< std::is_base_of<std::error_condition,T>::value >::type
|
||||
static /*void*/ serial_process(
|
||||
RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
const T& cond,
|
||||
const std::string& member_name )
|
||||
{
|
||||
ErrConditionWrapper ew(cond);
|
||||
serial_process(j, ctx, ew, member_name);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//============================================================================//
|
||||
@ -909,6 +910,27 @@ protected:
|
||||
t_RsTlvList<TLV_CLASS,TLV_TYPE>& member,
|
||||
RsJson& jDoc );
|
||||
|
||||
[[noreturn]] static void fatalUnknownSerialJob(int j)
|
||||
{
|
||||
RsFatal() << " Unknown serial job: " << j << std::endl;
|
||||
print_stacktrace();
|
||||
exit(EINVAL);
|
||||
}
|
||||
|
||||
struct ErrConditionWrapper : RsSerializable
|
||||
{
|
||||
ErrConditionWrapper(const std::error_condition& ec): mec(ec) {}
|
||||
|
||||
/** supports only TO_JSON if a different SerializeJob is passed it will
|
||||
* explode at runtime */
|
||||
void serial_process(
|
||||
RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx ) override;
|
||||
|
||||
private:
|
||||
const std::error_condition& mec;
|
||||
};
|
||||
|
||||
RS_SET_CONTEXT_DEBUG_LEVEL(1)
|
||||
};
|
||||
|
||||
|
@ -41,12 +41,14 @@ struct t_RsLogger
|
||||
{
|
||||
inline t_RsLogger() = default;
|
||||
|
||||
typedef t_RsLogger stream_type;
|
||||
|
||||
template<typename T>
|
||||
inline t_RsLogger& operator<<(const T& val)
|
||||
inline stream_type& operator<<(const T& val)
|
||||
{ ostr << val; return *this; }
|
||||
|
||||
/// needed for manipulators and things like std::endl
|
||||
t_RsLogger& operator<<(std::ostream& (*pf)(std::ostream&))
|
||||
stream_type& operator<<(std::ostream& (*pf)(std::ostream&))
|
||||
{
|
||||
if(pf == static_cast<std::ostream& (*)(std::ostream&)>(
|
||||
&std::endl< char, std::char_traits<char> > ))
|
||||
@ -84,8 +86,10 @@ struct t_RsLogger
|
||||
{
|
||||
inline t_RsLogger() = default;
|
||||
|
||||
typedef decltype(std::cerr) stream_type;
|
||||
|
||||
template<typename T>
|
||||
inline std::ostream& operator<<(const T& val)
|
||||
inline stream_type& operator<<(const T& val)
|
||||
{
|
||||
return std::cerr << static_cast<char>(CATEGORY) << " " << time(nullptr)
|
||||
<< " " << val;
|
||||
|
@ -205,6 +205,7 @@ bool ConvertUtf16ToUtf8(const std::wstring& source, std::string& dest)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool is_alphanumeric(char c)
|
||||
{
|
||||
return (c>='0' && c<='9') || (c>='a' && c<='z') || (c>='A' && c<='Z');
|
||||
@ -216,6 +217,7 @@ bool is_alphanumeric(const std::string& s)
|
||||
if(!is_alphanumeric(s[i])) return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} } // librs::util
|
||||
|
||||
|
@ -30,10 +30,10 @@ namespace librs {
|
||||
|
||||
bool ConvertUtf8ToUtf16(const std::string& source, std::wstring& dest);
|
||||
bool ConvertUtf16ToUtf8(const std::wstring& source, std::string& dest);
|
||||
|
||||
#if 0
|
||||
bool is_alphanumeric(char c) ;
|
||||
bool is_alphanumeric(const std::string& s);
|
||||
|
||||
#endif
|
||||
} } // librs::util
|
||||
|
||||
#ifdef WIN32
|
||||
|
Loading…
Reference in New Issue
Block a user