From c87006a26458ae30986b074b1ee8b57fdd3723d1 Mon Sep 17 00:00:00 2001 From: Ossama Othman Date: Fri, 4 Oct 2013 13:40:24 -0700 Subject: [PATCH] Initial support for event reporting. Signed-off-by: Ossama Othman --- include/settingsd/Makefile.am | 2 + include/settingsd/event_callback.hpp | 116 ++++++++++++++++++++++++++++++++ include/settingsd/response_callback.hpp | 35 +++------- include/settingsd/send_callback.hpp | 91 +++++++++++++++++++++++++ lib/Makefile.am | 2 + lib/event_callback.cpp | 88 ++++++++++++++++++++++++ lib/manager.cpp | 3 +- lib/response_callback.cpp | 91 +++++++------------------ lib/send_callback.cpp | 99 +++++++++++++++++++++++++++ src/websocket_server.cpp | 4 ++ 10 files changed, 437 insertions(+), 94 deletions(-) create mode 100644 include/settingsd/event_callback.hpp create mode 100644 include/settingsd/send_callback.hpp create mode 100644 lib/event_callback.cpp create mode 100644 lib/send_callback.cpp diff --git a/include/settingsd/Makefile.am b/include/settingsd/Makefile.am index c81f8a1..eb43239 100644 --- a/include/settingsd/Makefile.am +++ b/include/settingsd/Makefile.am @@ -22,6 +22,8 @@ pkginclude_HEADERS = \ settings_api.hpp \ plugin.hpp \ registrar.hpp \ + send_callback.hpp \ + event_callback.hpp \ response_callback.hpp \ glib_traits.hpp \ json_glib_traits.hpp \ diff --git a/include/settingsd/event_callback.hpp b/include/settingsd/event_callback.hpp new file mode 100644 index 0000000..8c02918 --- /dev/null +++ b/include/settingsd/event_callback.hpp @@ -0,0 +1,116 @@ +/** + * @file event_callback.hpp + * + * @brief Settings event callback header. + * + * @author Ossama Othman @ + * + * @copyright @par + * Copyright 2013 Intel Corporation All Rights Reserved. + * @par + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * @par + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + +#ifndef IVI_SETTINGS_EVENT_CALLBACK_HPP +#define IVI_SETTINGS_EVENT_CALLBACK_HPP + +#include +#include + +#include +#include + + +namespace ivi +{ + namespace settings + { + template class smart_ptr; + + /** + * @class event_callback event_callback.hpp + * + * @brief Callback that handles sending event to Settings app. + * + * A @c event_callback sends a JSON formatted event string + * to the Settings app. It is up to the specific settings plugin + * to decide what goes in to the event. + */ + class SETTINGS_API event_callback + { + public: + + /// Constructor + event_callback(libwebsocket * wsi); + + /** + * Send event to Settings app. + * + * The settings daemon requires that plugins use the json-glib + * library to build JSON event strings. Plugins will pass a + * callback function @a event_builder that uses to the + * json-glib high level "builder" API to append the event to the + * JSON event string. Plugins should take care to only use the + * builder functions that add members and their corresponding + * values. They should not attempt to start or end the top + * level JSON object. That will be automatically handled by + * this class. + * + * @param[in] type Setting type, e.g. @c "wifi". + * @param[in] event_builder Callback function that appends JSON + * formatted event data. + */ + bool send_event( + std::string const & type, + std::function event_builder); + + private: + + /** + * Begin the JSON formatted event to the Settings app + * request. + * + * The appropriate "header" information will be prepended to the + * event. + * + * @param[in] result @c "succeeded" or @c "failed" + */ + smart_ptr begin_event(std::string const & type); + + /** + * End the JSON formatted event to the Settings app request. + */ + void end_event(smart_ptr const & builder); + + private: + + /// Object used to send event to client over WebSocket. + send_callback writer_; + + }; + + } +} + +#endif /* IVI_SETTINGS_EVENT_CALLBACK_HPP */ + + +// Local Variables: +// mode:c++ +// c-basic-offset:2 +// indent-tabs-mode: nil +// End: diff --git a/include/settingsd/response_callback.hpp b/include/settingsd/response_callback.hpp index 3c59a79..083bd54 100644 --- a/include/settingsd/response_callback.hpp +++ b/include/settingsd/response_callback.hpp @@ -6,7 +6,7 @@ * @author Ossama Othman @ * * @copyright @par - * Copyright 2012, 2013 Intel Corporation All Rights Reserved. + * Copyright 2013 Intel Corporation All Rights Reserved. * @par * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,12 +29,10 @@ #define IVI_SETTINGS_RESPONSE_CALLBACK_HPP #include +#include -#include -#include - -#include #include +#include namespace ivi @@ -57,26 +55,22 @@ namespace ivi public: /// Constructor - response_callback(struct libwebsocket * wsi, + response_callback(libwebsocket * wsi, std::string type, std::string transaction_id); - /// Destructor. - ~response_callback(); - /** * Send (successful) response to Settings app. * * The settings daemon requires that plugins use the json-glib - * library to build JSON respons strings. Plugins will pass a + * library to build JSON response strings. Plugins will pass a * callback function @a response_builder that uses to the * json-glib high level "builder" API to append the results of * the successful Settings app request to the JSON response * string. Plugins should take care to only use the builder - * functions that add members and their corresponding to - * values. They should not attempt to start or end the top - * level JSON object. That will be automatically handled by - * this class. + * functions that add members and their corresponding values. + * They should not attempt to start or end the top level JSON + * object. That will be automatically handled by this class. * * @param[in] response_builder Callback function that appends * JSON formatted response data. @@ -127,19 +121,10 @@ namespace ivi */ void end_response(smart_ptr const & builder); - /** - * Send the JSON formatted response to the Settings app - * request over the corresponding websocket. - */ - bool send_payload(smart_ptr const & builder); - private: - /** - * Pointer to the websocket through which the response will be - * sent to the Settings app. - */ - struct libwebsocket * const wsi_; + /// Object used to send response to client over WebSocket. + send_callback writer_; /** * Settings type (e.g. "bluetooth", "wifi", etc). diff --git a/include/settingsd/send_callback.hpp b/include/settingsd/send_callback.hpp new file mode 100644 index 0000000..599358d --- /dev/null +++ b/include/settingsd/send_callback.hpp @@ -0,0 +1,91 @@ +/** + * @file send_callback.hpp + * + * @brief Core send functionality for responses and events. + * + * @author Ossama Othman @ + * + * @copyright @par + * Copyright 2013 Intel Corporation All Rights Reserved. + * @par + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * @par + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * @note This header is internal. + */ + + +#ifndef IVI_SETTINGS_SEND_CALLBACK_HPP +#define IVI_SETTINGS_SEND_CALLBACK_HPP + +#include +#include + + +namespace ivi +{ + namespace settings + { + template class smart_ptr; + + /** + * @class send_callback + * + * @brief Callback that handles sending response to Settings app. + * + * A @c send_callback sends a JSON formatted response string + * to the Settings app. It is up to the specific settings plugin + * to decide what goes in to the response. + */ + class send_callback + { + public: + + /// Constructor + send_callback(libwebsocket * wsi); + + /** + * Send the JSON formatted payload to the Settings app + * over the corresponding websocket. + * + * @param[in] send_type Type of payload, e.g. @c "response" or + * @c "event". + * @param[in] builder JSON-GLib object containing the + * pre-marshalled (in-memory) payload. + */ + bool send_payload(char const * send_type, + smart_ptr const & builder); + + private: + + /** + * Pointer to the websocket through which the payload will be + * sent to the Settings app. + */ + libwebsocket * const wsi_; + + }; + + } +} + +#endif /* IVI_SETTINGS_SEND_CALLBACK_HPP */ + + +// Local Variables: +// mode:c++ +// c-basic-offset:2 +// indent-tabs-mode: nil +// End: diff --git a/lib/Makefile.am b/lib/Makefile.am index 276a61f..940386c 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -25,6 +25,8 @@ libsettings_la_SOURCES = \ manager.cpp \ plugin.cpp \ registrar.cpp \ + send_callback.cpp \ + event_callback.cpp \ response_callback.cpp libsettings_la_CPPFLAGS = -DSETTINGS_BUILDING_DLL -I$(top_srcdir)/include diff --git a/lib/event_callback.cpp b/lib/event_callback.cpp new file mode 100644 index 0000000..f07a77f --- /dev/null +++ b/lib/event_callback.cpp @@ -0,0 +1,88 @@ +/** + * @file event_callback.cpp + * + * @brief Settings plugin event_callback implementation. + * + * @author Ossama Othman @ + * + * @copyright @par + * Copyright 2013 Intel Corporation All Rights Reserved. + * @par + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * @par + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include + + +ivi::settings::event_callback::event_callback(libwebsocket * wsi) + : writer_(wsi) +{ +} + +bool +ivi::settings::event_callback::send_event( + std::string const & type, + std::function event_builder) +{ + smart_ptr const builder = begin_event(type); + + // Append settings type-specific JSON formatted events. + event_builder(builder.get()); + + end_event(builder); + + bool const success = writer_.send_payload("event", builder); + + if (!success) + g_critical("Unable to send %s event", type.c_str()); + + return success; +} + +ivi::settings::smart_ptr +ivi::settings::event_callback::begin_event(std::string const & type) +{ + // Construct JSON event string. + smart_ptr safe_builder(json_builder_new()); + JsonBuilder * const builder = safe_builder.get(); + + json_builder_begin_object(builder); + + json_builder_set_member_name(builder, "type"); + if (type.empty()) + json_builder_add_null_value(builder); + else + json_builder_add_string_value(builder, type.c_str()); + + return safe_builder; +} + +void +ivi::settings::event_callback::end_event( + ivi::settings::smart_ptr const & builder) +{ + json_builder_end_object(builder.get()); +} + + + +// Local Variables: +// mode:c++ +// c-basic-offset:2 +// indent-tabs-mode: nil +// End: diff --git a/lib/manager.cpp b/lib/manager.cpp index 0b497c9..c8d4357 100644 --- a/lib/manager.cpp +++ b/lib/manager.cpp @@ -105,7 +105,8 @@ ivi::settings::manager::load_settings(std::string const & dir) * @todo I really hate catching an exception like this, but I * really don't want to resort to a construct/init() * style of object initialization. Fix. - */std::cerr << "Error loading plugin: " << e.what() << "\n"; + */ + std::cerr << "Error loading plugin: " << e.what() << "\n"; } } diff --git a/lib/response_callback.cpp b/lib/response_callback.cpp index 6eb3eaa..0d56aa8 100644 --- a/lib/response_callback.cpp +++ b/lib/response_callback.cpp @@ -6,7 +6,7 @@ * @author Ossama Othman @ * * @copyright @par - * Copyright 2012, 2013 Intel Corporation All Rights Reserved. + * Copyright 2013 Intel Corporation All Rights Reserved. * @par * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,29 +25,20 @@ */ #include -#include #include #include -#include -#include -#include - ivi::settings::response_callback::response_callback( - struct libwebsocket * wsi, + libwebsocket * wsi, std::string type, std::string transaction_id) - : wsi_(wsi) + : writer_(wsi) , type_(type) , transaction_id_(transaction_id) { } -ivi::settings::response_callback::~response_callback() -{ -} - bool ivi::settings::response_callback::send_response( std::function response_builder) @@ -60,7 +51,16 @@ ivi::settings::response_callback::send_response( end_response(builder); - return send_payload(builder); + bool const success = writer_.send_payload("response", builder); + + if (!success) + g_critical("Unable to send response for:\n" + " type: %s\n" + " transactionid: %s\n", + type_.c_str(), + transaction_id_.c_str()); + + return success; } bool @@ -73,7 +73,16 @@ ivi::settings::response_callback::send_error(std::string error_message) end_response(builder); - return send_payload(builder); + bool const success = writer_.send_payload("error", builder); + + if (!success) + g_critical("Unable to send error for:\n" + " type: %s\n" + " transactionid: %s\n", + type_.c_str(), + transaction_id_.c_str()); + + return success; } void @@ -114,60 +123,6 @@ ivi::settings::response_callback::end_response( json_builder_end_object(builder.get()); } -bool -ivi::settings::response_callback::send_payload( - ivi::settings::smart_ptr const & builder) -{ - smart_ptr const generator(json_generator_new()); - smart_ptr const root(json_builder_get_root(builder.get())); - json_generator_set_root(generator.get(), root.get()); - - gchar * const response = - json_generator_to_data(generator.get(), nullptr); - - smart_ptr safe_response(response); - - if (response == nullptr) { - g_critical("Unable to generate JSON response for:\n" - " type: %s\n" - " transactionid: %s\n", - type_.c_str(), - transaction_id_.c_str()); - - return false; - } - - g_debug("Sending response: %s\n", response); - - size_t const payload_len = strlen(response); - - // libwebsockets wants a sequence of octets (unsigned char *) rather - // than characters. - typedef std::vector vector_type; - - vector_type::size_type const buf_len = - LWS_SEND_BUFFER_PRE_PADDING - + payload_len - + LWS_SEND_BUFFER_POST_PADDING; - - vector_type buf(buf_len); - unsigned char * const payload = - buf.data() + LWS_SEND_BUFFER_PRE_PADDING; - - // Copy the string into the buffer after libwebsockets pre-padding. - std::copy(response, - response + payload_len, - payload); - - int const count = libwebsocket_write(wsi_, - payload, - payload_len, - LWS_WRITE_TEXT); - - return count >= 0; -} - - // Local Variables: // mode:c++ diff --git a/lib/send_callback.cpp b/lib/send_callback.cpp new file mode 100644 index 0000000..878f3ac --- /dev/null +++ b/lib/send_callback.cpp @@ -0,0 +1,99 @@ +/** + * @file send_callback.cpp + * + * @brief Core send functionality for responses and events. + * + * @author Ossama Othman @ + * + * @copyright @par + * Copyright 2013 Intel Corporation All Rights Reserved. + * @par + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * @par + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include +#include +#include + + +ivi::settings::send_callback::send_callback(libwebsocket * wsi) + : wsi_(wsi) +{ +} + +bool +ivi::settings::send_callback::send_payload( + char const * send_type, + ivi::settings::smart_ptr const & builder) +{ + smart_ptr const generator(json_generator_new()); + smart_ptr const root(json_builder_get_root(builder.get())); + json_generator_set_root(generator.get(), root.get()); + + gchar * const data = + json_generator_to_data(generator.get(), nullptr); + + smart_ptr safe_data(data); + + if (data == nullptr) { + g_critical("Unable to generate JSON formatted %s payload:\n", + send_type); + + return false; + } + + g_debug("Sending %s: %s\n", send_type, data); + + size_t const payload_len = strlen(data); + + // libwebsockets wants a sequence of octets (unsigned char *) rather + // than characters. + typedef std::vector vector_type; + + vector_type::size_type const buf_len = + LWS_SEND_BUFFER_PRE_PADDING + + payload_len + + LWS_SEND_BUFFER_POST_PADDING; + + vector_type buf(buf_len); + unsigned char * const payload = + buf.data() + LWS_SEND_BUFFER_PRE_PADDING; + + // Copy the string into the buffer after libwebsockets pre-padding. + std::copy(data, + data + payload_len, + payload); + + int const count = libwebsocket_write(wsi_, + payload, + payload_len, + LWS_WRITE_TEXT); + + return count >= 0; +} + + + +// Local Variables: +// mode:c++ +// c-basic-offset:2 +// indent-tabs-mode: nil +// End: diff --git a/src/websocket_server.cpp b/src/websocket_server.cpp index e454839..69fbfeb 100644 --- a/src/websocket_server.cpp +++ b/src/websocket_server.cpp @@ -53,6 +53,10 @@ namespace libwebsocket_context_user(context)); switch(reason) { + case LWS_CALLBACK_ESTABLISHED: + // Enable event dispatching to client. + + break; case LWS_CALLBACK_RECEIVE: // Request has come in from Settings app. Pass it on to the // settings manager. -- 2.7.4