From 78ac57f28edded4949481b62ab81b3faf43d6cce Mon Sep 17 00:00:00 2001 From: Joshua Moerman Date: Tue, 5 Mar 2013 09:41:44 +0100 Subject: [PATCH] Added json, and another protocol --- .gitmodules | 3 ++ CMakeLists.txt | 22 ++++++---- beats-server.sublime-project | 1 + contrib/json-spirit | 1 + main.cpp | 79 ++++++++++++++++++++++++++++++++---- websockets.cpp | 14 ++++--- websockets.h | 3 ++ 7 files changed, 103 insertions(+), 20 deletions(-) create mode 160000 contrib/json-spirit diff --git a/.gitmodules b/.gitmodules index a4e2a7c..18b48dd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "contrib/libwebsockets"] path = contrib/libwebsockets url = git://github.com/warmcat/libwebsockets.git +[submodule "contrib/json-spirit"] + path = contrib/json-spirit + url = git://github.com/sirikata/json-spirit.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 60702e4..abfafe3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,30 @@ cmake_minimum_required(VERSION 2.8) -set(CMAKE_CSS_FLAGS "#{CMAKE_CSS_FLAGS} -Wdeprecated-declarations") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -g3") project(server) +# JSON lib +set(JSON_SPIRIT_BUILD_DEMOS OFF CACHE INTERNAL "" FORCE) +set(JSON_SPIRIT_BUILD_TESTS OFF CACHE INTERNAL "" FORCE) +set(JSON_SPIRIT_LIBRARY_TYPE "STATIC" CACHE INTERNAL "" FORCE) +add_subdirectory(${PROJECT_SOURCE_DIR}/contrib/json-spirit/build ${CMAKE_CURRENT_BINARY_DIR}/json-spirit) +include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/contrib/json-spirit/include/") + +# websockets lib +set(WITHOUT_TESTAPPS ON CACHE INTERNAL "" FORCE) add_subdirectory(${PROJECT_SOURCE_DIR}/contrib/libwebsockets/) -set(WITHOUT_TESTAPPS CACHE BOOL ON) +include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/contrib/libwebsockets/") -find_package(Boost 1.48 REQUIRED) +# Boost libs +find_package(Boost 1.48 REQUIRED COMPONENTS thread system) include_directories(${Boost_INCLUDE_DIRS}) - set(boost ${Boost_LIBRARIES}) -include_directories("${PROJECT_SOURCE_DIR}") -include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/contrib/libwebsockets/") +set(all_libraries websockets json_spirit) -set(all_libraries ${boost} websockets) +# Own files +include_directories("${PROJECT_SOURCE_DIR}") file(GLOB all_files "*.cpp") add_executable(server ${all_files}) diff --git a/beats-server.sublime-project b/beats-server.sublime-project index 6fa06a7..57d4f9b 100644 --- a/beats-server.sublime-project +++ b/beats-server.sublime-project @@ -12,6 +12,7 @@ [ "-isystem/Users/joshua/Documents/Code/libcxx/include/", "-isystem${folder:${project_path:beats-server.sublime-project}}/contrib/libwebsockets/", + "-isystem${folder:${project_path:beats-server.sublime-project}}/contrib/json-spirit/include", "-Wall", "-std=c++11", "-stdlib=libc++" diff --git a/contrib/json-spirit b/contrib/json-spirit new file mode 160000 index 0000000..b585cf7 --- /dev/null +++ b/contrib/json-spirit @@ -0,0 +1 @@ +Subproject commit b585cf771ca10de706f96ddbd6d853dde72c6bbd diff --git a/main.cpp b/main.cpp index 4f5bd1d..9da9132 100644 --- a/main.cpp +++ b/main.cpp @@ -3,21 +3,56 @@ #include #include +#include #include "websockets.h" -int uid = 0; -std::map people_online; +namespace js = json_spirit; + +js::Object get_object(std::string const & in){ + js::Value value; + js::read(in, value); + return value.getObject(); +} -// NOTE: we cannot use C++ ctors and dtors, because it will be allocated by libwebsockets (= C lib) +int uid = 0; struct User { - unsigned int index; + 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; + } + + js::Object to_json() const { + js::Object obj; + #define out(x) obj[#x] = x + out(name); + out(width); + out(height); + #undef out + return obj; + } }; +// unfortunately libwebsockets own the user thingy +std::map people_online; + + websockets::TestProtocol default_protocol{ // connection established [](User& user){ + user.name = "Unknown guest"; user.index = uid++; - people_online[user.index] = ""; + people_online[user.index] = &user; }, // connection closed [](User& user){ @@ -26,17 +61,47 @@ 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.first != user.index) string_to_send += " " + x.second; + for(auto x : people_online) if(x.second != &user) string_to_send += " " + x.second->name; return string_to_send; }, // receive [](User& user, std::string in){ - people_online[user.index] = in; + try{ + user = User::from_json(get_object(in)); + } catch(std::exception& e) { + throw websockets::runtime_error(e.what()); + } + } +}; + +struct Empty{ + int x; +}; + +websockets::TestProtocol observer_protocol{ + // connection established + [](Empty& user){}, + // connection closed + [](Empty& user){}, + // write (will always come after receive) + [](Empty& user) -> std::string{ + js::Array array; + for(auto x : people_online){ + array.push_back(x.second->to_json()); + } + js::Value value(array); + std::cout << "OUTPUT JSON: " << write(value, js::remove_trailing_zeros) << std::endl; + return write(value); + }, + // receive + [](Empty& user, std::string in){ + std::cout << "INPUT: " << in << std::endl; } }; static libwebsocket_protocols protocols[] = { WSstandard_protocol("default", default_protocol), + WSstandard_protocol("observer", observer_protocol), { NULL, NULL, 0 } // end of list }; diff --git a/websockets.cpp b/websockets.cpp index bec876c..0429714 100644 --- a/websockets.cpp +++ b/websockets.cpp @@ -58,14 +58,16 @@ namespace websockets { info.ssl_private_key_filepath = "libwebsockets-test-server.key.pem"; } - websockets::Context context(info); + { + websockets::Context context(info); - static bool force_exit = false; - signal(SIGINT, [](int){ force_exit = true; }); + static bool force_exit = false; + signal(SIGINT, [](int){ force_exit = true; }); - while (!force_exit) { - auto ret = libwebsocket_service(context.get_raw(), 10); - if(ret < 0) break; + while (!force_exit) { + auto ret = libwebsocket_service(context.get_raw(), 10); + if(ret < 0) break; + } } log.notice("libwebsockets-test-echo exited cleanly\n"); diff --git a/websockets.h b/websockets.h index ee1e20b..98c0cbb 100644 --- a/websockets.h +++ b/websockets.h @@ -90,6 +90,7 @@ namespace websockets { // 4-function Protocol, provide functions to handle establishment, closing, receiving and writing (follows receiving) // To let the callback return something non-zero (in case of error), use websockets::runtime_error + // Only types with no-arg ctor are allowed (uses placement new, because libwebsockets allocates for us) template struct TestProtocol { typedef T user_type; @@ -111,9 +112,11 @@ namespace websockets { try{ switch (reason) { case LWS_CALLBACK_ESTABLISHED: + new (user_ptr) user_type(); establish_func(user); break; case LWS_CALLBACK_CLOSED: + user.~user_type(); close_func(user); break; case LWS_CALLBACK_SERVER_WRITEABLE:{