"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"
+ ]
+ ]
+ }
#include <settingsd/settings_api.hpp>
#include <settingsd/send_callback.hpp>
-#include <string>
#include <functional>
namespace settings
{
template<typename T> class smart_ptr;
+ class manager;
/**
* @class event_callback event_callback.hpp <settingsd/event_callback.hpp>
public:
/// Constructor
- event_callback(libwebsocket * wsi);
+ event_callback(manager & m);
/**
* Send event to Settings app.
* 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(
- std::string const & type,
+ char const * object_path,
+ char const * interface_name,
+ char const * event_name,
std::function<void(JsonBuilder *)> event_builder);
private:
*
* The appropriate "header" information will be prepended to the
* event.
- *
- * @param[in] result @c "succeeded" or @c "failed"
*/
- smart_ptr<JsonBuilder> begin_event(std::string const & type);
+ 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.
private:
- /// Object used to send event to client over WebSocket.
- send_callback writer_;
+ /**
+ * Settings manager used to send event to clients over
+ * corresponding WebSockets.
+ */
+ manager & manager_;
};
std::string type,
std::string transaction_id);
+ /// Copy constructor
+ response_callback(response_callback const & other);
+
/**
* Send (successful) response to Settings app.
*
/// 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.
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 * const wsi_;
+ libwebsocket * wsi_;
};
## Boston, MA 02110-1301 USA
## ---------------------------------------------------------
-## settings plugin library
+## settingsd plugin library
## ---------------------------------------------------------
lib_LTLIBRARIES = libsettings.la
#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(libwebsocket * wsi)
- : writer_(wsi)
+ivi::settings::event_callback::event_callback(manager & mgr)
+ : manager_(mgr)
{
}
bool
ivi::settings::event_callback::send_event(
- std::string const & type,
+ 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(type);
+ 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 = writer_.send_payload("event", builder);
+ bool const success = manager_.send_event(builder);
if (!success)
- g_critical("Unable to send %s event", type.c_str());
+ g_critical("Unable to send %s event", event_name);
return success;
}
ivi::settings::smart_ptr<JsonBuilder>
-ivi::settings::event_callback::begin_event(std::string const & type)
+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());
json_builder_begin_object(builder);
- json_builder_set_member_name(builder, "type");
- if (type.empty())
+ 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, type.c_str());
+ 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;
}
#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::subscribe_client(libwebsocket * wsi)
{
- clients_.push_back(wsi);
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ send_callbacks_.emplace_back(wsi);
}
void
ivi::settings::manager::unsubscribe_client(libwebsocket * wsi)
{
- auto const end = clients_.end();
- for (auto i = clients_.begin; i != end; ++i)
+ 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)
- clients_.erase(i);
+ 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;
}
#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 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<libwebsocket *> clients_;
+ std::vector<send_callback> send_callbacks_;
};
{
}
+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)
{
}
+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,
- ivi::settings::smart_ptr<JsonBuilder> const & builder)
+ smart_ptr<JsonBuilder> const & builder)
{
smart_ptr<JsonGenerator> const generator(json_generator_new());
smart_ptr<JsonNode> const root(json_builder_get_root(builder.get()));
}
-
// Local Variables:
// mode:c++
// c-basic-offset:2
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();
switch(reason) {
case LWS_CALLBACK_ESTABLISHED:
// Enable event dispatching to client.
- manager->subscribe_client(wsi);
+ mgr->subscribe_client(wsi);
break;
case LWS_CALLBACK_CLOSED:
// Disable event dispatching to client.
- manager->unsubscribe_client(wsi);
+ mgr->unsubscribe_client(wsi);
break;
case LWS_CALLBACK_RECEIVE: