~thomas-voss/location-service/fix-service-path

« back to all changes in this revision

Viewing changes to src/location_service/com/ubuntu/location/service/ichnaea_reporter.cpp

  • Committer: thomas-voss
  • Date: 2014-07-11 12:56:40 UTC
  • mto: This revision was merged to the branch mainline in revision 69.
  • Revision ID: thomas.voss@canonical.com-20140711125640-ef50ri8iotiqqb43
Switch to json-c for json parsing/generation purposes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 * Authored by: Thomas Voß <thomas.voss@canonical.com>
17
17
 */
18
18
 
 
19
#include <json/json.h>
 
20
 
19
21
#include <com/ubuntu/location/service/ichnaea_reporter.h>
20
22
 
21
23
#include <com/ubuntu/location/logging.h>
26
28
#include <core/net/http/response.h>
27
29
#include <core/net/http/status.h>
28
30
 
29
 
#include <json/json.h>
30
 
 
31
31
#include <thread>
32
32
 
33
 
namespace json = Json;
 
33
namespace json
 
34
{
 
35
Object Object::parse_from_string(const std::string& s)
 
36
{
 
37
    return Object{json_tokener_parse(s.c_str())};
 
38
}
 
39
 
 
40
Object Object::create_array()
 
41
{
 
42
    return Object{json_object_new_array()};
 
43
}
 
44
 
 
45
Object Object::create_object()
 
46
{
 
47
    return Object{json_object_new_object()};
 
48
}
 
49
 
 
50
Object::Object(json_object* object) : object(object)
 
51
{
 
52
}
 
53
 
 
54
Object::Object(const Object& rhs) : object(json_object_get(rhs.object))
 
55
{
 
56
}
 
57
 
 
58
Object::~Object()
 
59
{
 
60
    json_object_put(object);
 
61
}
 
62
 
 
63
Object& Object::operator=(const Object& rhs)
 
64
{
 
65
    json_object_put(object);
 
66
    object = json_object_get(rhs.object);
 
67
 
 
68
    return *this;
 
69
}
 
70
 
 
71
std::string Object::to_plain_string()
 
72
{
 
73
    return std::string
 
74
    {
 
75
        json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN)
 
76
    };
 
77
}
 
78
 
 
79
Object Object::get(const std::string& name) const
 
80
{
 
81
    json_object* result{nullptr};
 
82
 
 
83
    json_object_object_get_ex(object, name.c_str(), &result);
 
84
 
 
85
    if (not result) throw std::out_of_range
 
86
    {
 
87
        name.c_str()
 
88
    };
 
89
 
 
90
    return Object{result};
 
91
}
 
92
 
 
93
namespace
 
94
{
 
95
template<json_type type> void throw_if_type_mismatch(json_object* object)
 
96
{
 
97
    if (not json_object_is_type(object, type)) throw std::logic_error
 
98
    {
 
99
        "Type mismatch."
 
100
    };
 
101
}
 
102
}
 
103
// Attempts to resolve the object to a boolean value.
 
104
// Throws std::logic_error in case of type mismatches.
 
105
bool Object::to_bool() const
 
106
{
 
107
    throw_if_type_mismatch<json_type_boolean>(object);
 
108
    return json_object_get_boolean(object);
 
109
}
 
110
 
 
111
std::int32_t Object::to_int32() const
 
112
{
 
113
    throw_if_type_mismatch<json_type_int>(object);
 
114
    return json_object_get_int(object);
 
115
}
 
116
 
 
117
std::int64_t Object::to_int64() const
 
118
{
 
119
    throw_if_type_mismatch<json_type_int>(object);
 
120
    return json_object_get_int64(object);
 
121
}
 
122
 
 
123
double Object::to_double() const
 
124
{
 
125
    throw_if_type_mismatch<json_type_double>(object);
 
126
    return json_object_get_double(object);
 
127
}
 
128
 
 
129
std::string Object::to_string() const
 
130
{
 
131
    throw_if_type_mismatch<json_type_string>(object);
 
132
    return std::string{json_object_get_string(object)};
 
133
}
 
134
 
 
135
void Object::put_array(const std::string& name, Object array)
 
136
{
 
137
    json_object_object_add(object, name.c_str(), json_object_get(array.object));
 
138
}
 
139
 
 
140
void Object::put_object(const std::string& name, Object other)
 
141
{
 
142
    json_object_object_add(object, name.c_str(), json_object_get(other.object));
 
143
}
 
144
 
 
145
void Object::put_boolean(const std::string& name, bool value)
 
146
{
 
147
    json_object_object_add(object, name.c_str(), json_object_new_boolean(value));
 
148
}
 
149
 
 
150
void Object::put_int32(const std::string& name, std::int32_t value)
 
151
{
 
152
    json_object_object_add(object, name.c_str(), json_object_new_int(value));
 
153
}
 
154
 
 
155
void Object::put_int64(const std::string& name, std::int64_t value)
 
156
{
 
157
    json_object_object_add(object, name.c_str(), json_object_new_int64(value));
 
158
}
 
159
 
 
160
void Object::put_double(const std::string& name, double value)
 
161
{
 
162
    json_object_object_add(object, name.c_str(), json_object_new_double(value));
 
163
}
 
164
 
 
165
void Object::put_string(const std::string& name, const std::string& value)
 
166
{
 
167
    json_object_object_add(object, name.c_str(), json_object_new_string_len(value.c_str(), value.size()));
 
168
}
 
169
 
 
170
std::size_t Object::array_size() const
 
171
{
 
172
    throw_if_type_mismatch<json_type_array>(object);
 
173
    return json_object_array_length(object);
 
174
}
 
175
 
 
176
void Object::append(Object other)
 
177
{
 
178
    throw_if_type_mismatch<json_type_array>(object);
 
179
    json_object_array_add(object, json_object_get(other.object));
 
180
}
 
181
 
 
182
void Object::put_object_for_index(std::size_t index, Object other)
 
183
{
 
184
    throw_if_type_mismatch<json_type_array>(object);
 
185
    json_object_array_put_idx(object, index, json_object_get(other.object));
 
186
}
 
187
 
 
188
// Queries the object at index 'index'.
 
189
// Throws std::logic_error if the object does not represent an array.
 
190
// Throws std::out_of_range if the index exceeds the bounds of the array.
 
191
Object Object::get_object_for_index(std::size_t index)
 
192
{
 
193
    throw_if_type_mismatch<json_type_array>(object);
 
194
    return Object
 
195
    {
 
196
        json_object_get(json_object_array_get_idx(object, index))
 
197
    };
 
198
}
 
199
}
 
200
 
34
201
namespace location = com::ubuntu::location;
35
202
 
36
203
location::service::ichnaea::Reporter::Reporter(
79
246
        const std::vector<location::connectivity::WirelessNetwork::Ptr>& wifis,
80
247
        const std::vector<location::connectivity::RadioCell::Ptr>& cells)
81
248
{
82
 
    json::Value submit;
83
 
    json::Value item;
 
249
    json::Object submit = json::Object::create_object();
 
250
    json::Object items = json::Object::create_array();
 
251
    json::Object item = json::Object::create_object();
84
252
 
85
 
    item[Json::radio] = "gsm"; // We currently only support gsm radio types.
86
 
    item[Json::lat] = update.value.latitude.value.value();
87
 
    item[Json::lon] = update.value.longitude.value.value();
 
253
    item.put_string(Json::radio, "gsm"); // We currently only support gsm radio types.
 
254
    item.put_double(Json::lat, update.value.latitude.value.value());
 
255
    item.put_double(Json::lon, update.value.longitude.value.value());
88
256
 
89
257
    if (update.value.accuracy.horizontal)
90
 
        item[Json::accuracy] = (*update.value.accuracy.horizontal).value();
 
258
        item.put_double(Json::accuracy, (*update.value.accuracy.horizontal).value());
91
259
    if (update.value.altitude)
92
 
        item[Json::altitude] = (*update.value.altitude).value.value();
 
260
        item.put_double(Json::altitude, (*update.value.altitude).value.value());
93
261
    if (update.value.accuracy.vertical)
94
 
        item[Json::altitude_accuracy] = (*update.value.accuracy.vertical).value();
 
262
        item.put_double(Json::altitude_accuracy, (*update.value.accuracy.vertical).value());
95
263
 
96
264
    if (!wifis.empty())
97
 
        ichnaea::Reporter::convert_wifis_to_json(wifis, item[Json::wifi]);
 
265
    {
 
266
        json::Object w = json::Object::create_array();
 
267
        ichnaea::Reporter::convert_wifis_to_json(wifis, w);
 
268
        item.put_array(Json::wifi, w);
 
269
    }
98
270
 
99
271
    if (!cells.empty())
100
 
        ichnaea::Reporter::convert_cells_to_json(cells, item[Json::cell]);
101
 
 
102
 
    submit[Json::items].append(item);
103
 
 
104
 
    json::FastWriter writer;
105
 
 
106
 
    VLOG(10) << "Submitting: " << writer.write(submit);
 
272
    {
 
273
        json::Object c = json::Object::create_array();
 
274
        ichnaea::Reporter::convert_cells_to_json(cells, c);
 
275
        item.put_array(Json::cell, c);
 
276
    }
 
277
 
 
278
    items.append(item);
 
279
    submit.put_array(Json::items, items);
 
280
 
 
281
    auto string_representation = submit.to_plain_string();
 
282
 
 
283
    VLOG(10) << "Submitting: " << string_representation;
107
284
 
108
285
    auto request = http_client->post(
109
286
                submit_request_config,
110
 
                writer.write(submit),
 
287
                string_representation,
111
288
                core::net::http::ContentType::json);
112
289
 
113
290
    request->async_execute(
127
304
 
128
305
void location::service::ichnaea::Reporter::convert_wifis_to_json(
129
306
        const std::vector<location::connectivity::WirelessNetwork::Ptr>& wifis,
130
 
        json::Value& destination)
 
307
        json::Object& destination)
131
308
{
132
309
    for (const auto& wifi : wifis)
133
310
    {
135
312
        if (wifi->ssid().get().find("_nomap") != std::string::npos)
136
313
            continue;
137
314
 
138
 
        json::Value w;
139
 
        w[Json::Wifi::key] = wifi->bssid().get();
 
315
        json::Object w = json::Object::create_object();
 
316
        w.put_string(Json::Wifi::key, wifi->bssid().get());
140
317
 
141
318
        if (wifi->frequency().get().is_valid())
142
 
            w[Json::Wifi::frequency] = static_cast<int>(wifi->frequency().get());
 
319
            w.put_int32(Json::Wifi::frequency, static_cast<int>(wifi->frequency().get()));
143
320
 
144
321
        // We have a relative signal strength percentage in the wifi record.
145
322
        // TODO(tvoss): Check how that could be translated to RSSI.
151
328
 
152
329
void location::service::ichnaea::Reporter::convert_cells_to_json(
153
330
        const std::vector<location::connectivity::RadioCell::Ptr>& cells,
154
 
        json::Value& destination)
 
331
        json::Object& destination)
155
332
{
156
333
    for (const auto& cell : cells)
157
334
    {
158
 
        json::Value c;
 
335
        json::Object c = json::Object::create_object();
159
336
 
160
337
        switch (cell->type())
161
338
        {
162
339
        case connectivity::RadioCell::Type::gsm:
163
340
        {
164
 
            c[Json::Cell::radio] = "gsm";
 
341
            c.put_string(Json::Cell::radio, "gsm");
165
342
 
166
343
            const auto& details = cell->gsm();
167
344
 
168
345
            if (details.mobile_country_code.is_valid())
169
 
                c[Json::Cell::mcc] = details.mobile_country_code.get();
 
346
                c.put_int32(Json::Cell::mcc, details.mobile_country_code.get());
170
347
            if (details.mobile_network_code.is_valid())
171
 
                c[Json::Cell::mnc] = details.mobile_network_code.get();
 
348
                c.put_int32(Json::Cell::mnc, details.mobile_network_code.get());
172
349
            if (details.location_area_code.is_valid())
173
 
                c[Json::Cell::lac] = details.location_area_code.get();
 
350
                c.put_int32(Json::Cell::lac, details.location_area_code.get());
174
351
            if (details.id.is_valid())
175
 
                c[Json::Cell::cid] = details.id.get();
 
352
                c.put_int32(Json::Cell::cid, details.id.get());
176
353
            if  (details.strength.is_valid())
177
 
                c[Json::Cell::asu] = details.strength.get();
 
354
                c.put_int32(Json::Cell::asu, details.strength.get());
178
355
 
179
356
            break;
180
357
        }
181
358
        case connectivity::RadioCell::Type::umts:
182
359
        {
183
 
            c[Json::Cell::radio] = "umts";
 
360
            c.put_string(Json::Cell::radio, "umts");
184
361
 
185
362
            const auto& details = cell->umts();
186
363
 
187
364
            if (details.mobile_country_code.is_valid())
188
 
                c[Json::Cell::mcc] = details.mobile_country_code.get();
 
365
                c.put_int32(Json::Cell::mcc, details.mobile_country_code.get());
189
366
            if (details.mobile_network_code.is_valid())
190
 
                c[Json::Cell::mnc] = details.mobile_network_code.get();
 
367
                c.put_int32(Json::Cell::mnc, details.mobile_network_code.get());
191
368
            if (details.location_area_code.is_valid())
192
 
                c[Json::Cell::lac] = details.location_area_code.get();
 
369
                c.put_int32(Json::Cell::lac, details.location_area_code.get());
193
370
            if (details.id.is_valid())
194
 
                c[Json::Cell::cid] = details.id.get();
 
371
                c.put_int32(Json::Cell::cid, details.id.get());
195
372
            if  (details.strength.is_valid())
196
 
                c[Json::Cell::asu] = details.strength.get();
 
373
                c.put_int32(Json::Cell::asu, details.strength.get());
197
374
 
198
375
            break;
199
376
        }
200
377
        case connectivity::RadioCell::Type::lte:
201
378
        {
202
 
            c[Json::Cell::radio] = "lte";
 
379
            c.put_string(Json::Cell::radio, "lte");
203
380
 
204
381
            const auto& details = cell->lte();
205
382
 
206
383
            if (details.mobile_country_code.is_valid())
207
 
                c[Json::Cell::mcc] = details.mobile_country_code.get();
 
384
                c.put_int32(Json::Cell::mcc, details.mobile_country_code.get());
208
385
            if (details.mobile_network_code.is_valid())
209
 
                c[Json::Cell::mnc] = details.mobile_network_code.get();
 
386
                c.put_int32(Json::Cell::mnc, details.mobile_network_code.get());
210
387
            if (details.tracking_area_code.is_valid())
211
 
                c[Json::Cell::lac] = details.tracking_area_code.get();
 
388
                c.put_int32(Json::Cell::lac, details.tracking_area_code.get());
212
389
            if (details.id.is_valid())
213
 
                c[Json::Cell::cid] = details.id.get();
 
390
                c.put_int32(Json::Cell::cid, details.id.get());
214
391
            if (details.physical_id.is_valid())
215
 
                c[Json::Cell::psc] = details.physical_id.get();
 
392
                c.put_int32(Json::Cell::psc, details.physical_id.get());
216
393
            if  (details.strength.is_valid())
217
 
                c[Json::Cell::asu] = details.strength.get();
 
394
                c.put_int32(Json::Cell::asu, details.strength.get());
218
395
            break;
219
396
        }
220
397
        default: