Home | History | Annotate | Download | only in dbus
      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 
     23 namespace chromeos {
     24 
     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) {}
     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 
    190 LorgnetteManagerClient::LorgnetteManagerClient() {
    191 }
    192 
    193 LorgnetteManagerClient::~LorgnetteManagerClient() {
    194 }
    195 
    196 // static
    197 LorgnetteManagerClient* LorgnetteManagerClient::Create() {
    198   return new LorgnetteManagerClientImpl();
    199 }
    200 
    201 }  // namespace chromeos
    202