From 2b2cc872394f7ebf68cca146597cdc298e6e356e Mon Sep 17 00:00:00 2001 From: Joshua Moerman Date: Sat, 9 Mar 2013 21:50:49 +0100 Subject: [PATCH] Added json/fusion shit :D also moving people around --- json.h | 123 +++++++++++++++++++++++++++++++++++++++++++++++ main.cpp | 128 ++++++++++++++++++++++++++++++------------------- websockets.cpp | 1 - websockets.h | 7 ++- 4 files changed, 207 insertions(+), 52 deletions(-) create mode 100644 json.h diff --git a/json.h b/json.h new file mode 100644 index 0000000..fed608d --- /dev/null +++ b/json.h @@ -0,0 +1,123 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +#include + +namespace js = json_spirit; + +inline js::Value parse_json(std::string const & in){ + js::Value value; + js::read(in, value); + return value; +} + +inline std::string write_json(js::Value const & v){ + return js::write(v); +} + +/* + *** WRITING *** + Note: Does not yet support arrays, only basic types, std::strings and user defined types (with boost::fusion adaption) +*/ + +// Basic types +template +typename std::enable_if::value && !std::is_pointer::value, js::Value>::type to_json(T const & x){ + return x; +} + +inline js::Value to_json(std::string const & x){ + return x; +} + +// Compound types (need recursion) +template +typename std::enable_if::value, js::Value>::type to_json(T const & x); + +// boost::fusion magics +template +struct write_itr{ + typedef typename boost::mpl::next::type next_t; + typedef boost::fusion::extension::struct_member_name name_t; + + static inline void exec(js::Object & obj, const T& x){ + obj[name_t::call()] = to_json(boost::fusion::at(x)); + write_itr::exec(obj, x); + } +}; + +template +struct write_itr::type>{ + static inline void exec(js::Object & obj, const T& x) {} +}; + +// Compound types (need recursion) +template +typename std::enable_if::value, js::Value>::type to_json(T const & x){ + js::Object obj; + write_itr>::exec(obj, x); + return obj; +} + + +/* + *** READING *** + Note: Does not yet support arrays, only basic types, std::strings and user defined types (with boost::fusion adaption) +*/ + +// Basic types +template +typename std::enable_if::value, T>::type from_json(js::Value const & x){ + return x.getInt64(); +} + +template +typename std::enable_if::value, T>::type from_json(js::Value const & x){ + return x.getReal(); +} + +template +typename std::enable_if::value, T>::type from_json(js::Value const & x){ + return x.getString(); +} + +// Compound types (need recursion) +template +typename std::enable_if::value && !std::is_same::value, T>::type from_json(js::Value const & x); + +// boost::fusion magics +template +struct read_itr{ + typedef typename boost::fusion::result_of::value_at::type current_t; + typedef typename boost::mpl::next::type next_t; + typedef boost::fusion::extension::struct_member_name name_t; + + static inline void exec(js::Object const & obj, T& x){ + try{ + boost::fusion::at(x) = from_json(obj.at(name_t::call())); + } catch(std::out_of_range& e) { + throw std::out_of_range(e.what() + std::string(": ") + name_t::call()); + } + read_itr::exec(obj, x); + } +}; + +template +struct read_itr::type>{ + static inline void exec(js::Object const & obj, T& x) {} +}; + +// Compound types (need recursion) +template +typename std::enable_if::value && !std::is_same::value, T>::type from_json(js::Value const & x){ + T ret; + read_itr>::exec(x.getObject(), ret); + return ret; +} diff --git a/main.cpp b/main.cpp index b7f7791..c83fa40 100644 --- a/main.cpp +++ b/main.cpp @@ -2,57 +2,92 @@ #include #include #include +#include +#include #include -#include +#include "json.h" #include "websockets.h" -namespace js = json_spirit; - -js::Object get_object(std::string const & in){ - js::Value value; - js::read(in, value); - return value.getObject(); +template +inline js::Value ptrvector_to_json(C const & container){ + js::Array array; + for(auto x : container){ + array.push_back(to_json(*x)); + } + return array; } +BOOST_FUSION_DEFINE_STRUCT( + , Size, + (int, width) + (int, height) +) + +BOOST_FUSION_DEFINE_STRUCT( + , Position, + (int, x) + (int, y) +) + +BOOST_FUSION_DEFINE_STRUCT( + , IncomingPacket, + (std::string, name) + (Size, size) +) + int uid = 0; struct User { unsigned int index{0}; - std::string name{"Guest"}; - - int width{0}; - int height{0}; - - static User from_json(const js::Object& obj){ - User ret; - #define in(x, f) ret.x = obj.at(#x).f() - in(name, getString); - in(width, getInt); - in(height, getInt); - #undef in - return ret; - } + std::string name{"Unknown guest"}; + + Size size{0,0}; + Position position{0,0}; + + User() + : index(uid++) + {} - js::Object to_json() const { - js::Object obj; - #define out(x) obj[#x] = x - out(name); - out(width); - out(height); - #undef out - return obj; + User& operator=(IncomingPacket const & p){ + name = p.name; + size = p.size; + return *this; } }; +BOOST_FUSION_ADAPT_STRUCT( + User, + (unsigned int, index) + (std::string, name) + (Size, size) + (Position, position) +) + // unfortunately libwebsockets owns the user thingy std::vector people_online; +inline void update_positions(){ + typedef std::chrono::duration> fseconds; + static auto start = std::chrono::steady_clock::now(); + auto end = std::chrono::steady_clock::now(); + double time = std::chrono::duration_cast(end-start).count(); + + //std::cout << time << std::endl; + auto n = people_online.size(); + for(int i = 0; i < n; ++i){ + User& user = *people_online[i]; + double x = cos(0.1 * time + 2*M_PI*i/double(n)); + double y = sin(0.1 * time + 2*M_PI*i/double(n)); + + user.position.x = 200 + 180*x; + user.position.y = 200 + 180*y; + } +} + websockets::TestProtocol default_protocol{ // connection established [](User& user){ - user.name = "Unknown guest"; - user.index = uid++; people_online.push_back(&user); }, // connection closed @@ -61,23 +96,20 @@ websockets::TestProtocol default_protocol{ }, // write (will always come after receive) [](User& user) -> std::string{ - std::string string_to_send = "Other People:"; - for(auto x : people_online) if(x != &user) string_to_send += " " + x->name; - return string_to_send; + update_positions(); + return write_json(ptrvector_to_json(people_online)); }, // receive [](User& user, std::string in){ try{ - user = User::from_json(get_object(in)); + user = from_json(parse_json(in)); } catch(std::exception& e) { throw websockets::runtime_error(e.what()); } } }; -struct Empty{ - int x; -}; +struct Empty{}; websockets::TestProtocol observer_protocol{ // connection established @@ -86,23 +118,19 @@ websockets::TestProtocol observer_protocol{ [](Empty& user){}, // write (will always come after receive) [](Empty& user) -> std::string{ - js::Array array; - for(auto x : people_online){ - array.push_back(x->to_json()); - } - js::Value value(array); - return write(value); + update_positions(); + return write_json(ptrvector_to_json(people_online)); }, // receive [](Empty& user, std::string in){} }; -static libwebsocket_protocols protocols[] = { - WSstandard_protocol("default", default_protocol), - WSstandard_protocol("observer", observer_protocol), - { NULL, NULL, 0 } // end of list -}; - int main(int argc, char **argv){ + libwebsocket_protocols protocols[] = { + WSstandard_protocol("default", default_protocol), + WSstandard_protocol("observer", observer_protocol), + { NULL, NULL, 0 } // end of list + }; + return websockets::default_main(argc, argv, protocols); } diff --git a/websockets.cpp b/websockets.cpp index 0429714..e06f6fa 100644 --- a/websockets.cpp +++ b/websockets.cpp @@ -42,7 +42,6 @@ namespace websockets { } websockets::Log log("lwsts", LOG_PID | LOG_PERROR, 7); - log.notice("Running in server mode\n"); lws_context_creation_info info; memset(&info, 0, sizeof info); diff --git a/websockets.h b/websockets.h index 98c0cbb..247eb55 100644 --- a/websockets.h +++ b/websockets.h @@ -1,4 +1,4 @@ - +#include #include #include #include @@ -100,6 +100,8 @@ namespace websockets { std::function write_func; std::function receive_func; + bool verbose{false}; + TestProtocol(decltype(establish_func) establish_func, decltype(close_func) close_func, decltype(write_func) write_func, decltype(receive_func) receive_func) : establish_func(establish_func) , close_func(close_func) @@ -112,15 +114,18 @@ namespace websockets { try{ switch (reason) { case LWS_CALLBACK_ESTABLISHED: + lwsl_notice("Connection established (%p, %p)\n", this, user_ptr); new (user_ptr) user_type(); establish_func(user); break; case LWS_CALLBACK_CLOSED: + lwsl_notice("Connection closed (%p, %p)\n", this, user_ptr); user.~user_type(); close_func(user); break; case LWS_CALLBACK_SERVER_WRITEABLE:{ std::string string_to_send = write_func(user); + if(verbose) std::cout << string_to_send << std::endl; // we need the extra bytes padding on both sides :( unsigned char * buf = new unsigned char [LWS_SEND_BUFFER_PRE_PADDING + string_to_send.size() + LWS_SEND_BUFFER_POST_PADDING]; memcpy(&buf[LWS_SEND_BUFFER_PRE_PADDING], string_to_send.c_str(), string_to_send.size());