#include <chrono>
#include <cstdlib>
#include <ctime>
#include <deque>
#include <iostream>
#include <sstream>
#include <string>
#include <random>
using namespace std::chrono_literals;
struct request_base
{
int m_id;
request_base( int id ) : m_id{ id } {}
};
struct req_A final : request_base {};
struct req_B final : request_base {};
struct req_C final : request_base {};
struct req_D final : request_base {};
struct req_E final : request_base {};
struct req_F final : request_base {};
struct req_G final : request_base {};
struct req_I final : request_base {};
struct log_message
{
std::string m_what;
};
{
public :
a_logger_t( context_t ctx )
+ limit_then_abort< log_message >( 100 ) )
, m_started_at( std::chrono::steady_clock::now() )
{}
void so_define_agent() override
{
so_default_state().event(
[this]( const log_message & evt ) {
std::cout << "[+" << time_delta()
<< "] -- " << evt.m_what << std::endl;
} );
}
private :
const std::chrono::steady_clock::time_point m_started_at;
std::string time_delta() const
{
auto now = std::chrono::steady_clock::now();
std::ostringstream ss;
ss << double(
std::chrono::duration_cast< std::chrono::milliseconds >(
now - m_started_at ).count()
) / 1000.0 << "ms";
return ss.str();
}
};
{
template< typename Request >
[[nodiscard]]
auto
make_event_handler( std::string name )
{
return [this, req_name=std::move(name)]( mhood_t<Request> cmd ) {
so_5::send< log_message >( m_logger,
req_name + ": redirected to trash can, id=" +
std::to_string(cmd->m_id) );
};
}
public :
a_trash_can_t(
context_t ctx,
+ limit_then_drop< any_unspecified_message >( 10u )
}
, m_logger{ std::move(logger) }
{}
void so_define_agent() override
{
so_default_state()
.event( make_event_handler< req_A >( "req_A" ) )
.event( make_event_handler< req_B >( "req_B" ) )
.event( make_event_handler< req_C >( "req_C" ) )
.event( make_event_handler< req_D >( "req_D" ) )
.event( make_event_handler< req_E >( "req_E" ) )
.event( make_event_handler< req_F >( "req_F" ) )
.event( make_event_handler< req_G >( "req_G" ) )
.event( make_event_handler< req_I >( "req_I" ) )
;
}
};
{
template< typename Request >
[[nodiscard]]
auto make_request_handler(
std::string name,
std::chrono::milliseconds duration )
{
return [this, req_name=std::move(name), duration]
( mhood_t< Request > cmd )
{
so_5::send< log_message >( m_logger,
"processing request " + req_name + " (" +
std::to_string( cmd->m_id ) + ") for " +
std::to_string( duration.count() ) + "ms" );
std::this_thread::sleep_for(
std::chrono::milliseconds( duration ) );
};
}
public :
a_processor_t(
context_t ctx,
+ limit_then_redirect< req_A >( 10u, trash_can )
+ limit_then_redirect< req_C >( 8u, trash_can )
+ limit_then_abort< shutdown >( 1u )
+ limit_then_redirect< any_unspecified_message >( 4u, trash_can )
}
, m_logger( std::move( logger ) )
{}
void so_define_agent() override
{
so_default_state()
.event( make_request_handler< req_A >( "req_A", 1ms ) )
.event( make_request_handler< req_B >( "req_B", 15ms ) )
.event( make_request_handler< req_C >( "req_C", 2ms ) )
.event( make_request_handler< req_D >( "req_D", 18ms ) )
.event( make_request_handler< req_E >( "req_E", 22ms ) )
.event( make_request_handler< req_F >( "req_F", 19ms ) )
.event( make_request_handler< req_G >( "req_G", 24ms ) )
.event( make_request_handler< req_I >( "req_I", 23ms ) )
.event( [this]( mhood_t< shutdown > ) {
so_deregister_agent_coop_normally();
} )
;
}
};
using sender_t = void(*)(
const so_5::mbox_t & to,
int id );
template< typename Request >
[[nodiscard]]
sender_t make_sender()
{
so_5::send< Request >( to, id );
};
}
{
logger->so_direct_mbox() );
logger->so_direct_mbox(),
trash_can->so_direct_mbox() );
return processor->so_direct_mbox();
});
std::array< sender_t, 10 > senders{
make_sender< req_A >(),
make_sender< req_B >(),
make_sender< req_C >(),
make_sender< req_D >(),
make_sender< req_E >(),
make_sender< req_F >(),
make_sender< req_G >(),
make_sender< req_I >(),
make_sender< req_A >(),
make_sender< req_E >()
};
{
std::random_device rd;
std::mt19937 generator{ rd() };
std::shuffle( std::begin(senders), std::end(senders), generator );
}
int id = 0;
for( int i = 0; i < 15; ++i )
{
for( const auto & s : senders )
s( processor_mbox, id++ );
std::this_thread::sleep_for( 13ms );
}
so_5::send< a_processor_t::shutdown >( processor_mbox );
}
int main()
{
try
{
}
catch( const std::exception & ex )
{
std::cerr << "Error: " << ex.what() << std::endl;
return 1;
}
return 0;
}