Merge lp:~unity-api-team/unity-scopes-api/leverage-net-cpp-streaming-api into lp:unity-scopes-api/devel

Proposed by Marcus Tomlinson
Status: Merged
Approved by: Marcus Tomlinson
Approved revision: 585
Merged at revision: 589
Proposed branch: lp:~unity-api-team/unity-scopes-api/leverage-net-cpp-streaming-api
Merge into: lp:unity-scopes-api/devel
Diff against target: 234 lines (+72/-41)
6 files modified
CMakeLists.txt (+1/-1)
debian/control (+1/-1)
include/unity/scopes/internal/smartscopes/HttpClientNetCpp.h (+2/-2)
include/unity/scopes/internal/smartscopes/SmartScopesClient.h (+4/-2)
src/scopes/internal/smartscopes/HttpClientNetCpp.cpp (+11/-11)
src/scopes/internal/smartscopes/SmartScopesClient.cpp (+53/-24)
To merge this branch: bzr merge lp:~unity-api-team/unity-scopes-api/leverage-net-cpp-streaming-api
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Michi Henning (community) Approve
Thomas Voß (community) Approve
Review via email: mp+256281@code.launchpad.net

Commit message

Leverage the streaming API introduced in net-cpp 1.2.0.

To post a comment you must log in.
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

This is a copy of lp:~thomas-voss/unity-scopes-api/leverage-net-cpp-streaming-api, with buffering of partial json chucks added to SmartScopesClient.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Thomas Voß (thomas-voss) wrote :

LGTM.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Need to wait for net-cpp to land before we can go ahead with this one.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Re-approving as net-cpp has now landed

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michi Henning (michihenning) wrote :

LGTM!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Oh gosh, benchmark test failure... Here goes another 2 hours of build time...

Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-05-15 06:05:48 +0000
3+++ CMakeLists.txt 2015-05-18 06:26:24 +0000
4@@ -70,7 +70,7 @@
5 pkg_check_modules(LIBACCOUNTS libaccounts-glib REQUIRED)
6 pkg_check_modules(LIBSIGNON libsignon-glib REQUIRED)
7 pkg_check_modules(ZMQLIB libzmq REQUIRED)
8-pkg_check_modules(NET_CPP net-cpp REQUIRED)
9+pkg_check_modules(NET_CPP net-cpp>=1.2.0 REQUIRED)
10
11 find_library(ZMQPPLIB zmqpp)
12 if(NOT ZMQPPLIB)
13
14=== modified file 'debian/control'
15--- debian/control 2015-05-15 00:25:07 +0000
16+++ debian/control 2015-05-18 06:26:24 +0000
17@@ -20,7 +20,7 @@
18 libdbustest1-dev,
19 libjsoncpp-dev,
20 liblttng-ust-dev,
21- libnet-cpp-dev,
22+ libnet-cpp-dev (>= 1.2.0),
23 libprocess-cpp-dev (>= 1.0.1),
24 libsignon-glib-dev,
25 libunity-api-dev (>= 7.80.7~),
26
27=== modified file 'include/unity/scopes/internal/smartscopes/HttpClientNetCpp.h'
28--- include/unity/scopes/internal/smartscopes/HttpClientNetCpp.h 2015-01-16 06:13:57 +0000
29+++ include/unity/scopes/internal/smartscopes/HttpClientNetCpp.h 2015-05-18 06:26:24 +0000
30@@ -30,7 +30,7 @@
31 {
32 namespace http
33 {
34-class Client;
35+class StreamingClient;
36 }
37 }
38 }
39@@ -63,7 +63,7 @@
40 void cancel_get(unsigned int session_id) override;
41
42 unsigned int no_reply_timeout;
43- std::shared_ptr<core::net::http::Client> client;
44+ std::shared_ptr<core::net::http::StreamingClient> client;
45 std::thread worker;
46 };
47
48
49=== modified file 'include/unity/scopes/internal/smartscopes/SmartScopesClient.h'
50--- include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2015-01-28 09:03:59 +0000
51+++ include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2015-05-18 06:26:24 +0000
52@@ -215,8 +215,10 @@
53 std::shared_ptr<DepartmentInfo> parse_departments(JsonNodeInterface::SPtr node);
54 Filters parse_filters(JsonNodeInterface::SPtr node);
55 FilterState parse_filter_state(JsonNodeInterface::SPtr node);
56- void parse_line(std::string const& json, SearchReplyHandler const& handler);
57- void parse_line(std::string const& json, PreviewReplyHandler const& handler);
58+
59+ std::string handle_chunk(const std::string& chunk, std::function<void(const std::string&)> line_handler);
60+ void handle_line(std::string const& json, SearchReplyHandler const& handler);
61+ void handle_line(std::string const& json, PreviewReplyHandler const& handler);
62
63 std::vector<std::string> extract_json_stream(std::string const& json_stream);
64
65
66=== modified file 'src/scopes/internal/smartscopes/HttpClientNetCpp.cpp'
67--- src/scopes/internal/smartscopes/HttpClientNetCpp.cpp 2015-01-19 09:15:06 +0000
68+++ src/scopes/internal/smartscopes/HttpClientNetCpp.cpp 2015-05-18 06:26:24 +0000
69@@ -20,8 +20,8 @@
70
71 #include <unity/UnityExceptions.h>
72
73-#include <core/net/http/client.h>
74-#include <core/net/http/request.h>
75+#include <core/net/http/streaming_client.h>
76+#include <core/net/http/streaming_request.h>
77 #include <core/net/http/response.h>
78 #include <core/net/http/status.h>
79
80@@ -102,7 +102,7 @@
81
82 HttpClientNetCpp::HttpClientNetCpp(unsigned int no_reply_timeout)
83 : no_reply_timeout{no_reply_timeout},
84- client{http::make_client()},
85+ client{http::make_streaming_client()},
86 worker([this]() { client->run(); })
87 {
88 }
89@@ -129,7 +129,7 @@
90 }
91 http_config.header = http_header;
92
93- auto request = client->get(http_config);
94+ auto request = client->streaming_get(http_config);
95 request->set_timeout(std::chrono::milliseconds{no_reply_timeout});
96
97 auto promise = std::make_shared<std::promise<void>>();
98@@ -157,12 +157,8 @@
99 }
100 else
101 {
102- std::istringstream in(response.body);
103- std::string line;
104- while (std::getline(in, line))
105- {
106- line_data(line);
107- }
108+ // call line_data with empty string to signal end of chunked data
109+ line_data("");
110 promise->set_value();
111 }
112 })
113@@ -170,7 +166,11 @@
114 {
115 unity::ResourceException re(e.what());
116 promise->set_exception(std::make_exception_ptr(re));
117- }));
118+ }),
119+ [line_data](const std::string& const_data)
120+ {
121+ line_data(const_data);
122+ });
123
124 return std::make_shared<HttpResponseHandle>(
125 shared_from_this(),
126
127=== modified file 'src/scopes/internal/smartscopes/SmartScopesClient.cpp'
128--- src/scopes/internal/smartscopes/SmartScopesClient.cpp 2015-04-10 03:55:25 +0000
129+++ src/scopes/internal/smartscopes/SmartScopesClient.cpp 2015-05-18 06:26:24 +0000
130@@ -472,18 +472,17 @@
131 headers.push_back(std::make_pair("User-Agent", user_agent_hdr));
132 }
133
134- auto reponse_mutex = std::make_shared<std::mutex>();
135- query_results_[search_id] = http_client_->get(search_uri.str(), [this, handler, reponse_mutex](std::string const& line_data)
136+ auto tmp_data = std::make_shared<std::string>();
137+ query_results_[search_id] = http_client_->get(search_uri.str(), [this, tmp_data, handler](std::string const& chunk)
138 {
139- std::lock_guard<std::mutex> lock(*reponse_mutex);
140- try
141- {
142- parse_line(line_data, handler);
143- }
144- catch (std::exception const &e)
145- {
146- BOOST_LOG_SEV(logger_, Logger::Error) << "SmartScopesClient.search(): Failed to parse: " << e.what();
147- }
148+ // prepend any leftover data from the previous handle_chunk call
149+ std::string data = *tmp_data + (chunk.empty() ? "\n" : chunk);
150+
151+ // store the leftover data from the handle_chunk call into tmp_data
152+ *tmp_data = handle_chunk(data, [this, handler](const std::string& line)
153+ {
154+ handle_line(line, handler);
155+ });
156 }, headers);
157
158 return SearchHandle::UPtr(new SearchHandle(search_id, shared_from_this()));
159@@ -540,24 +539,54 @@
160
161 BOOST_LOG_SEV(logger_, Logger::Info) << "SmartScopesClient.preview(): GET " << preview_uri.str();
162
163- auto reponse_mutex = std::make_shared<std::mutex>();
164- query_results_[preview_id] = http_client_->get(preview_uri.str(), [this, handler, reponse_mutex](std::string const& line_data)
165+ auto tmp_data = std::make_shared<std::string>();
166+ query_results_[preview_id] = http_client_->get(preview_uri.str(), [this, tmp_data, handler](std::string const& chunk)
167 {
168- std::lock_guard<std::mutex> lock(*reponse_mutex);
169- try
170- {
171- parse_line(line_data, handler);
172- }
173- catch (std::exception const &e)
174- {
175- BOOST_LOG_SEV(logger_, Logger::Error) << "SmartScopesClient.preview(): Failed to parse: " << e.what();
176- }
177+ // prepend any leftover data from the previous handle_chunk call
178+ std::string data = *tmp_data + (chunk.empty() ? "\n" : chunk);
179+
180+ // store the leftover data from the handle_chunk call into tmp_data
181+ *tmp_data = handle_chunk(data, [this, handler](const std::string& line)
182+ {
183+ handle_line(line, handler);
184+ });
185 }, headers);
186
187 return PreviewHandle::UPtr(new PreviewHandle(preview_id, shared_from_this()));
188 }
189
190-void SmartScopesClient::parse_line(std::string const& json, PreviewReplyHandler const& handler)
191+std::string SmartScopesClient::handle_chunk(const std::string& chunk, std::function<void(const std::string&)> line_handler)
192+{
193+ // According to the docs, we expect:
194+ // The response will have Content-Type
195+ // application/json, it will be a chunked response, in practice a series of
196+ // “\r\n” delimited lines, each containing one JSON object, with the
197+ // possible forms, matching what currently can be pushed into a reply in the
198+ // new scopes API
199+ static constexpr const char separator{'\n'};
200+
201+ // read data line-by-line calling line_handler() for each
202+ auto newline_pos = 0;
203+ auto endline_pos = chunk.find(separator);
204+ while (endline_pos != std::string::npos)
205+ {
206+ try
207+ {
208+ line_handler(chunk.substr(newline_pos, endline_pos - newline_pos));
209+ }
210+ catch (std::exception const &e)
211+ {
212+ BOOST_LOG_SEV(logger_, Logger::Error) << "SmartScopesClient.handle_chunk(): Failed to parse line: " << e.what();
213+ }
214+ newline_pos = endline_pos + 1;
215+ endline_pos = chunk.find(separator, newline_pos);
216+ }
217+
218+ // return the leftover data
219+ return chunk.substr(newline_pos, chunk.size() - newline_pos);
220+}
221+
222+void SmartScopesClient::handle_line(std::string const& json, PreviewReplyHandler const& handler)
223 {
224 JsonNodeInterface::SPtr root_node;
225 JsonNodeInterface::SPtr child_node;
226@@ -605,7 +634,7 @@
227 }
228 }
229
230-void SmartScopesClient::parse_line(std::string const& json, SearchReplyHandler const& handler)
231+void SmartScopesClient::handle_line(std::string const& json, SearchReplyHandler const& handler)
232 {
233 JsonNodeInterface::SPtr root_node;
234 JsonNodeInterface::SPtr child_node;

Subscribers

People subscribed via source and target branches

to all changes: