Compute can_use_lcd_text using property trees.
[chromium-blink-merge.git] / remoting / host / gcd_rest_client.cc
blobc8c429f9c1cec3067e1eca69837d36f921e56c84
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/host/gcd_rest_client.h"
7 #include "base/bind.h"
8 #include "base/json/json_writer.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "base/time/default_clock.h"
12 #include "base/values.h"
13 #include "net/url_request/url_fetcher.h"
14 #include "remoting/base/logging.h"
16 namespace remoting {
18 // Only 'patchState' requests are supported at the moment, but other
19 // types of requests may be added in the future.
20 struct GcdRestClient::PatchStateRequest {
21 GcdRestClient::PatchStateCallback callback;
22 scoped_ptr<net::URLFetcher> url_fetcher;
25 GcdRestClient::GcdRestClient(const std::string& gcd_base_url,
26 const std::string& gcd_device_id,
27 const scoped_refptr<net::URLRequestContextGetter>&
28 url_request_context_getter,
29 OAuthTokenGetter* token_getter)
30 : gcd_base_url_(gcd_base_url),
31 gcd_device_id_(gcd_device_id),
32 url_request_context_getter_(url_request_context_getter),
33 token_getter_(token_getter),
34 clock_(new base::DefaultClock),
35 weak_factory_(this) {
38 GcdRestClient::~GcdRestClient() {
39 while (!pending_requests_.empty()) {
40 delete pending_requests_.front();
41 pending_requests_.pop();
45 void GcdRestClient::PatchState(
46 scoped_ptr<base::DictionaryValue> patch_details,
47 const GcdRestClient::PatchStateCallback& callback) {
48 // Construct a status update message in the format GCD expects. The
49 // message looks like this, where "..." is filled in from
50 // |patch_details|:
52 // {
53 // requestTimeMs: T,
54 // patches: [{
55 // timeMs: T,
56 // patch: {...}
57 // }]
58 // }
60 // Note that |now| is deliberately using a double to hold an integer
61 // value because |DictionaryValue| doesn't support int64 values, and
62 // GCD doesn't accept fractional values.
63 double now = clock_->Now().ToJavaTime();
64 scoped_ptr<base::DictionaryValue> patch_dict(new base::DictionaryValue);
65 patch_dict->SetDouble("requestTimeMs", now);
66 scoped_ptr<base::ListValue> patch_list(new base::ListValue);
67 base::DictionaryValue* patch_item = new base::DictionaryValue;
68 patch_list->Append(patch_item);
69 patch_item->Set("patch", patch_details.Pass());
70 patch_item->SetDouble("timeMs", now);
71 patch_dict->Set("patches", patch_list.Pass());
73 // Stringify the message.
74 std::string patch_string;
75 if (!base::JSONWriter::Write(*patch_dict, &patch_string)) {
76 LOG(ERROR) << "Error building GCD device state patch.";
77 callback.Run(OTHER_ERROR);
78 return;
80 DLOG(INFO) << "sending state patch: " << patch_string;
82 std::string url =
83 gcd_base_url_ + "/devices/" + gcd_device_id_ + "/patchState";
85 // Enqueue an HTTP request to issue once an auth token is available.
86 scoped_ptr<PatchStateRequest> request(new PatchStateRequest);
87 request->callback = callback;
88 request->url_fetcher =
89 net::URLFetcher::Create(GURL(url), net::URLFetcher::POST, this);
90 request->url_fetcher->SetUploadData("application/json", patch_string);
91 if (url_request_context_getter_) {
92 request->url_fetcher->SetRequestContext(url_request_context_getter_.get());
95 if (current_request_) {
96 // New request will start when the current request finishes.
97 DCHECK(pending_requests_.empty());
98 pending_requests_.push(request.release());
99 } else {
100 current_request_ = request.Pass();
101 StartNextRequest();
105 void GcdRestClient::StartNextRequest() {
106 DCHECK(current_request_);
107 token_getter_->CallWithToken(
108 base::Bind(&GcdRestClient::OnTokenReceived, base::Unretained(this)));
111 void GcdRestClient::OnTokenReceived(OAuthTokenGetter::Status status,
112 const std::string& user_email,
113 const std::string& access_token) {
114 DCHECK(current_request_);
115 if (status != OAuthTokenGetter::SUCCESS) {
116 LOG(ERROR) << "Error getting OAuth token for GCD request: "
117 << current_request_->url_fetcher->GetOriginalURL();
118 if (status == OAuthTokenGetter::NETWORK_ERROR) {
119 FinishCurrentRequest(NETWORK_ERROR);
120 } else {
121 FinishCurrentRequest(OTHER_ERROR);
123 return;
126 current_request_->url_fetcher->SetExtraRequestHeaders(
127 "Authorization: Bearer " + access_token);
128 current_request_->url_fetcher->Start();
131 void GcdRestClient::FinishCurrentRequest(Status result) {
132 DCHECK(current_request_);
133 scoped_ptr<PatchStateRequest> request = current_request_.Pass();
134 if (!pending_requests_.empty()) {
135 current_request_.reset(pending_requests_.front());
136 pending_requests_.pop();
138 // This object may be destroyed by the call to request->callback
139 // below, so instead of calling StartNextRequest() at the end of
140 // this method, schedule a call using a weak pointer.
141 base::ThreadTaskRunnerHandle::Get()->PostTask(
142 FROM_HERE, base::Bind(&GcdRestClient::StartNextRequest,
143 weak_factory_.GetWeakPtr()));
146 request->callback.Run(result);
149 void GcdRestClient::OnURLFetchComplete(const net::URLFetcher* source) {
150 DCHECK(current_request_);
152 const GURL& request_url = current_request_->url_fetcher->GetOriginalURL();
153 Status status = OTHER_ERROR;
154 int response = source->GetResponseCode();
155 if (response >= 200 && response < 300) {
156 DLOG(INFO) << "GCD request succeeded:" << request_url;
157 status = SUCCESS;
158 } else if (response == 404) {
159 LOG(WARNING) << "Host not found (" << response
160 << ") fetching URL: " << request_url;
161 status = NO_SUCH_HOST;
162 } else if (response == 0) {
163 LOG(ERROR) << "Network error (" << response
164 << ") fetching URL: " << request_url;
165 status = NETWORK_ERROR;
166 } else {
167 LOG(ERROR) << "Error (" << response << ") fetching URL: " << request_url;
170 FinishCurrentRequest(status);
173 } // namespace remoting