Home | History | Annotate | Download | only in serial
      1 // Copyright 2013 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 "chrome/browser/extensions/api/serial/serial_event_dispatcher.h"
      6 
      7 #include "chrome/browser/browser_process.h"
      8 #include "chrome/browser/extensions/api/serial/serial_connection.h"
      9 #include "chrome/browser/profiles/profile.h"
     10 #include "chrome/browser/profiles/profile_manager.h"
     11 #include "extensions/browser/event_router.h"
     12 
     13 namespace extensions {
     14 
     15 namespace api {
     16 
     17 namespace {
     18 
     19 bool ShouldPauseOnReceiveError(serial::ReceiveError error) {
     20   return error == serial::RECEIVE_ERROR_DEVICE_LOST ||
     21       error == serial::RECEIVE_ERROR_SYSTEM_ERROR ||
     22       error == serial::RECEIVE_ERROR_DISCONNECTED;
     23 }
     24 
     25 }  // namespace
     26 
     27 static base::LazyInstance<BrowserContextKeyedAPIFactory<SerialEventDispatcher> >
     28     g_factory = LAZY_INSTANCE_INITIALIZER;
     29 
     30 // static
     31 BrowserContextKeyedAPIFactory<SerialEventDispatcher>*
     32 SerialEventDispatcher::GetFactoryInstance() {
     33   return g_factory.Pointer();
     34 }
     35 
     36 // static
     37 SerialEventDispatcher* SerialEventDispatcher::Get(
     38     content::BrowserContext* context) {
     39   return BrowserContextKeyedAPIFactory<SerialEventDispatcher>::Get(context);
     40 }
     41 
     42 SerialEventDispatcher::SerialEventDispatcher(content::BrowserContext* context)
     43     : thread_id_(SerialConnection::kThreadId),
     44       profile_(Profile::FromBrowserContext(context)) {
     45   ApiResourceManager<SerialConnection>* manager =
     46       ApiResourceManager<SerialConnection>::Get(profile_);
     47   DCHECK(manager) << "No serial connection manager.";
     48   connections_ = manager->data_;
     49 }
     50 
     51 SerialEventDispatcher::~SerialEventDispatcher() {}
     52 
     53 SerialEventDispatcher::ReceiveParams::ReceiveParams() {}
     54 
     55 SerialEventDispatcher::ReceiveParams::~ReceiveParams() {}
     56 
     57 void SerialEventDispatcher::PollConnection(const std::string& extension_id,
     58                                            int connection_id) {
     59   DCHECK_CURRENTLY_ON(thread_id_);
     60 
     61   ReceiveParams params;
     62   params.thread_id = thread_id_;
     63   params.profile_id = profile_;
     64   params.extension_id = extension_id;
     65   params.connections = connections_;
     66   params.connection_id = connection_id;
     67 
     68   StartReceive(params);
     69 }
     70 
     71 // static
     72 void SerialEventDispatcher::StartReceive(const ReceiveParams& params) {
     73   DCHECK_CURRENTLY_ON(params.thread_id);
     74 
     75   SerialConnection* connection =
     76       params.connections->Get(params.extension_id, params.connection_id);
     77   if (!connection)
     78     return;
     79   DCHECK(params.extension_id == connection->owner_extension_id());
     80 
     81   if (connection->paused())
     82     return;
     83 
     84   connection->Receive(base::Bind(&ReceiveCallback, params));
     85 }
     86 
     87 // static
     88 void SerialEventDispatcher::ReceiveCallback(const ReceiveParams& params,
     89                                             const std::string& data,
     90                                             serial::ReceiveError error) {
     91   DCHECK_CURRENTLY_ON(params.thread_id);
     92 
     93   // Note that an error (e.g. timeout) does not necessarily mean that no data
     94   // was read, so we may fire an onReceive regardless of any error code.
     95   if (data.length() > 0) {
     96     serial::ReceiveInfo receive_info;
     97     receive_info.connection_id = params.connection_id;
     98     receive_info.data = data;
     99     scoped_ptr<base::ListValue> args = serial::OnReceive::Create(receive_info);
    100     scoped_ptr<extensions::Event> event(
    101         new extensions::Event(serial::OnReceive::kEventName, args.Pass()));
    102     PostEvent(params, event.Pass());
    103   }
    104 
    105   if (error != serial::RECEIVE_ERROR_NONE) {
    106     serial::ReceiveErrorInfo error_info;
    107     error_info.connection_id = params.connection_id;
    108     error_info.error = error;
    109     scoped_ptr<base::ListValue> args =
    110         serial::OnReceiveError::Create(error_info);
    111     scoped_ptr<extensions::Event> event(
    112         new extensions::Event(serial::OnReceiveError::kEventName, args.Pass()));
    113     PostEvent(params, event.Pass());
    114     if (ShouldPauseOnReceiveError(error)) {
    115       SerialConnection* connection =
    116           params.connections->Get(params.extension_id, params.connection_id);
    117       if (connection)
    118         connection->set_paused(true);
    119     }
    120   }
    121 
    122   // Queue up the next read operation.
    123   BrowserThread::PostTask(params.thread_id,
    124                           FROM_HERE,
    125                           base::Bind(&StartReceive, params));
    126 }
    127 
    128 // static
    129 void SerialEventDispatcher::PostEvent(const ReceiveParams& params,
    130                                       scoped_ptr<extensions::Event> event) {
    131   DCHECK_CURRENTLY_ON(params.thread_id);
    132 
    133   BrowserThread::PostTask(
    134       BrowserThread::UI, FROM_HERE,
    135       base::Bind(&DispatchEvent,
    136                  params.profile_id,
    137                  params.extension_id,
    138                  base::Passed(event.Pass())));
    139 }
    140 
    141 // static
    142 void SerialEventDispatcher::DispatchEvent(void* profile_id,
    143                                           const std::string& extension_id,
    144                                           scoped_ptr<extensions::Event> event) {
    145   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    146 
    147   Profile* profile = reinterpret_cast<Profile*>(profile_id);
    148   if (!g_browser_process->profile_manager()->IsValidProfile(profile))
    149     return;
    150 
    151   EventRouter* router = EventRouter::Get(profile);
    152   if (router)
    153     router->DispatchEventToExtension(extension_id, event.Pass());
    154 }
    155 
    156 }  // namespace api
    157 
    158 }  // namespace extensions
    159