Fixes bug in html_viewer that could lead to dropping interface requests
[chromium-blink-merge.git] / chromeos / dbus / lorgnette_manager_client.cc
blobd99f59bdf96faf46c36048d8cd2bcd1d229551f3
1 // Copyright 2014 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 "chromeos/dbus/lorgnette_manager_client.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/location.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/task_runner_util.h"
14 #include "base/threading/worker_pool.h"
15 #include "chromeos/dbus/pipe_reader.h"
16 #include "dbus/bus.h"
17 #include "dbus/message.h"
18 #include "dbus/object_path.h"
19 #include "dbus/object_proxy.h"
20 #include "net/base/file_stream.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
23 namespace chromeos {
25 // The LorgnetteManagerClient implementation used in production.
26 class LorgnetteManagerClientImpl : public LorgnetteManagerClient {
27 public:
28 LorgnetteManagerClientImpl() :
29 lorgnette_daemon_proxy_(NULL), weak_ptr_factory_(this) {}
31 ~LorgnetteManagerClientImpl() override {}
33 void ListScanners(const ListScannersCallback& callback) override {
34 dbus::MethodCall method_call(lorgnette::kManagerServiceInterface,
35 lorgnette::kListScannersMethod);
36 lorgnette_daemon_proxy_->CallMethod(
37 &method_call,
38 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
39 base::Bind(&LorgnetteManagerClientImpl::OnListScanners,
40 weak_ptr_factory_.GetWeakPtr(),
41 callback));
44 // LorgnetteManagerClient override.
45 void ScanImageToFile(
46 std::string device_name,
47 const ScanProperties& properties,
48 const ScanImageToFileCallback& callback,
49 base::File* file) override {
50 dbus::FileDescriptor* file_descriptor = new dbus::FileDescriptor();
51 file_descriptor->PutValue(file->TakePlatformFile());
52 // Punt descriptor validity check to a worker thread; on return we'll
53 // issue the D-Bus request to stop tracing and collect results.
54 base::WorkerPool::PostTaskAndReply(
55 FROM_HERE,
56 base::Bind(&LorgnetteManagerClientImpl::CheckValidity,
57 file_descriptor),
58 base::Bind(&LorgnetteManagerClientImpl::OnCheckValidityScanImage,
59 weak_ptr_factory_.GetWeakPtr(),
60 base::Owned(file_descriptor),
61 device_name,
62 properties,
63 callback),
64 false);
67 void ScanImageToString(
68 std::string device_name,
69 const ScanProperties& properties,
70 const ScanImageToStringCallback& callback) override {
71 // Owned by the callback created in scan_to_string_completion->Start().
72 ScanToStringCompletion* scan_to_string_completion =
73 new ScanToStringCompletion();
74 base::File file;
75 ScanImageToFileCallback file_callback =
76 scan_to_string_completion->Start(callback, &file);
77 ScanImageToFile(device_name, properties, file_callback, &file);
80 protected:
81 void Init(dbus::Bus* bus) override {
82 lorgnette_daemon_proxy_ =
83 bus->GetObjectProxy(lorgnette::kManagerServiceName,
84 dbus::ObjectPath(lorgnette::kManagerServicePath));
87 private:
88 class ScanToStringCompletion {
89 public:
90 ScanToStringCompletion() {}
91 virtual ~ScanToStringCompletion() {}
93 // Creates a file stream in |file| that will stream image data to
94 // a string that will be supplied to |callback|. Passes ownership
95 // of |this| to a returned callback that can be handed to a
96 // ScanImageToFile invocation.
97 ScanImageToFileCallback Start(const ScanImageToStringCallback& callback,
98 base::File *file) {
99 CHECK(!pipe_reader_.get());
100 const bool kTasksAreSlow = true;
101 scoped_refptr<base::TaskRunner> task_runner =
102 base::WorkerPool::GetTaskRunner(kTasksAreSlow);
103 pipe_reader_.reset(
104 new chromeos::PipeReaderForString(
105 task_runner,
106 base::Bind(&ScanToStringCompletion::OnScanToStringDataCompleted,
107 base::Unretained(this))));
108 *file = pipe_reader_->StartIO();
110 return base::Bind(&ScanToStringCompletion::OnScanToStringCompleted,
111 base::Owned(this), callback);
114 private:
115 // Called when a |pipe_reader_| completes reading scan data to a string.
116 void OnScanToStringDataCompleted() {
117 pipe_reader_->GetData(&scanned_image_data_string_);
118 pipe_reader_.reset();
121 // Called by LorgnetteManagerImpl when scan completes.
122 void OnScanToStringCompleted(const ScanImageToStringCallback& callback,
123 bool succeeded) {
124 if (pipe_reader_.get()) {
125 pipe_reader_->OnDataReady(-1); // terminate data stream
127 callback.Run(succeeded, scanned_image_data_string_);
128 scanned_image_data_string_.clear();
131 scoped_ptr<chromeos::PipeReaderForString> pipe_reader_;
132 std::string scanned_image_data_string_;
134 DISALLOW_COPY_AND_ASSIGN(ScanToStringCompletion);
137 // Called when ListScanners completes.
138 void OnListScanners(const ListScannersCallback& callback,
139 dbus::Response* response) {
140 ScannerTable scanners;
141 dbus::MessageReader table_reader(NULL);
142 if (!response || !dbus::MessageReader(response).PopArray(&table_reader)) {
143 callback.Run(false, scanners);
144 return;
147 bool decode_failure = false;
148 while (table_reader.HasMoreData()) {
149 std::string device_name;
150 dbus::MessageReader device_entry_reader(NULL);
151 dbus::MessageReader device_element_reader(NULL);
152 if (!table_reader.PopDictEntry(&device_entry_reader) ||
153 !device_entry_reader.PopString(&device_name) ||
154 !device_entry_reader.PopArray(&device_element_reader)) {
155 decode_failure = true;
156 break;
159 ScannerTableEntry scanner_entry;
160 while (device_element_reader.HasMoreData()) {
161 dbus::MessageReader device_attribute_reader(NULL);
162 std::string attribute;
163 std::string value;
164 if (!device_element_reader.PopDictEntry(&device_attribute_reader) ||
165 !device_attribute_reader.PopString(&attribute) ||
166 !device_attribute_reader.PopString(&value)) {
167 decode_failure = true;
168 break;
170 scanner_entry[attribute] = value;
173 if (decode_failure)
174 break;
176 scanners[device_name] = scanner_entry;
179 if (decode_failure) {
180 LOG(ERROR) << "Failed to decode response from ListScanners";
181 callback.Run(false, scanners);
182 } else {
183 callback.Run(true, scanners);
187 // Called to check descriptor validity on a thread where i/o is permitted.
188 static void CheckValidity(dbus::FileDescriptor* file_descriptor) {
189 file_descriptor->CheckValidity();
192 // Called when a CheckValidity response is received.
193 void OnCheckValidityScanImage(
194 dbus::FileDescriptor* file_descriptor,
195 std::string device_name,
196 const ScanProperties& properties,
197 const ScanImageToFileCallback& callback) {
198 if (!file_descriptor->is_valid()) {
199 LOG(ERROR) << "Failed to scan image: file descriptor is invalid";
200 callback.Run(false);
201 return;
203 // Issue the dbus request to scan an image.
204 dbus::MethodCall method_call(
205 lorgnette::kManagerServiceInterface,
206 lorgnette::kScanImageMethod);
207 dbus::MessageWriter writer(&method_call);
208 writer.AppendString(device_name);
209 writer.AppendFileDescriptor(*file_descriptor);
211 dbus::MessageWriter option_writer(NULL);
212 dbus::MessageWriter element_writer(NULL);
213 writer.OpenArray("{sv}", &option_writer);
214 if (!properties.mode.empty()) {
215 option_writer.OpenDictEntry(&element_writer);
216 element_writer.AppendString(lorgnette::kScanPropertyMode);
217 element_writer.AppendVariantOfString(properties.mode);
218 option_writer.CloseContainer(&element_writer);
220 if (properties.resolution_dpi) {
221 option_writer.OpenDictEntry(&element_writer);
222 element_writer.AppendString(lorgnette::kScanPropertyResolution);
223 element_writer.AppendVariantOfUint32(properties.resolution_dpi);
224 option_writer.CloseContainer(&element_writer);
226 writer.CloseContainer(&option_writer);
228 lorgnette_daemon_proxy_->CallMethod(
229 &method_call,
230 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
231 base::Bind(&LorgnetteManagerClientImpl::OnScanImageComplete,
232 weak_ptr_factory_.GetWeakPtr(),
233 callback));
236 // Called when a response for ScanImage() is received.
237 void OnScanImageComplete(const ScanImageToFileCallback& callback,
238 dbus::Response* response) {
239 if (!response) {
240 LOG(ERROR) << "Failed to scan image";
241 callback.Run(false);
242 return;
244 callback.Run(true);
247 dbus::ObjectProxy* lorgnette_daemon_proxy_;
248 base::WeakPtrFactory<LorgnetteManagerClientImpl> weak_ptr_factory_;
250 DISALLOW_COPY_AND_ASSIGN(LorgnetteManagerClientImpl);
253 LorgnetteManagerClient::LorgnetteManagerClient() {
256 LorgnetteManagerClient::~LorgnetteManagerClient() {
259 // static
260 LorgnetteManagerClient* LorgnetteManagerClient::Create() {
261 return new LorgnetteManagerClientImpl();
264 } // namespace chromeos