[manager] Return immediately on empty request.
[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/smart_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 {
44   load_settings(dir);
45 }
46
47 ivi::settings::manager::~manager()
48 {
49 }
50
51 bool
52 ivi::settings::manager::register_setting(std::unique_ptr<plugin> p)
53 {
54   std::string const & id = p->id();
55
56   auto const result =
57     settings_.insert(std::make_pair(id, std::move(p)));
58
59   if (!result.second)
60     std::cerr << "Settings plugin registration for \""
61               << id << "\" failed." << std::endl;
62
63   return result.second;
64 }
65
66 void
67 ivi::settings::manager::load_settings(std::string const & dir)
68 {
69   if (dir.length() == 0)
70     throw std::logic_error("Zero length settings plugin directory path.");
71
72   namespace fs = boost::filesystem;
73
74   // Find all settings plugins in the plugin directory.
75   fs::path settings_dir(dir);
76
77   if (fs::is_directory(settings_dir)) {
78     // Iterate over directory entries, create settings instances
79     // for each settings plugin, and store in settings map.
80
81     fs::directory_iterator const end;
82     for (fs::directory_iterator i(settings_dir); i != end; ++i) {
83       try {
84         fs::path const & plugin_path = (*i).path();
85
86         // Verify that the plugin is actually a file with the
87         // appropriate extension (e.g. ".so").
88         //
89         // Note that the .extension() method returns a string like
90         // ".so" whereas G_MODULE_SUFFIX is preprocessor symbol/string
91         // like "so".  We prepend a period to G_MODULE_SUFFIX using
92         // standard string literal concatenation.
93         if (!fs::is_regular_file(plugin_path)
94             || plugin_path.extension() != "." G_MODULE_SUFFIX)
95           continue;
96
97         std::string const & plugin_name = plugin_path.string();
98
99         std::unique_ptr<loader> plugin(new loader(plugin_name, *this));
100
101         loaders_.push_back(std::move(plugin));
102       }
103       catch (std::logic_error & e) {
104         /**
105          * @todo I really hate catching an exception like this, but I
106          *       really don't want to resort to a construct/init()
107          *       style of object initialization.  Fix.
108          */
109         std::cerr << "Error loading plugin: " << e.what() << "\n";
110       }
111     }
112
113     if (settings_.size() == 0) {
114       std::cerr << "Settings plugin directory \""
115                 << dir << "\" has no plugins.\n";
116     } else {
117       std::cerr << "Registered settings plugins: \n";
118       for (auto const & i : settings_)
119         std::cerr << "\t" << i.first << '\n';
120     }
121   } else {
122     std::cerr << "Settings plugin directory \""
123               << dir << "\" does not exist.\n";
124   }
125 }
126
127 void
128 ivi::settings::manager::dispatch(std::string request,
129                                  struct libwebsocket * wsi)
130 {
131   if (request.empty()) {
132     response_callback response(wsi, std::string(), std::string());
133     response.send_error("Empty settings request.");
134     return;
135   }
136
137   smart_ptr<JsonParser> const parser(json_parser_new());
138   json_parser_load_from_data(parser.get(), request.c_str(), -1, nullptr);
139
140   JsonReader * const reader = json_reader_new(json_parser_get_root(parser.get()));
141   smart_ptr<JsonReader> const safe_reader(reader);
142
143   // Retrieve setting name and transcation ID from the JSON request
144   // string.
145   char const * type = nullptr;
146   if (json_reader_read_member(reader, "type")) {
147     type = json_reader_get_string_value(reader);
148   }
149   json_reader_end_member(reader);
150
151   /**
152    * @todo Allow transaction ID to be null?
153    */
154   char const * transaction_id = "";
155   if (json_reader_read_member(reader, "transactionid")) {
156     transaction_id = json_reader_get_string_value(reader);
157   }
158   json_reader_end_member(reader);
159
160   response_callback response(wsi,
161                              type == nullptr ? "" : type,
162                              transaction_id);
163
164   std::string error;
165   if (type != nullptr) {
166     // Dispatch the request to the corresponding settings plugin.
167     auto i = settings_.find(type);
168     if (i != settings_.end())
169       (*i).second->handle_request(request, response);
170     else {
171       error =
172         std::string("Settings type \"")
173         + type + "\" not supported.";
174
175       response.send_error(error);
176     }
177   } else {
178     error =
179       "Settings type not specified in request.\n"
180       "Supported plugins:\n";
181
182     for (auto const & i : settings_)
183       error += "\t" + i.first + "\n";
184
185     response.send_error(error);
186   }
187 }
188
189
190 // Local Variables:
191 // mode:c++
192 // c-basic-offset:2
193 // indent-tabs-mode: nil
194 // End: