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 "extensions/browser/api/serial/serial_event_dispatcher.h"
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"
12 namespace extensions
{
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
;
26 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<SerialEventDispatcher
> >
27 g_factory
= LAZY_INSTANCE_INITIALIZER
;
30 BrowserContextKeyedAPIFactory
<SerialEventDispatcher
>*
31 SerialEventDispatcher::GetFactoryInstance() {
32 return g_factory
.Pointer();
36 SerialEventDispatcher
* SerialEventDispatcher::Get(
37 content::BrowserContext
* context
) {
38 return BrowserContextKeyedAPIFactory
<SerialEventDispatcher
>::Get(context
);
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_
;
49 SerialEventDispatcher::~SerialEventDispatcher() {
52 SerialEventDispatcher::ReceiveParams::ReceiveParams() {
55 SerialEventDispatcher::ReceiveParams::~ReceiveParams() {
58 void SerialEventDispatcher::PollConnection(const std::string
& extension_id
,
60 DCHECK_CURRENTLY_ON(thread_id_
);
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
;
73 void SerialEventDispatcher::StartReceive(const ReceiveParams
& params
) {
74 DCHECK_CURRENTLY_ON(params
.thread_id
);
76 SerialConnection
* connection
=
77 params
.connections
->Get(params
.extension_id
, params
.connection_id
);
80 DCHECK(params
.extension_id
== connection
->owner_extension_id());
82 if (connection
->paused())
85 connection
->Receive(base::Bind(&ReceiveCallback
, params
));
89 void SerialEventDispatcher::ReceiveCallback(const ReceiveParams
& params
,
90 const std::vector
<char>& data
,
91 serial::ReceiveError error
) {
92 DCHECK_CURRENTLY_ON(params
.thread_id
);
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
.size() > 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());
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
);
119 connection
->set_paused(true);
123 // Queue up the next read operation.
124 BrowserThread::PostTask(
125 params
.thread_id
, FROM_HERE
, base::Bind(&StartReceive
, params
));
129 void SerialEventDispatcher::PostEvent(const ReceiveParams
& params
,
130 scoped_ptr
<extensions::Event
> event
) {
131 DCHECK_CURRENTLY_ON(params
.thread_id
);
133 BrowserThread::PostTask(BrowserThread::UI
,
135 base::Bind(&DispatchEvent
,
136 params
.browser_context_id
,
138 base::Passed(event
.Pass())));
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
);
147 content::BrowserContext
* context
=
148 reinterpret_cast<content::BrowserContext
*>(browser_context_id
);
149 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context
))
152 EventRouter
* router
= EventRouter::Get(context
);
154 router
->DispatchEventToExtension(extension_id
, event
.Pass());
157 } // namespace core_api
159 } // namespace extensions