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