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"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/location.h"
13 #include "base/memory/ref_counted_memory.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/task_runner_util.h"
16 #include "base/threading/worker_pool.h"
17 #include "chromeos/dbus/pipe_reader.h"
19 #include "dbus/message.h"
20 #include "dbus/object_path.h"
21 #include "dbus/object_proxy.h"
22 #include "net/base/file_stream.h"
23 #include "third_party/cros_system_api/dbus/service_constants.h"
27 // The LorgnetteManagerClient implementation used in production.
28 class LorgnetteManagerClientImpl : public LorgnetteManagerClient {
30 LorgnetteManagerClientImpl() :
31 lorgnette_daemon_proxy_(NULL), weak_ptr_factory_(this) {}
33 virtual ~LorgnetteManagerClientImpl() {}
35 void ListScanners(const ListScannersCallback& callback) override {
36 dbus::MethodCall method_call(lorgnette::kManagerServiceInterface,
37 lorgnette::kListScannersMethod);
38 lorgnette_daemon_proxy_->CallMethod(
40 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
41 base::Bind(&LorgnetteManagerClientImpl::OnListScanners,
42 weak_ptr_factory_.GetWeakPtr(),
46 // LorgnetteManagerClient override.
48 std::string device_name,
49 const ScanProperties& properties,
50 const ScanImageToFileCallback& callback,
51 base::File* file) override {
52 dbus::FileDescriptor* file_descriptor = new dbus::FileDescriptor();
53 file_descriptor->PutValue(file->TakePlatformFile());
54 // Punt descriptor validity check to a worker thread; on return we'll
55 // issue the D-Bus request to stop tracing and collect results.
56 base::WorkerPool::PostTaskAndReply(
58 base::Bind(&LorgnetteManagerClientImpl::CheckValidity,
60 base::Bind(&LorgnetteManagerClientImpl::OnCheckValidityScanImage,
61 weak_ptr_factory_.GetWeakPtr(),
62 base::Owned(file_descriptor),
69 void ScanImageToString(
70 std::string device_name,
71 const ScanProperties& properties,
72 const ScanImageToStringCallback& callback) override {
73 // Owned by the callback created in scan_to_string_completion->Start().
74 ScanToStringCompletion* scan_to_string_completion =
75 new ScanToStringCompletion();
77 ScanImageToFileCallback file_callback =
78 scan_to_string_completion->Start(callback, &file);
79 ScanImageToFile(device_name, properties, file_callback, &file);
83 void Init(dbus::Bus* bus) override {
84 lorgnette_daemon_proxy_ =
85 bus->GetObjectProxy(lorgnette::kManagerServiceName,
86 dbus::ObjectPath(lorgnette::kManagerServicePath));
90 class ScanToStringCompletion {
92 ScanToStringCompletion() {}
93 virtual ~ScanToStringCompletion() {}
95 // Creates a file stream in |file| that will stream image data to
96 // a string that will be supplied to |callback|. Passes ownership
97 // of |this| to a returned callback that can be handed to a
98 // ScanImageToFile invocation.
99 ScanImageToFileCallback Start(const ScanImageToStringCallback& callback,
101 CHECK(!pipe_reader_.get());
102 const bool kTasksAreSlow = true;
103 scoped_refptr<base::TaskRunner> task_runner =
104 base::WorkerPool::GetTaskRunner(kTasksAreSlow);
106 new chromeos::PipeReaderForString(
108 base::Bind(&ScanToStringCompletion::OnScanToStringDataCompleted,
109 base::Unretained(this))));
110 *file = pipe_reader_->StartIO();
112 return base::Bind(&ScanToStringCompletion::OnScanToStringCompleted,
113 base::Owned(this), callback);
117 // Called when a |pipe_reader_| completes reading scan data to a string.
118 void OnScanToStringDataCompleted() {
119 pipe_reader_->GetData(&scanned_image_data_string_);
120 pipe_reader_.reset();
123 // Called by LorgnetteManagerImpl when scan completes.
124 void OnScanToStringCompleted(const ScanImageToStringCallback& callback,
126 if (pipe_reader_.get()) {
127 pipe_reader_->OnDataReady(-1); // terminate data stream
129 callback.Run(succeeded, scanned_image_data_string_);
130 scanned_image_data_string_.clear();
133 scoped_ptr<chromeos::PipeReaderForString> pipe_reader_;
134 std::string scanned_image_data_string_;
136 DISALLOW_COPY_AND_ASSIGN(ScanToStringCompletion);
139 // Called when ListScanners completes.
140 void OnListScanners(const ListScannersCallback& callback,
141 dbus::Response* response) {
142 ScannerTable scanners;
143 dbus::MessageReader table_reader(NULL);
144 if (!response || !dbus::MessageReader(response).PopArray(&table_reader)) {
145 callback.Run(false, scanners);
149 bool decode_failure = false;
150 while (table_reader.HasMoreData()) {
151 std::string device_name;
152 dbus::MessageReader device_entry_reader(NULL);
153 dbus::MessageReader device_element_reader(NULL);
154 if (!table_reader.PopDictEntry(&device_entry_reader) ||
155 !device_entry_reader.PopString(&device_name) ||
156 !device_entry_reader.PopArray(&device_element_reader)) {
157 decode_failure = true;
161 ScannerTableEntry scanner_entry;
162 while (device_element_reader.HasMoreData()) {
163 dbus::MessageReader device_attribute_reader(NULL);
164 std::string attribute;
166 if (!device_element_reader.PopDictEntry(&device_attribute_reader) ||
167 !device_attribute_reader.PopString(&attribute) ||
168 !device_attribute_reader.PopString(&value)) {
169 decode_failure = true;
172 scanner_entry[attribute] = value;
178 scanners[device_name] = scanner_entry;
181 if (decode_failure) {
182 LOG(ERROR) << "Failed to decode response from ListScanners";
183 callback.Run(false, scanners);
185 callback.Run(true, scanners);
189 // Called to check descriptor validity on a thread where i/o is permitted.
190 static void CheckValidity(dbus::FileDescriptor* file_descriptor) {
191 file_descriptor->CheckValidity();
194 // Called when a CheckValidity response is received.
195 void OnCheckValidityScanImage(
196 dbus::FileDescriptor* file_descriptor,
197 std::string device_name,
198 const ScanProperties& properties,
199 const ScanImageToFileCallback& callback) {
200 if (!file_descriptor->is_valid()) {
201 LOG(ERROR) << "Failed to scan image: file descriptor is invalid";
205 // Issue the dbus request to scan an image.
206 dbus::MethodCall method_call(
207 lorgnette::kManagerServiceInterface,
208 lorgnette::kScanImageMethod);
209 dbus::MessageWriter writer(&method_call);
210 writer.AppendString(device_name);
211 writer.AppendFileDescriptor(*file_descriptor);
213 dbus::MessageWriter option_writer(NULL);
214 dbus::MessageWriter element_writer(NULL);
215 writer.OpenArray("{sv}", &option_writer);
216 if (!properties.mode.empty()) {
217 option_writer.OpenDictEntry(&element_writer);
218 element_writer.AppendString(lorgnette::kScanPropertyMode);
219 element_writer.AppendVariantOfString(properties.mode);
220 option_writer.CloseContainer(&element_writer);
222 if (properties.resolution_dpi) {
223 option_writer.OpenDictEntry(&element_writer);
224 element_writer.AppendString(lorgnette::kScanPropertyResolution);
225 element_writer.AppendVariantOfUint32(properties.resolution_dpi);
226 option_writer.CloseContainer(&element_writer);
228 writer.CloseContainer(&option_writer);
230 lorgnette_daemon_proxy_->CallMethod(
232 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
233 base::Bind(&LorgnetteManagerClientImpl::OnScanImageComplete,
234 weak_ptr_factory_.GetWeakPtr(),
238 // Called when a response for ScanImage() is received.
239 void OnScanImageComplete(const ScanImageToFileCallback& callback,
240 dbus::Response* response) {
242 LOG(ERROR) << "Failed to scan image";
249 dbus::ObjectProxy* lorgnette_daemon_proxy_;
250 base::WeakPtrFactory<LorgnetteManagerClientImpl> weak_ptr_factory_;
252 DISALLOW_COPY_AND_ASSIGN(LorgnetteManagerClientImpl);
255 LorgnetteManagerClient::LorgnetteManagerClient() {
258 LorgnetteManagerClient::~LorgnetteManagerClient() {
262 LorgnetteManagerClient* LorgnetteManagerClient::Create() {
263 return new LorgnetteManagerClientImpl();
266 } // namespace chromeos