lorgnette_manager_client.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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.
4
5#include "chromeos/dbus/lorgnette_manager_client.h"
6
7#include <string>
8
9#include "base/bind.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/platform_file.h"
15#include "base/threading/worker_pool.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"
22
23namespace chromeos {
24
25// The LorgnetteManagerClient implementation used in production.
26class LorgnetteManagerClientImpl : public LorgnetteManagerClient {
27 public:
28  LorgnetteManagerClientImpl() :
29      lorgnette_daemon_proxy_(NULL), weak_ptr_factory_(this) {}
30
31  virtual ~LorgnetteManagerClientImpl() {}
32
33  virtual 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));
42  }
43
44  // LorgnetteManagerClient override.
45  virtual void ScanImage(std::string device_name,
46                         base::PlatformFile file,
47                         const ScanProperties& properties,
48                         const ScanImageCallback& callback) OVERRIDE {
49    dbus::FileDescriptor* file_descriptor = new dbus::FileDescriptor();
50    file_descriptor->PutValue(file);
51    // Punt descriptor validity check to a worker thread; on return we'll
52    // issue the D-Bus request to stop tracing and collect results.
53    base::WorkerPool::PostTaskAndReply(
54        FROM_HERE,
55        base::Bind(&LorgnetteManagerClientImpl::CheckValidity,
56                   file_descriptor),
57        base::Bind(&LorgnetteManagerClientImpl::OnCheckValidityScanImage,
58                   weak_ptr_factory_.GetWeakPtr(),
59                   base::Owned(file_descriptor),
60                   device_name,
61                   properties,
62                   callback),
63        false);
64  }
65
66 protected:
67  virtual void Init(dbus::Bus* bus) OVERRIDE {
68    lorgnette_daemon_proxy_ =
69        bus->GetObjectProxy(lorgnette::kManagerServiceName,
70                            dbus::ObjectPath(lorgnette::kManagerServicePath));
71  }
72
73 private:
74  // Called when ListScanners completes.
75  void OnListScanners(const ListScannersCallback& callback,
76                      dbus::Response* response) {
77    ScannerTable scanners;
78    dbus::MessageReader table_reader(NULL);
79    if (!response || !dbus::MessageReader(response).PopArray(&table_reader)) {
80      callback.Run(false, scanners);
81      return;
82    }
83
84    bool decode_failure = false;
85    while (table_reader.HasMoreData()) {
86      std::string device_name;
87      dbus::MessageReader device_entry_reader(NULL);
88      dbus::MessageReader device_element_reader(NULL);
89      if (!table_reader.PopDictEntry(&device_entry_reader) ||
90          !device_entry_reader.PopString(&device_name) ||
91          !device_entry_reader.PopArray(&device_element_reader)) {
92        decode_failure = true;
93        break;
94      }
95
96      ScannerTableEntry scanner_entry;
97      while (device_element_reader.HasMoreData()) {
98        dbus::MessageReader device_attribute_reader(NULL);
99        std::string attribute;
100        std::string value;
101        if (!device_element_reader.PopDictEntry(&device_attribute_reader) ||
102            !device_attribute_reader.PopString(&attribute) ||
103            !device_attribute_reader.PopString(&value)) {
104          decode_failure = true;
105          break;
106        }
107        scanner_entry[attribute] = value;
108      }
109
110      if (decode_failure)
111          break;
112
113      scanners[device_name] = scanner_entry;
114    }
115
116    if (decode_failure) {
117      LOG(ERROR) << "Failed to decode response from ListScanners";
118      callback.Run(false, scanners);
119    } else {
120      callback.Run(true, scanners);
121    }
122  }
123
124  // Called to check descriptor validity on a thread where i/o is permitted.
125  static void CheckValidity(dbus::FileDescriptor* file_descriptor) {
126    file_descriptor->CheckValidity();
127  }
128
129  // Called when a CheckValidity response is received.
130  void OnCheckValidityScanImage(
131      dbus::FileDescriptor* file_descriptor,
132      std::string device_name,
133      const ScanProperties& properties,
134      const ScanImageCallback& callback) {
135    if (!file_descriptor->is_valid()) {
136      LOG(ERROR) << "Failed to scan image: file descriptor is invalid";
137      callback.Run(false);
138      return;
139    }
140    // Issue the dbus request to scan an image.
141    dbus::MethodCall method_call(
142        lorgnette::kManagerServiceInterface,
143        lorgnette::kScanImageMethod);
144    dbus::MessageWriter writer(&method_call);
145    writer.AppendString(device_name);
146    writer.AppendFileDescriptor(*file_descriptor);
147
148    dbus::MessageWriter option_writer(NULL);
149    dbus::MessageWriter element_writer(NULL);
150    writer.OpenArray("{sv}", &option_writer);
151    if (!properties.mode.empty()) {
152      option_writer.OpenDictEntry(&element_writer);
153      element_writer.AppendString(lorgnette::kScanPropertyMode);
154      element_writer.AppendVariantOfString(properties.mode);
155      option_writer.CloseContainer(&element_writer);
156    }
157    if (properties.resolution_dpi) {
158      option_writer.OpenDictEntry(&element_writer);
159      element_writer.AppendString(lorgnette::kScanPropertyResolution);
160      element_writer.AppendVariantOfUint32(properties.resolution_dpi);
161      option_writer.CloseContainer(&element_writer);
162    }
163    writer.CloseContainer(&option_writer);
164
165    lorgnette_daemon_proxy_->CallMethod(
166        &method_call,
167        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
168        base::Bind(&LorgnetteManagerClientImpl::OnScanImageComplete,
169                   weak_ptr_factory_.GetWeakPtr(),
170                   callback));
171  }
172
173  // Called when a response for ScanImage() is received.
174  void OnScanImageComplete(const ScanImageCallback& callback,
175                           dbus::Response* response) {
176    if (!response) {
177      LOG(ERROR) << "Failed to scan image";
178      callback.Run(false);
179      return;
180    }
181    callback.Run(true);
182  }
183
184  dbus::ObjectProxy* lorgnette_daemon_proxy_;
185  base::WeakPtrFactory<LorgnetteManagerClientImpl> weak_ptr_factory_;
186
187  DISALLOW_COPY_AND_ASSIGN(LorgnetteManagerClientImpl);
188};
189
190LorgnetteManagerClient::LorgnetteManagerClient() {
191}
192
193LorgnetteManagerClient::~LorgnetteManagerClient() {
194}
195
196// static
197LorgnetteManagerClient* LorgnetteManagerClient::Create() {
198  return new LorgnetteManagerClientImpl();
199}
200
201}  // namespace chromeos
202