Browse Source

Added json, and another protocol

master
Joshua Moerman 12 years ago
parent
commit
78ac57f28e
  1. 3
      .gitmodules
  2. 22
      CMakeLists.txt
  3. 1
      beats-server.sublime-project
  4. 1
      contrib/json-spirit
  5. 79
      main.cpp
  6. 2
      websockets.cpp
  7. 3
      websockets.h

3
.gitmodules

@ -1,3 +1,6 @@
[submodule "contrib/libwebsockets"] [submodule "contrib/libwebsockets"]
path = contrib/libwebsockets path = contrib/libwebsockets
url = git://github.com/warmcat/libwebsockets.git url = git://github.com/warmcat/libwebsockets.git
[submodule "contrib/json-spirit"]
path = contrib/json-spirit
url = git://github.com/sirikata/json-spirit.git

22
CMakeLists.txt

@ -1,22 +1,30 @@
cmake_minimum_required(VERSION 2.8) 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") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -g3")
project(server) 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/) 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}) include_directories(${Boost_INCLUDE_DIRS})
set(boost ${Boost_LIBRARIES}) set(boost ${Boost_LIBRARIES})
include_directories("${PROJECT_SOURCE_DIR}") set(all_libraries websockets json_spirit)
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/contrib/libwebsockets/")
set(all_libraries ${boost} websockets) # Own files
include_directories("${PROJECT_SOURCE_DIR}")
file(GLOB all_files "*.cpp") file(GLOB all_files "*.cpp")
add_executable(server ${all_files}) add_executable(server ${all_files})

1
beats-server.sublime-project

@ -12,6 +12,7 @@
[ [
"-isystem/Users/joshua/Documents/Code/libcxx/include/", "-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/libwebsockets/",
"-isystem${folder:${project_path:beats-server.sublime-project}}/contrib/json-spirit/include",
"-Wall", "-Wall",
"-std=c++11", "-std=c++11",
"-stdlib=libc++" "-stdlib=libc++"

1
contrib/json-spirit

@ -0,0 +1 @@
Subproject commit b585cf771ca10de706f96ddbd6d853dde72c6bbd

79
main.cpp

@ -3,21 +3,56 @@
#include <string> #include <string>
#include <lib/libwebsockets.h> #include <lib/libwebsockets.h>
#include <json_spirit/json_spirit.h>
#include "websockets.h" #include "websockets.h"
int uid = 0; namespace js = json_spirit;
std::map<int, std::string> people_online;
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 { 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<unsigned int, User*> people_online;
websockets::TestProtocol<User> default_protocol{ websockets::TestProtocol<User> default_protocol{
// connection established // connection established
[](User& user){ [](User& user){
user.name = "Unknown guest";
user.index = uid++; user.index = uid++;
people_online[user.index] = ""; people_online[user.index] = &user;
}, },
// connection closed // connection closed
[](User& user){ [](User& user){
@ -26,17 +61,47 @@ websockets::TestProtocol<User> default_protocol{
// write (will always come after receive) // write (will always come after receive)
[](User& user) -> std::string{ [](User& user) -> std::string{
std::string string_to_send = "Other People:"; 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; return string_to_send;
}, },
// receive // receive
[](User& user, std::string in){ [](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<Empty> 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[] = { static libwebsocket_protocols protocols[] = {
WSstandard_protocol("default", default_protocol), WSstandard_protocol("default", default_protocol),
WSstandard_protocol("observer", observer_protocol),
{ NULL, NULL, 0 } // end of list { NULL, NULL, 0 } // end of list
}; };

2
websockets.cpp

@ -58,6 +58,7 @@ namespace websockets {
info.ssl_private_key_filepath = "libwebsockets-test-server.key.pem"; info.ssl_private_key_filepath = "libwebsockets-test-server.key.pem";
} }
{
websockets::Context context(info); websockets::Context context(info);
static bool force_exit = false; static bool force_exit = false;
@ -67,6 +68,7 @@ namespace websockets {
auto ret = libwebsocket_service(context.get_raw(), 10); auto ret = libwebsocket_service(context.get_raw(), 10);
if(ret < 0) break; if(ret < 0) break;
} }
}
log.notice("libwebsockets-test-echo exited cleanly\n"); log.notice("libwebsockets-test-echo exited cleanly\n");
return 0; return 0;

3
websockets.h

@ -90,6 +90,7 @@ namespace websockets {
// 4-function Protocol, provide functions to handle establishment, closing, receiving and writing (follows receiving) // 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 // 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 <typename T> template <typename T>
struct TestProtocol { struct TestProtocol {
typedef T user_type; typedef T user_type;
@ -111,9 +112,11 @@ namespace websockets {
try{ try{
switch (reason) { switch (reason) {
case LWS_CALLBACK_ESTABLISHED: case LWS_CALLBACK_ESTABLISHED:
new (user_ptr) user_type();
establish_func(user); establish_func(user);
break; break;
case LWS_CALLBACK_CLOSED: case LWS_CALLBACK_CLOSED:
user.~user_type();
close_func(user); close_func(user);
break; break;
case LWS_CALLBACK_SERVER_WRITEABLE:{ case LWS_CALLBACK_SERVER_WRITEABLE:{