Keep 10 extra unassigned slots for event types

Proper error reporting + cruft removal
This commit is contained in:
Gioacchino Mazzurco 2020-04-06 17:10:16 +02:00
parent 76d492b4aa
commit b701ca8da3
No known key found for this signature in database
GPG Key ID: A1FBCA3872E87051
5 changed files with 149 additions and 109 deletions

View File

@ -395,7 +395,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
} ); } );
}; };
bool retval = rsEvents->registerEventsHandler( auto retval = rsEvents->registerEventsHandler(
multiCallback, hId, eventType ); multiCallback, hId, eventType );
{ {

View File

@ -151,8 +151,6 @@ protected:
/// @see RsThread /// @see RsThread
void onStopRequested() override; void onStopRequested() override;
static const RsJsonApiErrorCategory sErrorCategory;
static std::error_condition badApiCredientalsFormat( static std::error_condition badApiCredientalsFormat(
const std::string& user, const std::string& passwd ); const std::string& user, const std::string& passwd );

View File

@ -3,7 +3,9 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2019-2020 Retroshare Team <contact@retroshare.cc> *
* Copyright (C) 2019-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -97,9 +99,60 @@ enum class RsEventType : uint32_t
/// @see RsMsgs /// @see RsMsgs
CHAT_MESSAGE = 15, CHAT_MESSAGE = 15,
__MAX /// Used internally to detect invalid event type passed __MAX /// Used internally, keep last
}; };
enum class RsEventsErrorNum : int32_t
{
EVENT_TYPE_UNDEFINED = 3004,
EVENT_TYPE_OUT_OF_RANGE = 3005,
INVALID_HANDLER_ID = 3006,
NULL_EVENT_POINTER = 3007
};
struct RsEventsErrorCategory: std::error_category
{
const char* name() const noexcept override
{ return "RetroShare Events"; }
std::string message(int ev) const override
{
switch (static_cast<RsEventsErrorNum>(ev))
{
case RsEventsErrorNum::EVENT_TYPE_UNDEFINED:
return "Undefined event type";
case RsEventsErrorNum::EVENT_TYPE_OUT_OF_RANGE:
return "Event type out of range";
case RsEventsErrorNum::INVALID_HANDLER_ID:
return "Invalid handler id";
default:
return "Error message for error: " + std::to_string(ev) +
" not available in category: " + name();
}
}
std::error_condition default_error_condition(int ev) const noexcept override;
const static RsEventsErrorCategory instance;
};
namespace std
{
/** Register RsJsonApiErrorNum as an error condition enum, must be in std
* namespace */
template<> struct is_error_condition_enum<RsEventsErrorNum> : true_type {};
}
/** Provide RsEventsErrorNum conversion to std::error_condition, must be in
* same namespace of RsJsonApiErrorNum */
inline std::error_condition make_error_condition(RsEventsErrorNum e) noexcept
{
return std::error_condition(
static_cast<int>(e), RsEventsErrorCategory::instance );
};
/** /**
* This struct is not meant to be used directly, you should create events type * This struct is not meant to be used directly, you should create events type
* deriving from it. * deriving from it.
@ -144,12 +197,10 @@ public:
* @param[in] event * @param[in] event
* @param[out] errorMessage Optional storage for error messsage, meaningful * @param[out] errorMessage Optional storage for error messsage, meaningful
* only on failure. * only on failure.
* @return False on error, true otherwise. * @return Success or error details.
*/ */
virtual bool postEvent( virtual std::error_condition postEvent(
std::shared_ptr<const RsEvent> event, std::shared_ptr<const RsEvent> event ) = 0;
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
) = 0;
/** /**
* @brief Send event directly to handlers. Blocking API * @brief Send event directly to handlers. Blocking API
@ -157,12 +208,10 @@ public:
* @param[in] event * @param[in] event
* @param[out] errorMessage Optional storage for error messsage, meaningful * @param[out] errorMessage Optional storage for error messsage, meaningful
* only on failure. * only on failure.
* @return False on error, true otherwise. * @return Success or error details.
*/ */
virtual bool sendEvent( virtual std::error_condition sendEvent(
std::shared_ptr<const RsEvent> event, std::shared_ptr<const RsEvent> event ) = 0;
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
) = 0;
/** /**
* @brief Generate unique handler identifier * @brief Generate unique handler identifier
@ -187,9 +236,9 @@ public:
* @param[in] eventType Optional type of event for which the callback is * @param[in] eventType Optional type of event for which the callback is
* called, if __NONE is passed multiCallback is * called, if __NONE is passed multiCallback is
* called for every events without filtering. * called for every events without filtering.
* @return False on error, true otherwise. * @return Success or error details.
*/ */
virtual bool registerEventsHandler( virtual std::error_condition registerEventsHandler(
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback, std::function<void(std::shared_ptr<const RsEvent>)> multiCallback,
RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0), RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0),
RsEventType eventType = RsEventType::__NONE ) = 0; RsEventType eventType = RsEventType::__NONE ) = 0;
@ -197,9 +246,10 @@ public:
/** /**
* @brief Unregister event handler * @brief Unregister event handler
* @param[in] hId Id of the event handler to unregister * @param[in] hId Id of the event handler to unregister
* @return True if the handler id has been found, false otherwise. * @return Success or error details.
*/ */
virtual bool unregisterEventsHandler(RsEventsHandlerId_t hId) = 0; virtual std::error_condition unregisterEventsHandler(
RsEventsHandlerId_t hId ) = 0;
virtual ~RsEvents(); virtual ~RsEvents();
}; };

View File

@ -3,7 +3,9 @@
* * * *
* libretroshare: retroshare core library * * libretroshare: retroshare core library *
* * * *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@eigenlab.org> * * Copyright (C) 2019-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2019-2020 Retroshare Team <contact@retroshare.cc> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as * * it under the terms of the GNU Lesser General Public License as *
@ -27,64 +29,62 @@
/*extern*/ RsEvents* rsEvents = nullptr; /*extern*/ RsEvents* rsEvents = nullptr;
RsEvent::~RsEvent() {};
RsEvents::~RsEvents() {};
bool isEventValid( RsEvent::~RsEvent() = default;
std::shared_ptr<const RsEvent> event, std::string& errorMessage ) RsEvents::~RsEvents() = default;
/*static*/ const RsEventsErrorCategory RsEventsErrorCategory::instance;
std::error_condition RsEventsErrorCategory::default_error_condition(int ev)
const noexcept
{ {
if(!event) switch(static_cast<RsEventsErrorNum>(ev))
{ {
errorMessage = "Event is null!"; case RsEventsErrorNum::INVALID_HANDLER_ID: // [[fallthrough]];
return false; case RsEventsErrorNum::NULL_EVENT_POINTER: // [[fallthrough]];
case RsEventsErrorNum::EVENT_TYPE_UNDEFINED: // [[fallthrough]];
case RsEventsErrorNum::EVENT_TYPE_OUT_OF_RANGE:
return std::errc::invalid_argument;
default:
return std::error_condition(ev, *this);
} }
if(event->mType <= RsEventType::__NONE)
{
errorMessage = "Event has type NONE: " +
std::to_string(
static_cast<std::underlying_type<RsEventType>::type >(
event->mType ) );
return false;
}
if(event->mType >= RsEventType::__MAX)
{
errorMessage = "Event has type >= RsEventType::__MAX: " +
std::to_string(
static_cast<std::underlying_type<RsEventType>::type >(
event->mType ) );
}
return true;
} }
bool RsEventsService::postEvent( std::shared_ptr<const RsEvent> event, std::error_condition RsEventsService::isEventTypeInvalid(RsEventType eventType)
std::string& errorMessage )
{ {
if(!isEventValid(event, errorMessage)) if(eventType == RsEventType::__NONE)
{ return RsEventsErrorNum::EVENT_TYPE_UNDEFINED;
std::cerr << __PRETTY_FUNCTION__ << " Error: "<< errorMessage
<< std::endl; if( eventType < RsEventType::__NONE ||
return false; eventType >= static_cast<RsEventType>(mHandlerMaps.size()) )
} return RsEventsErrorNum::EVENT_TYPE_OUT_OF_RANGE;
return std::error_condition();
}
std::error_condition RsEventsService::isEventInvalid(
std::shared_ptr<const RsEvent> event)
{
if(!event) return RsEventsErrorNum::NULL_EVENT_POINTER;
return isEventTypeInvalid(event->mType);
}
std::error_condition RsEventsService::postEvent(
std::shared_ptr<const RsEvent> event )
{
if(std::error_condition ec = isEventInvalid(event)) return ec;
RS_STACK_MUTEX(mEventQueueMtx); RS_STACK_MUTEX(mEventQueueMtx);
mEventQueue.push_back(event); mEventQueue.push_back(event);
return true; return std::error_condition();
} }
bool RsEventsService::sendEvent( std::shared_ptr<const RsEvent> event, std::error_condition RsEventsService::sendEvent(
std::string& errorMessage ) std::shared_ptr<const RsEvent> event )
{ {
if(!isEventValid(event, errorMessage)) if(std::error_condition ec = isEventInvalid(event)) return ec;
{
RsErr() << __PRETTY_FUNCTION__ << " "<< errorMessage << std::endl;
return false;
}
handleEvent(event); handleEvent(event);
return true; return std::error_condition();
} }
RsEventsHandlerId_t RsEventsService::generateUniqueHandlerId() RsEventsHandlerId_t RsEventsService::generateUniqueHandlerId()
@ -99,35 +99,29 @@ RsEventsHandlerId_t RsEventsService::generateUniqueHandlerId_unlocked()
return 1; return 1;
} }
bool RsEventsService::registerEventsHandler( std::error_condition RsEventsService::registerEventsHandler(
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback, std::function<void(std::shared_ptr<const RsEvent>)> multiCallback,
RsEventsHandlerId_t& hId, RsEventType eventType ) RsEventsHandlerId_t& hId, RsEventType eventType )
{ {
RS_STACK_MUTEX(mHandlerMapMtx); RS_STACK_MUTEX(mHandlerMapMtx);
if( eventType >= RsEventType::__MAX) if(eventType != RsEventType::__NONE)
{ if(std::error_condition ec = isEventTypeInvalid(eventType))
RsErr() << __PRETTY_FUNCTION__ << " Invalid event type: " return ec;
<< static_cast<uint32_t>(eventType) << " >= RsEventType::__MAX:"
<< static_cast<uint32_t>(RsEventType::__MAX) << std::endl;
print_stacktrace();
return false;
}
if(!hId) hId = generateUniqueHandlerId_unlocked(); if(!hId) hId = generateUniqueHandlerId_unlocked();
else if (hId > mLastHandlerId) else if (hId > mLastHandlerId)
{ {
RsErr() << __PRETTY_FUNCTION__ << " Invalid handler id: " << hId
<< " how did you generate it? " << std::endl;
print_stacktrace(); print_stacktrace();
return false; return RsEventsErrorNum::INVALID_HANDLER_ID;
} }
mHandlerMaps[static_cast<std::size_t>(eventType)][hId] = multiCallback; mHandlerMaps[static_cast<std::size_t>(eventType)][hId] = multiCallback;
return true; return std::error_condition();
} }
bool RsEventsService::unregisterEventsHandler(RsEventsHandlerId_t hId) std::error_condition RsEventsService::unregisterEventsHandler(
RsEventsHandlerId_t hId )
{ {
RS_STACK_MUTEX(mHandlerMapMtx); RS_STACK_MUTEX(mHandlerMapMtx);
@ -137,10 +131,10 @@ bool RsEventsService::unregisterEventsHandler(RsEventsHandlerId_t hId)
if(it != mHandlerMaps[i].end()) if(it != mHandlerMaps[i].end())
{ {
mHandlerMaps[i].erase(it); mHandlerMaps[i].erase(it);
return true; return std::error_condition();
} }
} }
return false; return RsEventsErrorNum::INVALID_HANDLER_ID;
} }
void RsEventsService::threadTick() void RsEventsService::threadTick()
@ -179,17 +173,13 @@ dispatchEventFromQueueLock:
void RsEventsService::handleEvent(std::shared_ptr<const RsEvent> event) void RsEventsService::handleEvent(std::shared_ptr<const RsEvent> event)
{ {
uint32_t event_type_index = static_cast<uint32_t>(event->mType); if(std::error_condition ec = isEventInvalid(event))
if(RsEventType::__NONE >= event->mType || event->mType >= RsEventType::__MAX )
{ {
RsErr() << __PRETTY_FUNCTION__ << " Invalid event type: " RsErr() << __PRETTY_FUNCTION__ << " " << ec << std::endl;
<< event_type_index << std::endl;
print_stacktrace(); print_stacktrace();
return; return;
} }
{
RS_STACK_MUTEX(mHandlerMapMtx); RS_STACK_MUTEX(mHandlerMapMtx);
/* It is important to also call the callback under mutex protection to /* It is important to also call the callback under mutex protection to
* ensure they are not unregistered in the meanwhile. * ensure they are not unregistered in the meanwhile.
@ -197,11 +187,11 @@ void RsEventsService::handleEvent(std::shared_ptr<const RsEvent> event)
* deadlock */ * deadlock */
// Call all clients that registered a callback for this event type // Call all clients that registered a callback for this event type
for(auto cbit: mHandlerMaps[event_type_index]) cbit.second(event); for(auto cbit: mHandlerMaps[static_cast<uint32_t>(event->mType)])
cbit.second(event);
/* Also call all clients that registered with NONE, meaning that they /* Also call all clients that registered with NONE, meaning that they
* expect all events */ * expect all events */
for(auto cbit: mHandlerMaps[static_cast<uint32_t>(RsEventType::__NONE)]) for(auto cbit: mHandlerMaps[static_cast<uint32_t>(RsEventType::__NONE)])
cbit.second(event); cbit.second(event);
}
} }

View File

@ -40,38 +40,40 @@ public:
mEventQueueMtx("RsEventsService::mEventQueueMtx") {} mEventQueueMtx("RsEventsService::mEventQueueMtx") {}
/// @see RsEvents /// @see RsEvents
bool postEvent( std::error_condition postEvent(
std::shared_ptr<const RsEvent> event, std::shared_ptr<const RsEvent> event ) override;
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
) override;
/// @see RsEvents /// @see RsEvents
bool sendEvent( std::error_condition sendEvent(
std::shared_ptr<const RsEvent> event, std::shared_ptr<const RsEvent> event ) override;
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
) override;
/// @see RsEvents /// @see RsEvents
RsEventsHandlerId_t generateUniqueHandlerId() override; RsEventsHandlerId_t generateUniqueHandlerId() override;
/// @see RsEvents /// @see RsEvents
bool registerEventsHandler( std::error_condition registerEventsHandler(
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback, std::function<void(std::shared_ptr<const RsEvent>)> multiCallback,
RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0), RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0),
RsEventType eventType = RsEventType::__NONE ) override; RsEventType eventType = RsEventType::__NONE ) override;
/// @see RsEvents /// @see RsEvents
bool unregisterEventsHandler(RsEventsHandlerId_t hId) override; std::error_condition unregisterEventsHandler(
RsEventsHandlerId_t hId ) override;
protected: protected:
std::error_condition isEventTypeInvalid(RsEventType eventType);
std::error_condition isEventInvalid(std::shared_ptr<const RsEvent> event);
RsMutex mHandlerMapMtx; RsMutex mHandlerMapMtx;
RsEventsHandlerId_t mLastHandlerId; RsEventsHandlerId_t mLastHandlerId;
/** Storage for event handlers, keep 10 extra types for plugins that might
* be released indipendently */
std::array< std::array<
std::map< std::map<
RsEventsHandlerId_t, RsEventsHandlerId_t,
std::function<void(std::shared_ptr<const RsEvent>)> >, std::function<void(std::shared_ptr<const RsEvent>)> >,
static_cast<std::size_t>(RsEventType::__MAX) static_cast<std::size_t>(RsEventType::__MAX) + 10
> mHandlerMaps; > mHandlerMaps;
RsMutex mEventQueueMtx; RsMutex mEventQueueMtx;