#include <so_5/all.hpp>
enum class field_id_t
{
author,
title,
summary
};
struct book_description_t
{
std::string m_author;
std::string m_title;
std::string m_summary;
};
template<field_id_t Field>
std::string get(const book_description_t &);
template<>
std::string get<field_id_t::author>(const book_description_t & b)
{
return b.m_author;
}
template<>
std::string get<field_id_t::title>(const book_description_t & b)
{
return b.m_title;
}
template<>
std::string get<field_id_t::summary>(const book_description_t & b)
{
return b.m_summary;
}
struct store_book_t : public so_5::message_t
{
const int m_key;
const book_description_t m_book;
const so_5::mbox_t m_ack_to;
store_book_t(int key, book_description_t book, so_5::mbox_t ack_to)
: m_key(key), m_book(
std::move(book)), m_ack_to(
std::move(ack_to))
{}
};
struct store_book_ack_t : public so_5::message_t
{
const int m_key;
store_book_ack_t(int key)
: m_key(key)
{}
};
struct request_data_t : public so_5::message_t
{
const int m_key;
const so_5::mbox_t m_reply_to;
request_data_t(int key, so_5::mbox_t reply_to)
: m_key(key), m_reply_to(
std::move(reply_to))
{}
};
struct data_t : public so_5::message_t
{
const int m_key;
const field_id_t m_field;
const std::string m_data;
data_t(int key, field_id_t field, std::string data)
: m_key(key), m_field(field), m_data(
std::move(data))
{}
};
template<field_id_t Field>
class shard_t final : public so_5::agent_t
{
public:
shard_t(context_t ctx, so_5::mbox_t command_mbox)
{
so_subscribe(command_mbox)
.event(&shard_t::on_store_book)
.event(&shard_t::on_request_data);
}
private:
using map_t = std::map<int, std::string>;
map_t m_data;
void on_store_book(mhood_t<store_book_t> cmd)
{
m_data[cmd->m_key] = get<Field>(cmd->m_book);
so_5::send<store_book_ack_t>(cmd->m_ack_to, cmd->m_key);
}
void on_request_data(mhood_t<request_data_t> cmd)
{
so_5::send<data_t>(cmd->m_reply_to, cmd->m_key, Field, m_data[cmd->m_key]);
}
};
class sample_performer_t final : public so_5::agent_t
{
static constexpr std::size_t total_books = 3;
public:
sample_performer_t(context_t ctx, so_5::mbox_t command_mbox)
, m_command_mbox(
std::move(command_mbox))
{
so_subscribe_self()
.event(&sample_performer_t::on_store_ack)
.event(&sample_performer_t::on_data);
}
virtual void so_evt_start() override
{
std::array<book_description_t, total_books> books{{
{ "Miguel De Cervantes", "Don Quixote",
"The story of the gentle knight and his servant Sancho Panza has "
"entranced readers for centuries. " },
{ "Jonathan Swift", "Gulliver's Travels",
"A wonderful satire that still works for all ages, despite the "
"savagery of Swift's vision." },
{ "Stendhal", "The Charterhouse of Parma",
"Penetrating and compelling chronicle of life in an Italian "
"court in post-Napoleonic France." }
}};
int key = 0;
for( const auto & b : books )
{
so_5::send<store_book_t>(m_command_mbox,
key,
b,
++key;
}
}
private:
store_book_ack_t,
data_t,
const so_5::mbox_t m_command_mbox;
std::size_t m_books_received = 0;
void on_store_ack(mhood_t<store_ack_mbox_t::messages_collected_t> cmd)
{
const auto key = cmd->with_nth(0, [](auto m) { return m->m_key; });
std::cout << "Book with key=" << key << " is stored" << std::endl;
so_5::send<request_data_t>(m_command_mbox,
key,
}
void on_data(mhood_t<data_mbox_t::messages_collected_t> cmd)
{
const auto key = cmd->with_nth(0, [](auto m) { return m->m_key; });
book_description_t book;
cmd->for_each([&book](auto m) {
if(field_id_t::author == m->m_field)
book.m_author = m->m_data;
else if(field_id_t::title == m->m_field)
book.m_title = m->m_data;
else if(field_id_t::summary == m->m_field)
book.m_summary = m->m_data;
});
std::cout << "Book with key=" << key << " is {"
<< book.m_author << ", '" << book.m_title << "', "
<< book.m_summary << "}" << std::endl;
++m_books_received;
if(total_books == m_books_received)
so_deregister_agent_coop_normally();
}
};
void init(so_5::environment_t & env)
{
env.introduce_coop([&](so_5::coop_t & coop) {
auto command_mbox = env.create_mbox();
coop.make_agent_with_binder<shard_t<field_id_t::author>>(
disp.binder(),
command_mbox);
coop.make_agent_with_binder<shard_t<field_id_t::title>>(
disp.binder(),
command_mbox);
coop.make_agent_with_binder<shard_t<field_id_t::summary>>(
disp.binder(),
command_mbox);
coop.make_agent<sample_performer_t>(command_mbox);
});
}
int main()
{
try
{
so_5::launch( &init );
}
catch(const std::exception & x)
{
std::cerr << "Exception caught: " << x.what() << std::endl;
}
}