Added API for enabling tethering
[profile/ivi/settings-daemon.git] / lib / manager.cpp
1 /**
2  * @file manager.cpp
3  *
4  * @brief Settings manager implementation.
5  *
6  * @author Ossama Othman @<ossama.othman@@intel.com@>
7  *
8  * @copyright @par
9  * Copyright 2012, 2013 Intel Corporation All Rights Reserved.
10  * @par
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation;
14  * version 2.1 of the License.
15  * @par
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  * @par
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA  02110-1301  USA
25  */
26
27
28 #include "config.hpp"
29 #include "manager.hpp"
30 #include <settingsd/plugin.hpp>
31 #include <settingsd/response_callback.hpp>
32 #include <settingsd/json_glib_traits.hpp>
33 #include <settingsd/unique_ptr.hpp>
34
35 #include <gmodule.h>
36
37 #include <boost/filesystem.hpp>
38
39
40 ivi::settings::manager::manager(std::string const & dir)
41   : loaders_()
42   , settings_()
43   , mutex_()
44   , send_callbacks_()
45 {
46   load_settings(dir);
47 }
48
49 ivi::settings::manager::~manager()
50 {
51 }
52
53 bool
54 ivi::settings::manager::register_setting(std::unique_ptr<plugin> p)
55 {
56   std::string const & id = p->id();
57
58   auto const result =
59     settings_.insert(std::make_pair(id, std::move(p)));
60
61   if (!result.second)
62     std::cerr << "Settings plugin registration for \""
63               << id << "\" failed." << std::endl;
64
65   return result.second;
66 }
67
68 void
69 ivi::settings::manager::load_settings(std::string const & dir)
70 {
71   if (dir.length() == 0)
72     throw std::invalid_argument("Zero length settings plugin "
73                                 "directory path.");
74
75   namespace fs = boost::filesystem;
76
77   // Find all settings plugins in the plugin directory.
78   fs::path settings_dir(dir);
79
80   if (fs::is_directory(settings_dir)) {
81     // Iterate over directory entries, create settings instances
82     // for each settings plugin, and store in settings map.
83
84     fs::directory_iterator const end;
85     for (fs::directory_iterator i(settings_dir); i != end; ++i) {
86       try {
87         fs::path const & plugin_path = (*i).path();
88
89         // Verify that the plugin is actually a file with the
90         // appropriate extension (e.g. ".so").
91         //
92         // Note that the .extension() method returns a string like
93         // ".so" whereas G_MODULE_SUFFIX is preprocessor symbol/string
94         // like "so".  We prepend a period to G_MODULE_SUFFIX using
95         // standard string literal concatenation.
96         if (!fs::is_regular_file(plugin_path)
97             || plugin_path.extension() != "." G_MODULE_SUFFIX)
98           continue;
99
100         std::string const & plugin_name = plugin_path.string();
101
102         std::unique_ptr<loader> plugin(new loader(plugin_name, *this));
103
104         loaders_.push_back(std::move(plugin));
105       }
106       catch (std::exception & e) {
107         /**
108          * @todo I really hate catching an exception like this, but I
109          *       really don't want to resort to a construct/init()
110          *       style of object initialization.  Fix.
111          */
112         std::cerr << "Error loading plugin: " << e.what() << "\n";
113       }
114       catch (...) {
115         std::cerr << "Ignoring unknown exception thrown from plugin.\n";
116       }
117     }
118
119     if (settings_.size() == 0) {
120       throw std::invalid_argument("Settings plugin directory \""
121                                   + dir + "\" has no plugins.");
122     } else {
123       std::cerr << "Registered settings plugins:\n";
124       for (auto const & i : settings_)
125         std::cerr << "\t" << i.first << '\n';
126     }
127   } else {
128     throw std::invalid_argument("Settings plugin directory \""
129                                 + dir + "\" does not exist.");
130   }
131 }
132
133 void
134 ivi::settings::manager::dispatch(std::string request,
135                                  libwebsocket * wsi)
136 {
137   if (request.empty()) {
138     response_callback response(wsi, std::string(), std::string());
139     response.send_error("Empty settings request.");
140     return;
141   }
142
143   unique_ptr<JsonParser> const parser(json_parser_new());
144   json_parser_load_from_data(parser.get(), request.c_str(), -1, nullptr);
145
146   JsonReader * const reader =
147     json_reader_new(json_parser_get_root(parser.get()));
148   unique_ptr<JsonReader> const safe_reader(reader);
149
150   // Retrieve setting name and transcation ID from the JSON request
151   // string.
152   char const * type = nullptr;
153   if (json_reader_read_member(reader, "type")) {
154     type = json_reader_get_string_value(reader);
155   }
156   json_reader_end_member(reader);
157
158   /**
159    * @todo Allow transaction ID to be null?
160    */
161   char const * transaction_id = "";
162   if (json_reader_read_member(reader, "transactionid")) {
163     transaction_id = json_reader_get_string_value(reader);
164   }
165   json_reader_end_member(reader);
166
167   response_callback response(wsi,
168                              type == nullptr ? "" : type,
169                              transaction_id);
170
171   std::string error;
172   if (type != nullptr) {
173     // Dispatch the request to the corresponding settings plugin.
174     auto i = settings_.find(type);
175     if (i != settings_.end())
176       (*i).second->handle_request(request, response);
177     else {
178       error =
179         std::string("Settings type \"")
180         + type + "\" not supported.";
181
182       response.send_error(error);
183     }
184   } else {
185     error =
186       "Settings type not specified in request.\n"
187       "Supported plugins:\n";
188
189     for (auto const & i : settings_)
190       error += "\t" + i.first + "\n";
191
192     response.send_error(error);
193   }
194 }
195
196 void
197 ivi::settings::manager::subscribe_client(libwebsocket * wsi)
198 {
199   std::lock_guard<std::mutex> lock(mutex_);
200
201   send_callbacks_.emplace_back(wsi);
202 }
203
204 void
205 ivi::settings::manager::unsubscribe_client(libwebsocket * wsi)
206 {
207   std::lock_guard<std::mutex> lock(mutex_);
208
209   auto const end = send_callbacks_.end();
210   for (auto i = send_callbacks_.begin(); i != end; ++i)
211     if (*i == wsi)
212       send_callbacks_.erase(i);
213 }
214
215 bool
216 ivi::settings::manager::send_event(
217   unique_ptr<JsonBuilder> const & builder) const
218 {
219   bool success = true;
220
221   std::lock_guard<std::mutex> lock(mutex_);
222
223   for (auto c : send_callbacks_)
224     if (!c.send_payload("event", builder))
225       success = false;
226
227   return success;
228 }
229
230
231 // Local Variables:
232 // mode:c++
233 // c-basic-offset:2
234 // indent-tabs-mode: nil
235 // End: