Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

polish chat_client and group_server up

  • Loading branch information...
commit d5ec1025872d362b43f86d46a743110e1dd37913 1 parent a5c9897
@Neverlord Neverlord authored
View
1  cppa.files
@@ -272,3 +272,4 @@ examples/group_chat.cpp
cppa/opt.hpp
src/opt.cpp
cppa/detail/opt_impls.hpp
+examples/type_plugins.hpp
View
241 examples/group_chat.cpp
@@ -1,54 +1,54 @@
#include <set>
#include <map>
#include <vector>
+#include <dlfcn.h>
#include <iostream>
#include <sstream>
#include <time.h>
#include <cstdlib>
+#include "cppa/opt.hpp"
#include "cppa/cppa.hpp"
+#include "type_plugins.hpp"
using namespace std;
using namespace cppa;
+using namespace cppa::placeholders;
-auto on_opt(char short_opt, const char* long_opt) -> decltype(on("", val<string>) || on(function<option<string> (const string&)>())) {
- const char short_flag_arr[] = {'-', short_opt, '\0' };
- const char* lhs_str = short_flag_arr;
- string prefix = "--";
- prefix += long_opt;
- prefix += "=";
- function<option<string> (const string&)> kvp = [prefix](const string& input) -> option<string> {
- if ( input.compare(0, prefix.size(), prefix) == 0
- // accept '-key=' as well
- || input.compare(1, prefix.size(), prefix) == 0) {
- return input.substr(prefix.size());
- }
- return {};
- };
- return on(lhs_str, val<string>) || on(kvp);
+struct line { string str; };
+
+istream& operator>>(istream& is, line& l) {
+ getline(is, l.str);
+ return is;
}
-auto on_void_opt(char short_opt, const char* long_opt) -> decltype(on<string>().when(cppa::placeholders::_x1.in(vector<string>()))) {
- const char short_flag_arr[] = {'-', short_opt, '\0' };
- vector<string> opt_strs = { short_flag_arr };
- opt_strs.push_back(string("-") + long_opt);
- string str = "-";
- str += opt_strs.back();
- opt_strs.push_back(move(str));
- return on<string>().when(cppa::placeholders::_x1.in(opt_strs));
+any_tuple s_last_line;
+
+any_tuple split_line(const line& l) {
+ vector<string> result;
+ stringstream strs(l.str);
+ string tmp;
+ while (getline(strs, tmp, ' ')) {
+ if (!tmp.empty()) result.push_back(std::move(tmp));
+ }
+ s_last_line = any_tuple::view(std::move(result));
+ return s_last_line;
}
class client : public event_based_actor {
- string m_username;
- actor_ptr m_printer;
+ public:
+
+ client(const string& name, actor_ptr printer)
+ : m_name(name), m_printer(printer) { }
+
+ protected:
void init() {
become (
- // local commands
on(atom("broadcast"), arg_match) >> [=](const string& message) {
for(auto& dest : joined_groups()) {
- send(dest, m_username + ": " + message);
+ send(dest, m_name + ": " + message);
}
},
on(atom("join"), arg_match) >> [=](const group_ptr& what) {
@@ -62,6 +62,7 @@ class client : public event_based_actor {
}
},
on(atom("quit")) >> [=] {
+ // ignore quit messages from remote actors
auto s = self->last_sender();
if (s->is_proxy()) {
reply("nice try");
@@ -75,14 +76,16 @@ class client : public event_based_actor {
if (last_sender() != this) forward_to(m_printer);
},
others() >> [=]() {
- send(m_printer, string("[!!!] unexpected message: '") + to_string(last_dequeued()));
+ send(m_printer,
+ "*** unexpected message: '" + to_string(last_dequeued()));
}
);
}
- public:
+ private:
- client(const string& username, actor_ptr printer) : m_username(username), m_printer(printer) { }
+ string m_name;
+ actor_ptr m_printer;
};
@@ -93,141 +96,93 @@ class print_actor : public event_based_actor {
self->quit();
},
on_arg_match >> [](const string& str) {
- cout << (str + "\n");
+ cout << str << endl;
}
);
}
};
-inline vector<string> split(const string& str, char delim) {
- vector<string> result;
- stringstream strs{str};
- string tmp;
- while (getline(strs, tmp, delim)) result.push_back(tmp);
- return result;
-}
-
-template<typename Iterator>
-inline string join(Iterator first, Iterator last, char delim) {
- string result;
- if (first != last) {
- result += *first++;
- for (; first != last; ++first) {
- result += delim;
- result += *first++;
- }
- }
- return result;
-}
-
-inline string join(const vector<string>& vec, char delim) {
- return join(begin(vec), end(vec), delim);
-}
-
-template<typename T>
-auto conv(const string& str) -> option<T> {
- T result;
- if (istringstream(str) >> result) return result;
- return {};
-}
-
-void print_usage(actor_ptr printer) {
- send(printer, "Usage: group_chat --type=<server|client>\n --type, -t\t\tcan be: server, s, client, c\n --name, -n\t\tusername (only needed for client)\n --host, -h\t\thostname (only needed for client)\n --port, -p\t\tport for server/client");
-}
-
-function<option<string> (const string&)> get_extractor(const string& identifier) {
- auto tmp = [&](const string& kvp) -> option<string> {
- auto vec = split(kvp, '=');
- if (vec.size() == 2) {
- if (vec.front() == "--"+identifier) {
- return vec.back();
- }
- }
- return {};
- };
- return tmp;
-}
-
-
auto main(int argc, char* argv[]) -> int {
- cout.unsetf(ios_base::unitbuf);
-
- auto printer = spawn<print_actor>();
+ // enables this client to print user-defined types
+ // without changing this source code
+ exec_plugin();
string name;
-
- bool args_valid = match_stream<string>(argv + 1, argv + argc) (
- on_opt('n', "name") >> [&](const string& input) -> bool {
- if (!name.empty()) {
- cout << "name already set to " << name << endl;
- return false;
- }
- name = input;
- return true;
- }
+ vector<string> group_ids;
+ options_description desc;
+ bool args_valid = argc > 1 && match_stream<string>(argv + 1, argv + argc) (
+ on_opt('n', "name", &desc, "set name") >> rd_arg(name),
+ on_opt('g', "group", &desc, "join group <arg>") >> add_arg(group_ids),
+ on_vopt('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
);
- if(!args_valid) {
- print_usage(printer);
- send(printer, atom("quit"));
- await_all_others_done();
- shutdown();
- return 0;
- }
+ if(!args_valid) print_desc_and_exit(&desc)();
+
+ auto printer = spawn<print_actor>();
while (name.empty()) {
- send(printer, "So what is your name for chatting?");
+ send(printer, "*** what is your name for chatting?");
if (!getline(cin, name)) return 1;
}
- send(printer, "Starting client.");
+ send(printer, "*** starting client.");
auto client_actor = spawn<client>(name, printer);
- auto get_command = [&]() -> bool {
- string input;
- bool done = false;
- getline(cin, input);
- if (input.size() > 0) {
- if (input.front() == '/') {
- input.erase(input.begin());
- vector<string> values = split(input, ' ');
- match (values) (
- on("send", val<string>, any_vals) >> [&](const string& groupname) {
- if (values.size() < 3) {
- send(printer, "no message to send");
- }
- else {
- send(client_actor, atom("send"), groupname, join(begin(values) + 2, end(values), ' '));
- }
- },
- on("join", arg_match) >> [&](const string& mod, const string& id) {
- group_ptr g;
- try {
- g = group::get(mod, id);
- send(client_actor, atom("join"), g);
- }
- catch (exception& e) {
- send(printer, string("exception: ") + e.what());
- }
- },
- on("quit") >> [&] {
- done = true;
- },
- others() >> [&] {
- send(printer, "available commands:\n /connect HOST PORT\n /join GROUPNAME\n /join hamcast URI\n /send GROUPNAME MESSAGE\n /quit");
- }
- );
+ // evaluate group parameters
+ for (auto& gid : group_ids) {
+ auto p = gid.find(':');
+ if (p == std::string::npos) {
+ cerr << "*** error parsing argument " << gid
+ << ", expected format: <module_name>:<group_id>";
+ }
+ else {
+ try {
+ auto g = group::get(gid.substr(0, p),
+ gid.substr(p + 1));
+ send(client_actor, atom("join"), g);
}
- else {
- send(client_actor, atom("broadcast"), input);
+ catch (exception& e) {
+ ostringstream err;
+ err << "*** exception: group::get(\"" << gid.substr(0, p)
+ << "\", \"" << gid.substr(p + 1) << "\") failed, what = "
+ << e.what() << endl;
+ send(printer, err.str());
}
}
- return !done;
- };
- while (get_command()) { }
- send(client_actor, atom("quit"));
+ }
+ istream_iterator<line> lines(cin);
+ istream_iterator<line> eof;
+ match_each(lines, eof, split_line) (
+ on("/join", arg_match) >> [&](const string& mod, const string& id) {
+ try {
+ send(client_actor, atom("join"), group::get(mod, id));
+ }
+ catch (exception& e) {
+ send(printer, string("*** exception: ") + e.what());
+ }
+ },
+ on("/quit") >> [&] {
+ close(0); // close STDIN
+ },
+ on<string, anything>().when(_x1.starts_with("/")) >> [&] {
+ send(printer, "*** available commands:\n "
+ "/join MODULE GROUP\n "
+ "/quit");
+ },
+ others() >> [&] {
+ if (s_last_line.size() > 0) {
+ string msg = s_last_line.get_as<string>(0);
+ for (size_t i = 1; i < s_last_line.size(); ++i) {
+ msg += " ";
+ msg += s_last_line.get_as<string>(i);
+ }
+ send(client_actor, atom("broadcast"), msg);
+ }
+ }
+ );
+ send(client_actor, atom("quit"));
send(printer, atom("quit"));
await_all_others_done();
shutdown();
View
38 examples/group_server.cpp
@@ -5,39 +5,20 @@
#include "cppa/opt.hpp"
#include "cppa/cppa.hpp"
+#include "type_plugins.hpp"
using namespace std;
using namespace cppa;
int main(int argc, char** argv) {
-
- // user-defined types can be announced by a plugin
- void* handle = dlopen("plugin.dylib", RTLD_NOW); // macos
- if (!handle) handle = dlopen("plugin.so", RTLD_NOW); // linux
- if (handle) {
- auto before = uniform_type_info::instances();
- cout << "found a plugin, call exec_plugin()" << endl;
- auto fun = (void (*)()) dlsym(handle, "exec_plugin");
- if (fun) {
- fun();
- cout << "the plugin announced the following types:" << endl;
- for (auto inf : uniform_type_info::instances()) {
- if (count(begin(before), end(before), inf) == 0) {
- cout << inf->name() << endl;
- }
- }
- }
- }
-
+ // enables this server to be used with user-defined types
+ // without changing this source code
+ exec_plugin();
uint16_t port = 0;
+ options_description desc;
bool args_valid = argc > 1 && match_stream<string>(argv + 1, argv + argc) (
- on_opt('p', "port") >> [&](const string& arg) -> bool {
- if (!(istringstream(arg) >> port)) {
- cout << "\"" << arg << "\" is not a valid port" << endl;
- return false;
- }
- return true;
- }
+ on_opt('p', "port", &desc, "set port") >> rd_arg(port),
+ on_vopt('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
);
if (port <= 1024) {
cout << "no port > 1024 given" << endl;
@@ -49,9 +30,8 @@ int main(int argc, char** argv) {
string line;
while (getline(cin, line)) {
if (line == "quit") return 0;
- else {
- cout << "illegal command" << endl;
- }
+ else cout << "illegal command" << endl;
}
+ shutdown();
return 0;
}
View
30 examples/type_plugins.hpp
@@ -0,0 +1,30 @@
+#ifndef TYPE_PLUGINS_HPP
+#define TYPE_PLUGINS_HPP
+
+#include <dlfcn.h>
+#include <iostream>
+#include "cppa/cppa.hpp"
+
+inline void exec_plugin() {
+ using namespace std;
+ using namespace cppa;
+ // user-defined types can be announced by a plugin
+ void* handle = dlopen("plugin.dylib", RTLD_NOW); // macos
+ if (!handle) handle = dlopen("plugin.so", RTLD_NOW); // linux
+ if (handle) {
+ auto before = uniform_type_info::instances();
+ cout << "found a plugin, call exec_plugin()" << endl;
+ auto fun = (void (*)()) dlsym(handle, "exec_plugin");
+ if (fun) {
+ fun();
+ cout << "the plugin announced the following types:" << endl;
+ for (auto inf : uniform_type_info::instances()) {
+ if (count(begin(before), end(before), inf) == 0) {
+ cout << inf->name() << endl;
+ }
+ }
+ }
+ }
+}
+
+#endif // TYPE_PLUGINS_HPP
Please sign in to comment.
Something went wrong with that request. Please try again.