Browse Source

Websockets: added callback in runloop, added more info to protocols

master
Joshua Moerman 11 years ago
parent
commit
8882fe3952
  1. 3
      .gitmodules
  2. 1
      simulation
  3. 31
      src/adaptions.h
  4. 18
      src/main.cpp
  5. 17
      src/websockets.cpp
  6. 28
      src/websockets.h

3
.gitmodules

@ -4,3 +4,6 @@
[submodule "contrib/json-spirit"] [submodule "contrib/json-spirit"]
path = contrib/json-spirit path = contrib/json-spirit
url = git://github.com/sirikata/json-spirit.git url = git://github.com/sirikata/json-spirit.git
[submodule "simulation"]
path = simulation
url = git@github.com:Jaxan/beats-sim.git

1
simulation

@ -0,0 +1 @@
Subproject commit 018cb176c4b3970cd2a6ecae8a63520183c5ddd3

31
src/adaptions.h

@ -0,0 +1,31 @@
#pragma once
#include <string>
#include <boost/fusion/include/define_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include "simulation/Simulation.h"
#include "simulation/Beat.h"
#include "simulation/math.h"
BOOST_FUSION_ADAPT_STRUCT(
::math::Vec2,
(float, x)
(float, y)
)
BOOST_FUSION_ADAPT_TPL_STRUCT(
(BallInfo),
(simulation::Ball) (BallInfo),
(BallInfo, information)
(::math::Vec2, position)
(::math::Vec2, speed)
)
BOOST_FUSION_ADAPT_TPL_STRUCT(
(LineInfo),
(simulation::Line) (LineInfo),
(::math::Vec2, starting_point)
(::math::Vec2, end_point)
(simulation::LineKind, line_kind)
)

18
src/main.cpp

@ -14,22 +14,24 @@
std::unique_ptr<App> app; std::unique_ptr<App> app;
using namespace websockets;
websockets::TestProtocol<User> default_protocol{ websockets::TestProtocol<User> default_protocol{
// connection established // connection established
[](User& user){ [](User& user, basic_websocket_info){
app->login(user); app->login(user);
}, },
// connection closed // connection closed
[](User& user){ [](User& user, basic_websocket_info){
app->logout(user); app->logout(user);
}, },
// write (will always come after receive) // write (will always come after receive)
[](User& user) -> std::string{
app->update_positions(); app->update_positions();
return write_json(ptrvector_to_json(app->people_online)); return write_json(ptrvector_to_json(app->people_online));
[](User& user, basic_websocket_info) -> std::string{
}, },
// receive // receive
[](User& user, std::string in){ [](User& user, std::string in, basic_websocket_info){
try{ try{
user = from_json<IncomingPacket>(parse_json(in)); user = from_json<IncomingPacket>(parse_json(in));
} catch(std::exception& e) { } catch(std::exception& e) {
@ -40,16 +42,16 @@ websockets::TestProtocol<User> default_protocol{
websockets::TestProtocol<Empty> observer_protocol{ websockets::TestProtocol<Empty> observer_protocol{
// connection established // connection established
[](Empty& user){}, [](Empty& user, basic_websocket_info){},
// connection closed // connection closed
[](Empty& user){}, [](Empty& user, basic_websocket_info){},
// write (will always come after receive) // write (will always come after receive)
[](Empty& user) -> std::string{
app->update_positions(); app->update_positions();
return write_json(ptrvector_to_json(app->people_online)); return write_json(ptrvector_to_json(app->people_online));
[](Empty& user, basic_websocket_info) -> std::string{
}, },
// receive // receive
[](Empty& user, std::string in){} [](Empty& user, std::string in, basic_websocket_info){}
}; };
int main(int argc, char **argv){ int main(int argc, char **argv){

17
src/websockets.cpp

@ -1,6 +1,9 @@
#include "websockets.h" #include "websockets.h"
#include <chrono>
#include <thread>
namespace websockets { namespace websockets {
option options[] = { option options[] = {
@ -11,7 +14,7 @@ namespace websockets {
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
int default_main(int argc, char **argv, libwebsocket_protocols* protocols){ int default_main(int argc, char **argv, libwebsocket_protocols* protocols, std::function<void()> runloop_callback){
int port = 7681; int port = 7681;
int use_ssl = 0; int use_ssl = 0;
char interface_name[128] = ""; char interface_name[128] = "";
@ -63,9 +66,21 @@ namespace websockets {
static bool force_exit = false; static bool force_exit = false;
signal(SIGINT, [](int){ force_exit = true; }); signal(SIGINT, [](int){ force_exit = true; });
using clock = std::chrono::steady_clock;
using duration = std::chrono::duration<double>;
while (!force_exit) { while (!force_exit) {
auto begin = clock::now();
auto ret = libwebsocket_service(context.get_raw(), 10); auto ret = libwebsocket_service(context.get_raw(), 10);
if(ret < 0) break; if(ret < 0) break;
if(runloop_callback) runloop_callback();
auto end = clock::now();
duration dur = (end - begin);
dur = duration(1.0/60.0) - dur;
std::this_thread::sleep_for(dur);
} }
} }

28
src/websockets.h

@ -88,6 +88,15 @@ namespace websockets {
}; };
}; };
struct basic_websocket_info{
libwebsocket_context* context{nullptr};
libwebsocket* wsi{nullptr};
basic_websocket_info(libwebsocket_context* context, libwebsocket* wsi)
: context(context)
, wsi(wsi)
{}
};
// 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) // Only types with no-arg ctor are allowed (uses placement new, because libwebsockets allocates for us)
@ -95,10 +104,10 @@ namespace websockets {
struct TestProtocol { struct TestProtocol {
typedef T user_type; typedef T user_type;
std::function<void(user_type&)> establish_func; std::function<void(user_type&, basic_websocket_info)> establish_func;
std::function<void(user_type&)> close_func; std::function<void(user_type&, basic_websocket_info)> close_func;
std::function<std::string(user_type&)> write_func; std::function<std::string(user_type&, basic_websocket_info)> write_func;
std::function<void(user_type&, std::string)> receive_func; std::function<void(user_type&, std::string, basic_websocket_info)> receive_func;
bool verbose{false}; bool verbose{false};
@ -111,20 +120,21 @@ namespace websockets {
int callback(libwebsocket_context* context, libwebsocket* wsi, libwebsocket_callback_reasons reason, void* user_ptr, void *in, size_t len){ int callback(libwebsocket_context* context, libwebsocket* wsi, libwebsocket_callback_reasons reason, void* user_ptr, void *in, size_t len){
user_type& user = *static_cast<user_type*>(user_ptr); user_type& user = *static_cast<user_type*>(user_ptr);
basic_websocket_info binfo{context, wsi};
try{ try{
switch (reason) { switch (reason) {
case LWS_CALLBACK_ESTABLISHED: case LWS_CALLBACK_ESTABLISHED:
lwsl_notice("Connection established (%p, %p)\n", this, user_ptr); lwsl_notice("Connection established (%p, %p)\n", this, user_ptr);
new (user_ptr) user_type(); new (user_ptr) user_type();
establish_func(user); establish_func(user, binfo);
break; break;
case LWS_CALLBACK_CLOSED: case LWS_CALLBACK_CLOSED:
lwsl_notice("Connection closed (%p, %p)\n", this, user_ptr); lwsl_notice("Connection closed (%p, %p)\n", this, user_ptr);
user.~user_type(); user.~user_type();
close_func(user); close_func(user, binfo);
break; break;
case LWS_CALLBACK_SERVER_WRITEABLE:{ case LWS_CALLBACK_SERVER_WRITEABLE:{
std::string string_to_send = write_func(user); std::string string_to_send = write_func(user, binfo);
if(verbose) std::cout << string_to_send << std::endl; if(verbose) std::cout << string_to_send << std::endl;
// we need the extra bytes padding on both sides :( // 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]; unsigned char * buf = new unsigned char [LWS_SEND_BUFFER_PRE_PADDING + string_to_send.size() + LWS_SEND_BUFFER_POST_PADDING];
@ -135,7 +145,7 @@ namespace websockets {
break; break;
} }
case LWS_CALLBACK_RECEIVE: case LWS_CALLBACK_RECEIVE:
receive_func(user, std::string((char*)in, len)); receive_func(user, std::string((char*)in, len), binfo);
libwebsocket_callback_on_writable(context, wsi); libwebsocket_callback_on_writable(context, wsi);
break; break;
default: default:
@ -158,6 +168,6 @@ namespace websockets {
#define WSstandard_protocol(name, protocol)\ #define WSstandard_protocol(name, protocol)\
{ name, WSprotocol_callback(protocol), sizeof(decltype(protocol)::user_type) } { name, WSprotocol_callback(protocol), sizeof(decltype(protocol)::user_type) }
int default_main(int argc, char **argv, libwebsocket_protocols* protocols); int default_main(int argc, char **argv, libwebsocket_protocols* protocols, std::function<void()> runloop_callback = nullptr);
} // namespace websockets } // namespace websockets