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.
5 #include "chrome/browser/extensions/api/serial/serial_event_dispatcher.h"
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"
13 namespace extensions
{
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
;
27 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<SerialEventDispatcher
> >
28 g_factory
= LAZY_INSTANCE_INITIALIZER
;
31 BrowserContextKeyedAPIFactory
<SerialEventDispatcher
>*
32 SerialEventDispatcher::GetFactoryInstance() {
33 return g_factory
.Pointer();
37 SerialEventDispatcher
* SerialEventDispatcher::Get(
38 content::BrowserContext
* context
) {
39 return BrowserContextKeyedAPIFactory
<SerialEventDispatcher
>::Get(context
);
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_
;
51 SerialEventDispatcher::~SerialEventDispatcher() {}
53 SerialEventDispatcher::ReceiveParams::ReceiveParams() {}
55 SerialEventDispatcher::ReceiveParams::~ReceiveParams() {}
57 void SerialEventDispatcher::PollConnection(const std::string
& extension_id
,
59 DCHECK_CURRENTLY_ON(thread_id_
);
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
;
72 void SerialEventDispatcher::StartReceive(const ReceiveParams
& params
) {
73 DCHECK_CURRENTLY_ON(params
.thread_id
);
75 SerialConnection
* connection
=
76 params
.connections
->Get(params
.extension_id
, params
.connection_id
);
79 DCHECK(params
.extension_id
== connection
->owner_extension_id());
81 if (connection
->paused())
84 connection
->Receive(base::Bind(&ReceiveCallback
, params
));
88 void SerialEventDispatcher::ReceiveCallback(const ReceiveParams
& params
,
89 const std::string
& data
,
90 serial::ReceiveError error
) {
91 DCHECK_CURRENTLY_ON(params
.thread_id
);
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());
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
);
118 connection
->set_paused(true);
122 // Queue up the next read operation.
123 BrowserThread::PostTask(params
.thread_id
,
125 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(
134 BrowserThread::UI
, FROM_HERE
,
135 base::Bind(&DispatchEvent
,
138 base::Passed(event
.Pass())));
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
);
147 Profile
* profile
= reinterpret_cast<Profile
*>(profile_id
);
148 if (!g_browser_process
->profile_manager()->IsValidProfile(profile
))
151 EventRouter
* router
= EventRouter::Get(profile
);
153 router
->DispatchEventToExtension(extension_id
, event
.Pass());
158 } // namespace extensions