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"
12 #include "extensions/browser/extension_system.h"
14 namespace extensions {
20 bool ShouldPauseOnReceiveError(serial::ReceiveError error) {
21 return error == serial::RECEIVE_ERROR_DEVICE_LOST ||
22 error == serial::RECEIVE_ERROR_SYSTEM_ERROR ||
23 error == serial::RECEIVE_ERROR_DISCONNECTED;
28 static base::LazyInstance<ProfileKeyedAPIFactory<SerialEventDispatcher> >
29 g_factory = LAZY_INSTANCE_INITIALIZER;
32 ProfileKeyedAPIFactory<SerialEventDispatcher>*
33 SerialEventDispatcher::GetFactoryInstance() {
34 return g_factory.Pointer();
38 SerialEventDispatcher* SerialEventDispatcher::Get(Profile* profile) {
39 return ProfileKeyedAPIFactory<SerialEventDispatcher>::GetForProfile(profile);
42 SerialEventDispatcher::SerialEventDispatcher(Profile* profile)
43 : thread_id_(SerialConnection::kThreadId),
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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI));
147 Profile* profile = reinterpret_cast<Profile*>(profile_id);
148 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
151 EventRouter* router = ExtensionSystem::Get(profile)->event_router();
153 router->DispatchEventToExtension(extension_id, event.Pass());
158 } // namespace extensions