Added some comments and exceptions to handle errors
This commit is contained in:
parent
2f2a84d586
commit
99a89ec22f
2 changed files with 61 additions and 39 deletions
9
main.cpp
9
main.cpp
|
@ -15,15 +15,13 @@ struct User {
|
||||||
|
|
||||||
websockets::TestProtocol<User> default_protocol{
|
websockets::TestProtocol<User> default_protocol{
|
||||||
// connection established
|
// connection established
|
||||||
[](User& user) -> int{
|
[](User& user){
|
||||||
user.index = uid++;
|
user.index = uid++;
|
||||||
people_online[user.index] = "";
|
people_online[user.index] = "";
|
||||||
return 0;
|
|
||||||
},
|
},
|
||||||
// connection closed
|
// connection closed
|
||||||
[](User& user) -> int{
|
[](User& user){
|
||||||
people_online.erase(user.index);
|
people_online.erase(user.index);
|
||||||
return 0;
|
|
||||||
},
|
},
|
||||||
// write (will always come after receive)
|
// write (will always come after receive)
|
||||||
[](User& user) -> std::string{
|
[](User& user) -> std::string{
|
||||||
|
@ -32,9 +30,8 @@ websockets::TestProtocol<User> default_protocol{
|
||||||
return string_to_send;
|
return string_to_send;
|
||||||
},
|
},
|
||||||
// receive
|
// receive
|
||||||
[](User& user, std::string in) -> int{
|
[](User& user, std::string in){
|
||||||
people_online[user.index] = in;
|
people_online[user.index] = in;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
57
websockets.h
57
websockets.h
|
@ -12,6 +12,23 @@
|
||||||
#include <lib/libwebsockets.h>
|
#include <lib/libwebsockets.h>
|
||||||
|
|
||||||
namespace websockets {
|
namespace websockets {
|
||||||
|
// Will be caught in the callback and program will continue to run (but connection will be closed)
|
||||||
|
struct runtime_error : public std::runtime_error {
|
||||||
|
int return_value;
|
||||||
|
|
||||||
|
runtime_error(const char * message, int return_value = -1)
|
||||||
|
: std::runtime_error(message)
|
||||||
|
, return_value(return_value)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Will never be caught (by us), and hence things will terminate
|
||||||
|
struct fatal_error : public std::runtime_error {
|
||||||
|
fatal_error(const char * message)
|
||||||
|
: std::runtime_error(message)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
struct Log {
|
struct Log {
|
||||||
Log(std::string const & name, int syslog_options, int debug_level){
|
Log(std::string const & name, int syslog_options, int debug_level){
|
||||||
setlogmask(LOG_UPTO (LOG_DEBUG));
|
setlogmask(LOG_UPTO (LOG_DEBUG));
|
||||||
|
@ -37,6 +54,7 @@ namespace websockets {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Basic wrapper for the context pointer
|
||||||
struct Context {
|
struct Context {
|
||||||
std::unique_ptr<libwebsocket_context, decltype(libwebsocket_context_destroy)*> context;
|
std::unique_ptr<libwebsocket_context, decltype(libwebsocket_context_destroy)*> context;
|
||||||
|
|
||||||
|
@ -58,6 +76,7 @@ namespace websockets {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Basic protocol to extend, already casts the void* to the actual type
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Protocol {
|
struct Protocol {
|
||||||
typedef T user_type;
|
typedef T user_type;
|
||||||
|
@ -69,12 +88,16 @@ 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
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct TestProtocol : public Protocol<T> {
|
struct TestProtocol {
|
||||||
std::function<int(T&)> establish_func;
|
typedef T user_type;
|
||||||
std::function<int(T&)> close_func;
|
|
||||||
std::function<std::string(T&)> write_func;
|
std::function<void(user_type&)> establish_func;
|
||||||
std::function<int(T&, std::string)> receive_func;
|
std::function<void(user_type&)> close_func;
|
||||||
|
std::function<std::string(user_type&)> write_func;
|
||||||
|
std::function<void(user_type&, std::string)> receive_func;
|
||||||
|
|
||||||
TestProtocol(decltype(establish_func) establish_func, decltype(close_func) close_func, decltype(write_func) write_func, decltype(receive_func) receive_func)
|
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)
|
: establish_func(establish_func)
|
||||||
|
@ -83,7 +106,9 @@ namespace websockets {
|
||||||
, receive_func(receive_func)
|
, receive_func(receive_func)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual int call(libwebsocket_context& context, libwebsocket& wsi, libwebsocket_callback_reasons reason, T& user, 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);
|
||||||
|
try{
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case LWS_CALLBACK_ESTABLISHED:
|
case LWS_CALLBACK_ESTABLISHED:
|
||||||
establish_func(user);
|
establish_func(user);
|
||||||
|
@ -96,28 +121,28 @@ namespace websockets {
|
||||||
// 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];
|
||||||
memcpy(&buf[LWS_SEND_BUFFER_PRE_PADDING], string_to_send.c_str(), string_to_send.size());
|
memcpy(&buf[LWS_SEND_BUFFER_PRE_PADDING], string_to_send.c_str(), string_to_send.size());
|
||||||
int n = libwebsocket_write(&wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], string_to_send.size(), LWS_WRITE_TEXT);
|
int n = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], string_to_send.size(), LWS_WRITE_TEXT);
|
||||||
if (n < 0) {
|
if (n < 0) throw runtime_error("Could not write", 1);
|
||||||
lwsl_err("ERROR %d writing to socket, hanging up\n", n);
|
if (n < string_to_send.size()) throw runtime_error("Partial write", -1);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (n < string_to_send.size()) {
|
|
||||||
lwsl_err("Partial write\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
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));
|
||||||
libwebsocket_callback_on_writable(&context, &wsi);
|
libwebsocket_callback_on_writable(context, wsi);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} catch(runtime_error& e){
|
||||||
|
lwsl_err("Exception thrown: %s", e.what());
|
||||||
|
return e.return_value;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Some wrappers to easily create the list of protocols from structs of above kind.
|
||||||
#define WSprotocol_callback(protocol)\
|
#define WSprotocol_callback(protocol)\
|
||||||
[](libwebsocket_context *context, libwebsocket *wsi, libwebsocket_callback_reasons reason, void *user, void *in, size_t len)\
|
[](libwebsocket_context *context, libwebsocket *wsi, libwebsocket_callback_reasons reason, void *user, void *in, size_t len)\
|
||||||
{return protocol.callback(context, wsi, reason, user, in, len);}
|
{return protocol.callback(context, wsi, reason, user, in, len);}
|
||||||
|
|
Reference in a new issue