This example shows how to distribute an application across a network.
pong.hpp (identical to the pong.hpp from the pong.cpp example!)
// acedia includes #include "acedia/actor.hpp" #include "acedia/invoker.hpp" // other includes #include <iostream> #include <boost/cstdint.hpp> typedef boost::int32_t i32; // the ball that's sended between Ping and Pong ACEDIA_DECLARE_CASE_TUPLE1((GameBall), hits, i32) class Ping : public acedia::Actor { void returnPass(i32 hits) { // lastReceivedMessage() returns the current processed // message in 'original' form which then is converted to // a string and printed to stdout std::cout << "Ping: " << lastReceivedMessage().toString().const_str() << std::endl; // inrement the hit counter and pass the ball back to Pong reply(GameBall(hits+1)); } public: // this is the only method you must override in your own actor class virtual void act() { using acedia::on; acedia::Invoker i; // Step by step: // on<GameBall>() => declares a pattern that matches instances // of GameBall // .unbox() => unboxing a tuple means: throw away the tuple // and handle the elements; in this case // all further operations see only a i32 // >> => if the left hand rule does match then invoke // the following callback // method(...) => declare a callback that invokes a member method i.add(on<GameBall>().unbox() >> method(&Ping::returnPass)); // call receiveAndInvoke until the actor dies for (;;) receiveAndInvoke(i); } }; class Pong : public acedia::Actor { acedia::ActorRef ping; void returnPass(i32 hits) { std::cout << "Pong: " << lastReceivedMessage().toString().const_str() << std::endl; reply(GameBall(hits+1)); } void die() { // do exit with a non-normal reason // a non-normal exit reason will cause all links to exit too // in this case Ping will die because it's linked with Pong and Pong // dies with USER_DEFINED_REASON (and not with NORMAL_EXIT) doExit(acedia::exit_reasons::USER_DEFINED_REASON); } public: Pong(acedia::ActorRef myPing) : ping(myPing) { } virtual void act() { using acedia::on; using acedia::isGt; // kickoff send(ping, GameBall(0)); acedia::Invoker i; i // on a GameBall message unbox it and check the guard isGt(9) // which returns true if GameBall::hits() > 9 .add(on<GameBall>().unbox().guard(isGt((i32) 9)) // invoke Pong::die if the patter does match // note that die does not take any arguments but is a valid // invoke target because you can ignore any number of // message elements // // e.g.: // you receive a message <int, string, float, double> // valid callback signatures are: // (int, string, float, double) // (string, float, double) // (float, double) // (double) // () >> method(&Pong::die)) // the second rule is only checked if the first rule did not match .add(on<GameBall>().unbox() >> method(&Pong::returnPass)) ; for (;;) receiveAndInvoke(i); } };
#include "pong.hpp" #include "acedia/acedia_network.hpp" // implementation of the client side void client(const char *host, boost::uint16_t port) { using namespace acedia; using std::cout; using std::endl; std::pair<ActorRef, ConnectionError> res = remoteActor(host, port); if (res.first.isValid()) { ActorRef ping = res.first; link(spawn<Pong>(ping), ping); waitForAllActorsDone(); shutdown(); } else { std::cout << "Could not connect to remote actor: " << acedia::asString(res.second) << std::endl; } } // implementation of the server side void server(boost::uint16_t port) { acedia::ActorRef ping = acedia::spawn<Ping>(); acedia::PublishingResult res = acedia::publish(ping, port); if (!res.successful()) { std::cout << "Could not publish Ping at port " << port << ": " << res.errorAsString() << std::endl; acedia::shutdown(); return; } acedia::waitForAllActorsDone(); acedia::shutdown(); } // if you call this program with one argument then you start the server and // the argument must be the port // if you call this program with two arguments then you start the client // and the arguments are host and port int main(int argc, char **argv) { if (argc == 2) { server(atoi(argv[1])); } else if (argc == 3) { client(argv[1], atoi(argv[2])); } else { std::cout << "usage:" << std::endl << "server: " << argv[0] << " {host} {port}" << std::endl << "client: " << argv[0] << " {port}" << std::endl; } return 0; }