"reason": "<some error message>"
}
+// General form of an event
+var event =
+ {
+ "object_path":"<object path>" or null,
+ "interface_name":"<interface name>" or null,
+ "name":"<event name>",
+ "value": <setting specific value>
+ }
+
// --------------------------------------------------------------
// Bluetooth
// --------------------------------------------------------------
]
}
+// WiFi "PropertyChanged" event
+var event =
+ {
+ "object_path":"/net/connman/technology/wifi",
+ "interface_name":"net.connman.Technology",
+ "name":"PropertyChanged",
+ "value":["Powered",false]
+ }
+
// --------------------------------------------------------------
// Clock
// --------------------------------------------------------------
"result": "succeeded"
"value": true or false
}
+
+
+// --------------------------------------------------------------
+// Global Events
+// --------------------------------------------------------------
+
+// "ServicesChanged" event from Connman Manager object
+var event =
+ {
+ "object_path":"/",
+ "interface_name":"net.connman.Manager"
+ "name": "ServicesChanged",
+ "value": [
+ [
+ [
+ "/net/connman/service/ethernet_002564e81cc7_cable",
+ {}
+ ],
+ [
+ "/net/connman/service/wifi_50465dae486e_574f537769666932472d4150_managed_wep",
+ {
+ "AutoConnect": false,
+ "Domains": [],
+ "Domains.Configuration": [],
+ "Ethernet": {
+ "Address": "20:36:5D:AF:28:9E",
+ "Interface": "wlan0",
+ "MTU": 1500,
+ "Method": "auto"
+ },
+ "Favorite": false,
+ "IPv4": {},
+ "IPv4.Configuration": {
+ "Method": "dhcp"
+ },
+ "IPv6": {},
+ "IPv6.Configuration": {
+ "Method": "auto",
+ "Privacy": "prefered"
+ },
+ "Immutable": false,
+ "Name": "WOSwifi2G-AP",
+ "Nameservers": [],
+ "Nameservers.Configuration": [],
+ "Provider": {},
+ "Proxy": {},
+ "Proxy.Configuration": {},
+ "Security": [
+ "wep"
+ ],
+ "State": "idle",
+ "Strength": 73,
+ "Timeservers": [],
+ "Timeservers.Configuration": [],
+ "Type": "wifi"
+ }
+ ]
+ ],
+ [
+ "/net/connman/service/wifi_50465dae486e_hidden_managed_wep"
+ ]
+ ]
+ }
settings_api.hpp \
plugin.hpp \
registrar.hpp \
+ send_callback.hpp \
+ event_callback.hpp \
response_callback.hpp \
glib_traits.hpp \
json_glib_traits.hpp \
--- /dev/null
+/**
+ * @file event_callback.hpp
+ *
+ * @brief Settings event callback header.
+ *
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @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 <settingsd/settings_api.hpp>
+#include <settingsd/send_callback.hpp>
+
+#include <functional>
+
+
+namespace ivi
+{
+ namespace settings
+ {
+ template<typename T> class smart_ptr;
+ class manager;
+
+ /**
+ * @class event_callback event_callback.hpp <settingsd/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(manager & m);
+
+ /**
+ * 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_name Event name, e.g.
+ * @c "PropertyChanged".
+ * @param[in] event_builder Callback function that appends JSON
+ * formatted event data.
+ */
+ bool send_event(
+ char const * object_path,
+ char const * interface_name,
+ char const * event_name,
+ std::function<void(JsonBuilder *)> event_builder);
+
+ private:
+
+ /**
+ * Begin the JSON formatted event to the Settings app
+ * request.
+ *
+ * The appropriate "header" information will be prepended to the
+ * event.
+ */
+ smart_ptr<JsonBuilder> begin_event(char const * object_path,
+ char const * interface_name,
+ char const * event_name);
+
+ /**
+ * End the JSON formatted event to the Settings app request.
+ */
+ void end_event(smart_ptr<JsonBuilder> const & builder);
+
+ private:
+
+ /**
+ * Settings manager used to send event to clients over
+ * corresponding WebSockets.
+ */
+ manager & manager_;
+
+ };
+
+ }
+}
+
+#endif /* IVI_SETTINGS_EVENT_CALLBACK_HPP */
+
+
+// Local Variables:
+// mode:c++
+// c-basic-offset:2
+// indent-tabs-mode: nil
+// End:
* @author Ossama Othman @<ossama.othman@@intel.com@>
*
* @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
#define IVI_SETTINGS_RESPONSE_CALLBACK_HPP
#include <settingsd/settings_api.hpp>
+#include <settingsd/send_callback.hpp>
-#include <libwebsockets.h>
-#include <json-glib/json-glib.h>
-
-#include <functional>
#include <string>
+#include <functional>
namespace ivi
public:
/// Constructor
- response_callback(struct libwebsocket * wsi,
+ response_callback(libwebsocket * wsi,
std::string type,
std::string transaction_id);
- /// Destructor.
- ~response_callback();
+ /// Copy constructor
+ response_callback(response_callback const & other);
/**
* 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.
*/
void end_response(smart_ptr<JsonBuilder> const & builder);
- /**
- * Send the JSON formatted response to the Settings app
- * request over the corresponding websocket.
- */
- bool send_payload(smart_ptr<JsonBuilder> 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).
--- /dev/null
+/**
+ * @file send_callback.hpp
+ *
+ * @brief Core send functionality for responses and events.
+ *
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @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 <libwebsockets.h>
+#include <json-glib/json-glib.h>
+
+
+namespace ivi
+{
+ namespace settings
+ {
+ template<typename T> 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);
+
+ /// Copy constructor.
+ send_callback(send_callback const & other);
+
+ /// Assignment operator.
+ send_callback & operator=(send_callback const & other);
+
+ /**
+ * 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<JsonBuilder> const & builder);
+
+ /**
+ * Check if the WebSocket instance @a wsi corresponds to this
+ * @c send_callback.
+ */
+ bool
+ operator==(libwebsocket const * wsi) const
+ {
+ return wsi_ == wsi;
+ }
+
+ private:
+
+ /**
+ * Pointer to the websocket through which the payload will be
+ * sent to the Settings app.
+ */
+ libwebsocket * wsi_;
+
+ };
+
+ }
+}
+
+#endif /* IVI_SETTINGS_SEND_CALLBACK_HPP */
+
+
+// Local Variables:
+// mode:c++
+// c-basic-offset:2
+// indent-tabs-mode: nil
+// End:
## Boston, MA 02110-1301 USA
## ---------------------------------------------------------
-## settings plugin library
+## settingsd plugin library
## ---------------------------------------------------------
lib_LTLIBRARIES = libsettings.la
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
--- /dev/null
+/**
+ * @file event_callback.cpp
+ *
+ * @brief Settings plugin event_callback implementation.
+ *
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @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 <settingsd/event_callback.hpp>
+#include <settingsd/json_glib_traits.hpp>
+#include <settingsd/smart_ptr.hpp>
+#include "manager.hpp"
+
+
+ivi::settings::event_callback::event_callback(manager & mgr)
+ : manager_(mgr)
+{
+}
+
+bool
+ivi::settings::event_callback::send_event(
+ char const * object_path,
+ char const * interface_name,
+ char const * event_name,
+ std::function<void(JsonBuilder *)> event_builder)
+{
+ smart_ptr<JsonBuilder> const builder =
+ begin_event(object_path, interface_name, event_name);
+
+ // Append settings type-specific JSON formatted events.
+ event_builder(builder.get());
+
+ end_event(builder);
+
+ bool const success = manager_.send_event(builder);
+
+ if (!success)
+ g_critical("Unable to send %s event", event_name);
+
+ return success;
+}
+
+ivi::settings::smart_ptr<JsonBuilder>
+ivi::settings::event_callback::begin_event(char const * object_path,
+ char const * interface_name,
+ char const * event_name)
+{
+ // Construct JSON event string.
+ smart_ptr<JsonBuilder> safe_builder(json_builder_new());
+ JsonBuilder * const builder = safe_builder.get();
+
+ json_builder_begin_object(builder);
+
+ json_builder_set_member_name(builder, "object_path");
+ if (object_path == nullptr)
+ json_builder_add_null_value(builder);
+ else
+ json_builder_add_string_value(builder, object_path);
+
+ json_builder_set_member_name(builder, "interface_name");
+ if (interface_name == nullptr)
+ json_builder_add_null_value(builder);
+ else
+ json_builder_add_string_value(builder, interface_name);
+
+ json_builder_set_member_name(builder, "name");
+ json_builder_add_string_value(builder, event_name);
+
+ return safe_builder;
+}
+
+void
+ivi::settings::event_callback::end_event(
+ ivi::settings::smart_ptr<JsonBuilder> const & builder)
+{
+ json_builder_end_object(builder.get());
+}
+
+
+
+// Local Variables:
+// mode:c++
+// c-basic-offset:2
+// indent-tabs-mode: nil
+// End:
#include "manager.hpp"
#include <settingsd/plugin.hpp>
#include <settingsd/registrar.hpp>
+#include <settingsd/event_callback.hpp>
#include <stdexcept>
#include <dlfcn.h>
dlerror();
// Retrieve the settings factory and destroyer functions.
- typedef bool(*factory_type)(registrar &);
+ typedef bool(*factory_type)(registrar &, event_callback const &);
factory_type const register_settings =
IVI_SETTINGS_EXTENSION reinterpret_cast<factory_type>(
dlsym(handle_,
// Now create the underlying settings implementation.
registrar r(mgr);
- if (!register_settings(r))
+ event_callback e(mgr);
+ if (!register_settings(r, e))
throw std::runtime_error("Unable to make \""
+ plugin_name
+ "\" settings plugin");
ivi::settings::manager::manager(std::string const & dir)
: loaders_()
, settings_()
+ , mutex_()
+ , send_callbacks_()
{
load_settings(dir);
}
void
ivi::settings::manager::dispatch(std::string request,
- struct libwebsocket * wsi)
+ libwebsocket * wsi)
{
if (request.empty()) {
response_callback response(wsi, std::string(), std::string());
}
}
+void
+ivi::settings::manager::subscribe_client(libwebsocket * wsi)
+{
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ send_callbacks_.emplace_back(wsi);
+}
+
+void
+ivi::settings::manager::unsubscribe_client(libwebsocket * wsi)
+{
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ auto const end = send_callbacks_.end();
+ for (auto i = send_callbacks_.begin(); i != end; ++i)
+ if (*i == wsi)
+ send_callbacks_.erase(i);
+}
+
+bool
+ivi::settings::manager::send_event(
+ smart_ptr<JsonBuilder> const & builder)
+{
+ bool success = true;
+
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ for (auto c : send_callbacks_)
+ if (!c.send_payload("event", builder))
+ success = false;
+
+ return success;
+}
+
// Local Variables:
// mode:c++
#include "loader.hpp"
#include <settingsd/plugin.hpp>
+#include <settingsd/send_callback.hpp>
#include <libwebsockets.h>
#include <map>
#include <vector>
#include <memory>
+#include <mutex>
namespace ivi
*/
void dispatch(std::string request, libwebsocket * wsi);
+ /**
+ * Subscribe client on the other side of the WebSocket @a wsi to
+ * events created by settings plugins.
+ */
+ void subscribe_client(libwebsocket * wsi);
+
+ /**
+ * Unsubscribe client on the other side of the WebSocket @a wsi
+ * from receiving further settings plugin events.
+ */
+ void unsubscribe_client(libwebsocket * wsi);
+
+ /**
+ * Send JSON formatted event to all clients.
+ *
+ * @param[in] builder Object used to generate the JSON formatted
+ * event.
+ *
+ * @return @c true on success.
+ */
+ bool send_event(smart_ptr<JsonBuilder> const & builder);
+
private:
/**
/// Map of settings name to @c settings instance.
map_type settings_;
+ /// Mutex used to synchronize access to the send_callback list.
+ std::mutex mutex_;
+
+ /**
+ * List of client WebSockets to be used for sending events to
+ * the client.
+ */
+ std::vector<send_callback> send_callbacks_;
+
};
}
* @author Ossama Othman @<ossama.othman@@intel.com@>
*
* @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
*/
#include <settingsd/response_callback.hpp>
-#include <settingsd/glib_traits.hpp>
#include <settingsd/json_glib_traits.hpp>
#include <settingsd/smart_ptr.hpp>
-#include <cstring>
-#include <algorithm>
-#include <iostream>
-
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()
+ivi::settings::response_callback::response_callback(
+ response_callback const & other)
+ : writer_(other.writer_)
+ , type_(other.type_)
+ , transaction_id_(other.transaction_id_)
{
}
+
bool
ivi::settings::response_callback::send_response(
std::function<void(JsonBuilder *)> response_builder)
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
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
json_builder_end_object(builder.get());
}
-bool
-ivi::settings::response_callback::send_payload(
- ivi::settings::smart_ptr<JsonBuilder> const & builder)
-{
- smart_ptr<JsonGenerator> const generator(json_generator_new());
- smart_ptr<JsonNode> 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<gchar> 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<unsigned char> 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++
--- /dev/null
+/**
+ * @file send_callback.cpp
+ *
+ * @brief Core send functionality for responses and events.
+ *
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @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 <settingsd/send_callback.hpp>
+#include <settingsd/glib_traits.hpp>
+#include <settingsd/json_glib_traits.hpp>
+#include <settingsd/smart_ptr.hpp>
+
+#include <cstring>
+#include <vector>
+#include <algorithm>
+
+
+ivi::settings::send_callback::send_callback(libwebsocket * wsi)
+ : wsi_(wsi)
+{
+}
+
+ivi::settings::send_callback::send_callback(
+ send_callback const & other)
+ : wsi_(other.wsi_)
+{
+}
+
+ivi::settings::send_callback &
+ivi::settings::send_callback::operator=(send_callback const & other)
+{
+ wsi_ = other.wsi_;
+
+ return *this;
+}
+
+bool
+ivi::settings::send_callback::send_payload(
+ char const * send_type,
+ smart_ptr<JsonBuilder> const & builder)
+{
+ smart_ptr<JsonGenerator> const generator(json_generator_new());
+ smart_ptr<JsonNode> 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<gchar> 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<unsigned char> 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:
clock.cpp \
ethernet.cpp \
wifi.cpp \
- registration.cpp
+ registration.cpp \
+ signal_callback.cpp
connman_la_CXXFLAGS = \
$(IVI_SETTINGS_PLUGIN_CXXFLAGS) \
$(GIO_CFLAGS) \
bluetooth.hpp \
clock.hpp \
ethernet.hpp \
- wifi.hpp
+ wifi.hpp \
+ signal_callback.hpp
// ----------------------------------------------------------------------
-ivi::settings::bluetooth::bluetooth()
- : technology_(technology_name)
+ivi::settings::bluetooth::bluetooth(event_callback const & e)
+ : technology_(technology_name, e)
{
}
public:
/// Constructor.
- bluetooth();
+ bluetooth(event_callback const & e);
/// Destructor.
virtual ~bluetooth();
#include <boost/lexical_cast.hpp>
-ivi::settings::clock::clock()
- : connman_("net.connman.Clock", "/")
+ivi::settings::clock::clock(event_callback const & e)
+ : connman_("net.connman.Clock", "/", e)
{
}
bool
ivi::settings::clock::set_property(char const * name,
GVariant * value,
- response_callback response,
+ response_callback /* response */,
GError *& error)
{
- bool success = false;
-
- // Get notified when the clock property has changed.
- auto property_promise = connman_.get_property_changed_promise(name);
- auto property_future = property_promise->get_future();
-
smart_ptr<GVariant> const ret(
connman_.set_property(name, value, error));
- if (ret != nullptr) {
- static int const timeout = 5000; // milliseconds
-
- // Block until the clock property has changed..
- std::future_status const status =
- property_future.wait_for(std::chrono::milliseconds(timeout));
-
- if (status == std::future_status::ready) {
- smart_ptr<GVariant> const value(property_future.get());
- success = true;
- } else {
- response.send_error(
- std::string("Wait for clock property \"")
- + name + "\" set failed: "
- + (status == std::future_status::timeout
- ? "timeout"
- : "deferred"));
- }
- }
-
- return success;
+ return ret.get() != nullptr;
}
GVariant *
public:
/// Constructor.
- clock();
+ clock(event_callback const & e);
/// Destructor.
virtual ~clock();
*/
#include "connman.hpp"
+#include "signal_callback.hpp"
#include <settingsd/reverse_lock.hpp>
#include <stdexcept>
-namespace
-{
- void
- on_property_changed(GDBusConnection * /* connection */,
- char const * /* sender_name */,
- char const * /* object_path */,
- char const * /* interface_name */,
- char const * /* signal_name */,
- GVariant * parameters,
- gpointer user_data)
- {
- // Notify callers about the scan results.
- typedef ivi::settings::connman::user_data user_data_type;
-
- user_data_type * const data = static_cast<user_data_type *>(user_data);
-
- std::lock_guard<std::mutex> lock(data->mutex);
- auto const end = data->promises.end();
- for (auto i = data->promises.begin(); i != end; ) {
- gchar * pname = nullptr;
- GVariant * pvalue = nullptr;
-
- g_variant_get(parameters, "(sv)", &pname, &pvalue);
-
- using namespace ivi::settings;
-
- smart_ptr<gchar> name(pname);
- smart_ptr<GVariant> value(pvalue);
-
- auto & p = *i;
-
- // Set the value in the promise if the desired property name
- // matches.
- if (strcmp(p.first, pname) == 0) {
- {
- // Release the mutex during the promise::set_value()
- // call/notification so that we don't unnecessarily block
- // threads attempting to get a property_changed promise.
- typedef ivi::settings::reverse_lock<std::mutex> reverse_lock;
- reverse_lock reverse(data->mutex);
-
- std::lock_guard<reverse_lock> kcol(reverse);
-
- p.second->set_value(std::move(value));
- }
-
- // Done with the pointer to the promise. Remove it from the
- // list now since we already have an iterator to it.
- i = data->promises.erase(i);
- } else {
- // Nothing to erase. Advance to the next list element.
- ++i;
- }
- }
- }
-}
-
-// ---------------------------------------------------------------
-
ivi::settings::connman::connman(char const * interface,
- char const * path)
+ char const * path,
+ event_callback const & e)
: proxy_(nullptr)
- , mutex_()
- , promises_()
- , data_(mutex_, promises_)
+ , event_callback_(e)
, subscription_id_(0)
{
static char const name[] = "net.connman"; // Service
path,
nullptr,
G_DBUS_SIGNAL_FLAGS_NONE,
- on_property_changed,
- &data_,
+ on_connman_signal,
+ &event_callback_,
nullptr);
}
&error);
}
-ivi::settings::connman::shared_promise_type
-ivi::settings::connman::get_property_changed_promise(
- char const * property)
-{
- // This promise must exist long enough for the value to retrieved
- // from the future. Use a shared_ptr<> to make that possible.
- shared_promise_type promise = std::make_shared<promise_type>();
-
- {
- std::lock_guard<std::mutex> lock(mutex_);
-
- // Add a new std::promise to the promises list. The promise will
- // only be used once, and will be removed once its value has been
- // set.
- promises_.push_back(std::make_pair(property, promise));
- }
-
- return promise;
-}
-
// Local Variables:
// mode:c++
#include <settingsd/glib_traits.hpp>
#include <settingsd/smart_ptr.hpp>
+#include <settingsd/event_callback.hpp>
#include <gio/gio.h>
-#include <future>
-#include <utility>
-#include <list>
-#include <memory>
-
namespace ivi
{
* @param[in] path Connman D-Bus object path.
*/
connman(char const * interface,
- char const * path);
+ char const * path,
+ event_callback const & e);
/// Destructor.
~connman();
- /// The type held by the @c future containing the async result.
- typedef smart_ptr<GVariant> future_value_type;
-
- /// The @c future type returned by the @c promise.
- typedef std::future<future_value_type> future_type;
-
- /// The @c promise that provides the async result.
- typedef std::promise<future_value_type> promise_type;
-
- /**
- * Smart pointer to the @c promise that provides the async
- * result.
- */
- typedef std::shared_ptr<promise_type> shared_promise_type;
-
- /**
- * Property Name/value pair type held by the @c future
- * containing the async result. Both values will be populated
- * when retrieving the value from the @c PropertyChanged
- * signal.
- *
- * @note The property name is meant for internal use.
- */
- typedef std::pair<char const *,
- shared_promise_type> promise_value_type;
-
- /// List type for promises to be updated with async result.
- typedef std::list<promise_value_type> promise_list_type;
-
/**
* Set @a property to given @a value on the underlying connman
* object.
GVariant * value,
GError *& error);
- /**
- * Get a promise that will contain the changed connman property
- * when it becomes available. The user must obtain the value
- * from the corresponding future object.
- */
- shared_promise_type get_property_changed_promise(
- char const * property);
-
/// Get pointer to underlying GDBusProxy.
GDBusProxy * proxy() const { return proxy_; }
return g_dbus_proxy_get_object_path(proxy_);
}
- /**
- * @struct user_data
- *
- * @brief Struct passed to @c ServicesChanged signal handler.
- */
- struct user_data
- {
- /// Constructor.
- user_data(std::mutex & m, promise_list_type & p)
- : mutex(m)
- , promises(p)
- {
- }
-
- /**
- * References to mutex used to synchronize access to the list
- * of promises.
- */
- std::mutex & mutex;
-
- /// List of promises to be updated with the changed services.
- promise_list_type & promises;
- };
-
private:
/// The proxy used to access the Connman D-Bus API.
GDBusProxy * proxy_;
- /// Mutex used to synchronize access to the promises list.
- std::mutex mutex_;
-
- /**
- * List of promises that will be updated with the
- * PropertyChanged signal results.
- */
- promise_list_type promises_;
-
- /// User data passed to @c PropertyChanged signal handler.
- user_data data_;
+ /// Callback through which events will be sent to clients.
+ event_callback event_callback_;
/// PropertyChanged signal subscription ID.
guint subscription_id_;
/**
* @file connman_manager.cpp
*
- * @brief Connman_Manager-based settings plugin.
+ * @brief Connman Manager operations.
*
* @author Ossama Othman @<ossama.othman@@intel.com@>
*
*/
#include "connman_manager.hpp"
+#include "signal_callback.hpp"
-#include <settingsd/json_glib_traits.hpp>
-#include <settingsd/reverse_lock.hpp>
+#include <settingsd/glib_traits.hpp>
+#include <settingsd/smart_ptr.hpp>
#include <cstring>
-namespace
-{
- void
- on_services_changed(GDBusConnection * /* connection */,
- char const * /* sender_name */,
- char const * /* object_path */,
- char const * /* interface_name */,
- char const * /* signal_name */,
- GVariant * parameters,
- gpointer user_data)
- {
- gsize const num_params = g_variant_n_children(parameters);
- if (num_params != 2) {
- // We should never get here!
- g_printerr("Number of ServicesChanged signal parameters "
- "is not 2: %" G_GSIZE_FORMAT "\n",
- num_params);
-
- return;
- }
-
- using namespace ivi::settings;
-
- // Changed services are found in the first ServicesChanged
- // argument.
- smart_ptr<GVariant> const changed_services(
- g_variant_get_child_value(parameters, 0));
-
- // Serialize the changed services into a JSON tree. This will be
- // an array of [object, dict], where "object" is the D-Bus object
- // path, and "dict" is a dictionary of object-specific
- // properties.
- smart_ptr<JsonNode> services(
- json_gvariant_serialize(changed_services.get()));
-
- // Notify callers about the scan results.
- typedef connman_manager::user_data user_data_type;
-
- user_data_type * const p = static_cast<user_data_type *>(user_data);
- connman_manager::promise_list_type & promises = p->promises;
-
- // Synchronize access to the promises list.
- std::lock_guard<std::mutex> lock(p->mutex);
-
- // Note that the end() iterator must be retrieved during each loop
- // iteration in case another thread caused another promise to be
- // added to the list when the lock was temporarily unlocked during
- // the promise::set_value() call below.
- for (auto i = promises.begin(); i != promises.end(); ) {
- auto & promise = *i;
-
- {
- // Release the mutex during the promise::set_value()
- // call/notification so that we don't unnecessarily block
- // threads attempting to get a services_changed promise.
- typedef ivi::settings::reverse_lock<std::mutex> reverse_lock;
- reverse_lock reverse(p->mutex);
-
- std::lock_guard<reverse_lock> kcol(reverse);
-
- // Thread that owns the corresponding future must transfer
- // ownership of the JsonNode to something that will release
- // the underlying JsonNode, e.g. a JsonBuilder via
- // json_builder_add_value() or another smart_ptr<JsonNode>.
- promise->set_value(std::move(services));
- }
-
- // Done with the pointer to the promise. Remove it from the
- // list now since we already have an iterator to it.
- i = promises.erase(i);
- }
- }
-
-}
-
-// ---------------------------------------------------------------
-
-ivi::settings::connman_manager::connman_manager()
+ivi::settings::connman_manager::connman_manager(
+ event_callback const & e)
: connman_("net.connman.Manager", // Interface
- "/") // Object path
- , mutex_()
- , promises_()
- , data_(mutex_, promises_)
+ "/", // Object path
+ e)
+ , event_callback_(e)
, subscription_id_(
g_dbus_connection_signal_subscribe(
g_dbus_proxy_get_connection(G_DBUS_PROXY(connman_.proxy())),
connman_.object_path(),
nullptr,
G_DBUS_SIGNAL_FLAGS_NONE,
- on_services_changed,
- &data_,
+ on_connman_signal,
+ &event_callback_,
nullptr))
{
}
&error);
}
-ivi::settings::connman_manager::shared_promise_type
-ivi::settings::connman_manager::get_services_changed_promise()
-{
- // This promise must exist long enough for the value to retrieved
- // from the future. Use a shared_ptr<> to make that possible.
- shared_promise_type p = std::make_shared<promise_type>();
-
- {
- std::lock_guard<std::mutex> lock(mutex_);
-
- // Add a new std::promise to the promises list. The promise will
- // only be used once, and will be removed once its value has been
- // set.
- promises_.push_back(p);
- }
-
- return p;
-}
-
// Local Variables:
// mode:c++
#include "connman.hpp"
-#include <settingsd/glib_traits.hpp>
-#include <settingsd/smart_ptr.hpp>
+#include <settingsd/event_callback.hpp>
#include <gio/gio.h>
-#include <json-glib/json-glib.h>
-#include <future>
-#include <list>
-#include <memory>
+#include <string>
namespace ivi
public:
/// Constructor.
- connman_manager();
+ connman_manager(event_callback const & e);
/// Destructor.
~connman_manager();
*/
GVariant * get_services(GError *& error) const;
- /// The type held by the @c future containing the async result.
- typedef smart_ptr<JsonNode> future_value_type;
-
- /// The @c future type returned by the @c promise.
- typedef std::future<future_value_type> future_type;
-
- /// The @c promise that provides the async result.
- typedef std::promise<future_value_type> promise_type;
-
- /**
- * Smart pointer to the @c promise that provides the async
- * result.
- */
- typedef std::shared_ptr<promise_type> shared_promise_type;
-
- /// List type for promises to be updated with async result.
- typedef std::list<shared_promise_type> promise_list_type;
-
- /**
- * Get a promise that will contain changed connman services when
- * they become available. The user must obtain the value from
- * the corresponding future object and release the @c JsonNode*
- * value contained within that future with @c json_node_free().
- */
- shared_promise_type get_services_changed_promise();
-
- /**
- * @struct user_data
- *
- * @brief Struct passed to @c ServicesChanged signal handler.
- */
- struct user_data
- {
- /// Constructor.
- user_data(std::mutex & m, promise_list_type & p)
- : mutex(m)
- , promises(p)
- {
- }
-
- /**
- * References to mutex used to synchronize access to the list
- * of promises.
- */
- std::mutex & mutex;
-
- /// List of promises to be updated with the changed services.
- promise_list_type & promises;
- };
-
private:
/// The proxy used to access the connman Manager D-Bus API.
connman connman_;
- /// Mutex used to synchronize access to the promises list.
- std::mutex mutex_;
-
- /**
- * List of promises that will be updated with the
- * ServicesChanged signal results.
- */
- promise_list_type promises_;
-
- /// User data passed to @c ServicesChanged signal handler.
- user_data data_;
+ /// Callback through which events will be sent to clients.
+ event_callback event_callback_;
/// ServicesChanged signal subscription ID.
guint const subscription_id_;
// ----------------------------------------------------------------------
-ivi::settings::ethernet::ethernet()
- : technology_(technology_name)
+ivi::settings::ethernet::ethernet(event_callback const & e)
+ : technology_(technology_name, e)
{
}
public:
/// Constructor.
- ethernet();
+ ethernet(event_callback const & e);
/// Destructor.
virtual ~ethernet();
#include <memory>
+namespace ivi
+{
+ namespace settings
+ {
+ class event_callback;
+ }
+}
+
/// Plugin factory/registration function.
extern "C" IVI_SETTINGS_CONNMAN_API bool
-register_settings(ivi::settings::registrar & r)
+register_settings(ivi::settings::registrar & r,
+ ivi::settings::event_callback const & e)
{
std::unique_ptr<ivi::settings::plugin> bt(
- new ivi::settings::bluetooth);
+ new ivi::settings::bluetooth(e));
std::unique_ptr<ivi::settings::plugin> clk(
- new ivi::settings::clock);
+ new ivi::settings::clock(e));
std::unique_ptr<ivi::settings::plugin> eth(
- new ivi::settings::ethernet);
+ new ivi::settings::ethernet(e));
std::unique_ptr<ivi::settings::plugin> wifi(
- new ivi::settings::wifi);
+ new ivi::settings::wifi(e));
return
r.register_setting(std::move(bt))
#include <chrono>
-ivi::settings::service::service(std::string service_path)
+ivi::settings::service::service(std::string service_path,
+ event_callback const & e)
: connman_("net.connman.Service", // Interface
- service_path.c_str()) // Object path
+ service_path.c_str(), // Object path
+ e)
{
}
*
* @param[in] service_path The D-Bus object path for connman
* service.
+ * @param[in] e Callback through which events will be
+ * sent to clients.
*/
- service(std::string service_path);
+ service(std::string service_path,
+ event_callback const & e);
/// Connect to the service.
void connect(response_callback response);
--- /dev/null
+/**
+ * @file signal_callback.cpp
+ *
+ * @brief Connman signal callback.
+ *
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @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 "signal_callback.hpp"
+
+#include <settingsd/event_callback.hpp>
+
+#include <json-glib/json-glib.h>
+
+
+void
+on_connman_signal(GDBusConnection * /* connection */,
+ char const * /* sender_name */,
+ char const * object_path,
+ char const * interface_name,
+ char const * signal_name,
+ GVariant * parameters,
+ gpointer user_data)
+{
+ using ivi::settings::event_callback;
+ event_callback * const e = static_cast<event_callback *>(user_data);
+
+ // Send event to clients.
+
+ /**
+ * @todo Fix type == nullptr.
+ */
+ e->send_event(
+ object_path,
+ interface_name,
+ signal_name,
+ [parameters](JsonBuilder * builder)
+ {
+ // Serialize the changed services into a JSON tree.
+ // The ServicesChanged signal parameters are:
+ //
+ // array{object, dict}, array{object})
+ //
+ // where "object" is the D-Bus object path, and "dict" is a
+ // dictionary of object-specific properties. The first
+ // parameter is list of changed services. The second is a
+ // list of removed services.
+
+ /**
+ * @todo Can @c json_gvariant_serialize() ever return a
+ * @c nullptr?
+ */
+ JsonNode * const services = json_gvariant_serialize(parameters);
+
+ json_builder_set_member_name(builder, "value");
+ json_builder_add_value(builder, services);
+
+ // No need to free the JsonNode. The builder will take
+ // ownership of it.
+ });
+}
+
+
+// Local Variables:
+// mode:c++
+// c-basic-offset:2
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/**
+ * @file signal_callback.hpp
+ *
+ * @brief Connman signal callback.
+ *
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @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_CONNMAN_SIGNAL_CALLBACK_HPP
+#define IVI_SETTINGS_CONNMAN_SIGNAL_CALLBACK_HPP
+
+#include <gio/gio.h>
+
+
+extern "C"
+void on_connman_signal(GDBusConnection * connection,
+ char const * sender_name,
+ char const * object_path,
+ char const * interface_name,
+ char const * signal_name,
+ GVariant * parameters,
+ gpointer user_data);
+
+#endif /* IVI_SETTINGS_CONNMAN_SIGNAL_CALLBACK_HPP */
+
+
+// Local Variables:
+// mode:c++
+// c-basic-offset:2
+// indent-tabs-mode: nil
+// End:
#include <chrono>
-ivi::settings::technology::technology(std::string tech)
+ivi::settings::technology::technology(std::string tech,
+ event_callback const & e)
: connman_("net.connman.Technology", // Interface
("/net/connman/technology/"
- + tech).c_str()) // Object path
- , manager_()
+ + tech).c_str(), // Object path
+ e)
+ , manager_(e)
, technology_(tech)
+ , event_callback_(e)
{
}
constexpr char const name[] = "Powered";
- // Get notified when the technology property has changed.
- auto property_promise = connman_.get_property_changed_promise(name);
- auto property_future = property_promise->get_future();
-
GError * error = nullptr;
smart_ptr<GVariant> ret(
smart_ptr<GError> safe_error(error);
if (ret != nullptr) {
- constexpr int const timeout = 5000; // milliseconds
-
- // Block until the technology property has changed..
- std::future_status const status =
- property_future.wait_for(std::chrono::milliseconds(timeout));
-
- if (status == std::future_status::ready) {
-
// Nothing to add to successful response.
response.send_response(
[](JsonBuilder * /* builder */) {});
-
- } else {
-
- response.send_error(
- std::string("Wait for enable status failed: ")
- + (status == std::future_status::timeout
- ? "timeout"
- : "deferred"));
-
- }
} else if (error != nullptr) {
response.send_error(
"Unable to set " + technology_ + " powered state: "
return;
}
- // Get notified when scan results are available.
- auto services_promise = manager_.get_services_changed_promise();
- auto services_future = services_promise->get_future();
-
// The scan could take a while.
constexpr gint const timeout = 10000; // milliseconds
GError * error = nullptr;
smart_ptr<GError> safe_error(error);
if (ret != nullptr) {
- constexpr gint const future_timeout = 5000; // milliseconds
-
- // Block until the scan results are in.
- std::future_status const status =
- services_future.wait_for(std::chrono::milliseconds(future_timeout));
-
- if (status != std::future_status::deferred) {
- // Don't call get() if the future isn't ready. Otherwise this
- // will be a blocking call.
- if (status == std::future_status::ready) {
- smart_ptr<JsonNode> const changed_services(services_future.get());
- }
-
- send_services(response, error);
-
- // A timeout is okay since some services may not have changed
- // within the timeout period but log it just in case.
- if (status == std::future_status::timeout)
- g_debug("%s settings: Timed out waiting for changed services.\n",
- technology_.c_str());
- } else {
- // We only get here if the future status is
- // std::future_status::deferred, meaning the result hasn't been
- // determined yet. That should never happen in our case.
- response.send_error("Wait for scan results failed: deferred");
- }
+ send_services(response, error);
} else if (error != nullptr) {
response.send_error(
"Unable to scan " + technology_ + ": "
/// @todo Refactor malformed JSON request handling code.
if (service_path != nullptr) {
- service s(service_path);
+ service s(service_path, event_callback_);
s.connect(response);
} else {
response.send_error(
json_reader_end_member(reader);
if (service_path != nullptr) {
- service s(service_path);
+ service s(service_path, event_callback_);
s.disconnect(response);
} else {
response.send_error(
* Constructor.
*
* @param[in] tech The connman technology, e.g. "bluetooth".
+ * @param[in] e Callback through which events will be sent to
+ * clients.
*/
- technology(std::string tech);
+ technology(std::string tech,
+ event_callback const & e);
/// Handle requests common to all connman technologies.
void handle_request(std::string request,
/// The proxy used to access the connman Technology D-Bus API.
connman connman_;
- /// The proxy used to access the connman Manager D-Bus API.
+ /**
+ * The proxy used to access the connman Manager D-Bus API.
+ *
+ * @todo There is no point in making this @c connman_manager
+ * instance technology-specific since it is really a
+ * connman global object.
+ */
connman_manager manager_;
/// Technology name, e.g. "bluetooth" or "wifi".
std::string const technology_;
+ /// Callback through which events will be sent to clients.
+ event_callback event_callback_;
+
};
}
// ----------------------------------------------------------------------
-ivi::settings::wifi::wifi()
- : technology_(technology_name)
+ivi::settings::wifi::wifi(event_callback const & e)
+ : technology_(technology_name, e)
{
}
public:
/// Constructor.
- wifi();
+ wifi(event_callback const & e);
/// Destructor.
virtual ~wifi();
libwebsocket_context_user(context));
switch(reason) {
+ case LWS_CALLBACK_ESTABLISHED:
+ // Enable event dispatching to client.
+ mgr->subscribe_client(wsi);
+ break;
+
+ case LWS_CALLBACK_CLOSED:
+ // Disable event dispatching to client.
+ mgr->unsubscribe_client(wsi);
+ break;
+
case LWS_CALLBACK_RECEIVE:
// Request has come in from Settings app. Pass it on to the
// settings manager.