Added json, and another protocol
This commit is contained in:
parent
99a89ec22f
commit
78ac57f28e
7 changed files with 106 additions and 23 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
||||||
find_package(Boost 1.48 REQUIRED)
|
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
set(boost ${Boost_LIBRARIES})
|
|
||||||
|
|
||||||
include_directories("${PROJECT_SOURCE_DIR}")
|
|
||||||
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/contrib/libwebsockets/")
|
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/contrib/libwebsockets/")
|
||||||
|
|
||||||
set(all_libraries ${boost} websockets)
|
# Boost libs
|
||||||
|
find_package(Boost 1.48 REQUIRED COMPONENTS thread system)
|
||||||
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
|
set(boost ${Boost_LIBRARIES})
|
||||||
|
|
||||||
|
set(all_libraries websockets json_spirit)
|
||||||
|
|
||||||
|
# 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})
|
||||||
|
|
|
@ -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
Submodule
1
contrib/json-spirit
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit b585cf771ca10de706f96ddbd6d853dde72c6bbd
|
79
main.cpp
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;
|
|
||||||
|
|
||||||
// NOTE: we cannot use C++ ctors and dtors, because it will be allocated by libwebsockets (= C lib)
|
js::Object get_object(std::string const & in){
|
||||||
|
js::Value value;
|
||||||
|
js::read(in, value);
|
||||||
|
return value.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:{
|
||||||
|
|
Reference in a new issue