- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / cast_channel / cast_channel_api.cc
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/cast_channel/cast_channel_api.h"
6
7 #include "base/json/json_writer.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/values.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/extensions/api/cast_channel/cast_socket.h"
12 #include "chrome/browser/extensions/event_router.h"
13 #include "chrome/browser/extensions/extension_system.h"
14 #include "chrome/browser/net/chrome_net_log.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "net/base/net_errors.h"
18 #include "url/gurl.h"
19
20 namespace extensions {
21
22 namespace Close = cast_channel::Close;
23 namespace OnError = cast_channel::OnError;
24 namespace OnMessage = cast_channel::OnMessage;
25 namespace Open = cast_channel::Open;
26 namespace Send = cast_channel::Send;
27 using cast_channel::CastSocket;
28 using cast_channel::ChannelError;
29 using cast_channel::ChannelInfo;
30 using cast_channel::MessageInfo;
31 using cast_channel::ReadyState;
32 using content::BrowserThread;
33
34 namespace {
35
36 // T is an extension dictionary (MessageInfo or ChannelInfo)
37 template <class T>
38 std::string ParamToString(const T& info) {
39   scoped_ptr<base::DictionaryValue> dict = info.ToValue();
40   std::string out;
41   base::JSONWriter::Write(dict.get(), &out);
42   return out;
43 }
44
45 }  // namespace
46
47 CastChannelAPI::CastChannelAPI(Profile* profile)
48   : profile_(profile) {
49   DCHECK(profile_);
50 }
51
52 // static
53 CastChannelAPI* CastChannelAPI::Get(Profile* profile) {
54   return ProfileKeyedAPIFactory<CastChannelAPI>::GetForProfile(profile);
55 }
56
57 static base::LazyInstance<ProfileKeyedAPIFactory<CastChannelAPI> > g_factory =
58     LAZY_INSTANCE_INITIALIZER;
59
60 // static
61 ProfileKeyedAPIFactory<CastChannelAPI>* CastChannelAPI::GetFactoryInstance() {
62   return &g_factory.Get();
63 }
64
65 scoped_ptr<CastSocket> CastChannelAPI::CreateCastSocket(
66     const std::string& extension_id, const GURL& url) {
67   if (socket_for_test_.get()) {
68     return socket_for_test_.Pass();
69   } else {
70     return scoped_ptr<CastSocket>(
71         new CastSocket(extension_id, url, this,
72                        g_browser_process->net_log()));
73   }
74 }
75
76 void CastChannelAPI::SetSocketForTest(scoped_ptr<CastSocket> socket_for_test) {
77   socket_for_test_ = socket_for_test.Pass();
78 }
79
80 void CastChannelAPI::OnError(const CastSocket* socket,
81                              cast_channel::ChannelError error) {
82   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
83   ChannelInfo channel_info;
84   socket->FillChannelInfo(&channel_info);
85   channel_info.error_state = error;
86   scoped_ptr<base::ListValue> results = OnError::Create(channel_info);
87   scoped_ptr<Event> event(new Event(OnError::kEventName, results.Pass()));
88   extensions::ExtensionSystem::Get(profile_)->event_router()->
89     DispatchEventToExtension(socket->owner_extension_id(), event.Pass());
90
91   // Destroy the socket that caused the error.
92   ApiResourceManager<CastSocket>* manager =
93     ApiResourceManager<CastSocket>::Get(profile_);
94   manager->Remove(socket->owner_extension_id(), socket->id());
95 }
96
97 void CastChannelAPI::OnMessage(const CastSocket* socket,
98                                const MessageInfo& message_info) {
99   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
100   ChannelInfo channel_info;
101   socket->FillChannelInfo(&channel_info);
102   scoped_ptr<base::ListValue> results =
103     OnMessage::Create(channel_info, message_info);
104   DVLOG(1) << "Sending message " << ParamToString(message_info)
105            << " to channel " << ParamToString(channel_info);
106   scoped_ptr<Event> event(new Event(OnMessage::kEventName, results.Pass()));
107   extensions::ExtensionSystem::Get(profile_)->event_router()->
108     DispatchEventToExtension(socket->owner_extension_id(), event.Pass());
109 }
110
111 CastChannelAPI::~CastChannelAPI() {}
112
113 CastChannelAsyncApiFunction::CastChannelAsyncApiFunction()
114   : manager_(NULL), error_(cast_channel::CHANNEL_ERROR_NONE) { }
115
116 CastChannelAsyncApiFunction::~CastChannelAsyncApiFunction() { }
117
118 bool CastChannelAsyncApiFunction::PrePrepare() {
119   manager_ = ApiResourceManager<CastSocket>::Get(GetProfile());
120   return true;
121 }
122
123 bool CastChannelAsyncApiFunction::Respond() {
124   return error_ != cast_channel::CHANNEL_ERROR_NONE;
125 }
126
127 CastSocket* CastChannelAsyncApiFunction::GetSocketOrCompleteWithError(
128     int channel_id) {
129   CastSocket* socket = GetSocket(channel_id);
130   if (!socket) {
131     SetResultFromError(cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID);
132     AsyncWorkCompleted();
133   }
134   return socket;
135 }
136
137 int CastChannelAsyncApiFunction::AddSocket(CastSocket* socket) {
138   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
139   DCHECK(socket);
140   DCHECK(manager_);
141   const int id = manager_->Add(socket);
142   socket->set_id(id);
143   return id;
144 }
145
146 void CastChannelAsyncApiFunction::RemoveSocket(int channel_id) {
147   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
148   DCHECK(manager_);
149   manager_->Remove(extension_->id(), channel_id);
150 }
151
152 void CastChannelAsyncApiFunction::SetResultFromSocket(int channel_id) {
153   CastSocket* socket = GetSocket(channel_id);
154   DCHECK(socket);
155   ChannelInfo channel_info;
156   socket->FillChannelInfo(&channel_info);
157   error_ = socket->error_state();
158   SetResultFromChannelInfo(channel_info);
159 }
160
161 void CastChannelAsyncApiFunction::SetResultFromError(ChannelError error) {
162   ChannelInfo channel_info;
163   channel_info.channel_id = -1;
164   channel_info.url = "";
165   channel_info.ready_state = cast_channel::READY_STATE_CLOSED;
166   channel_info.error_state = error;
167   SetResultFromChannelInfo(channel_info);
168   error_ = error;
169 }
170
171 CastSocket* CastChannelAsyncApiFunction::GetSocket(int channel_id) {
172   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
173   DCHECK(manager_);
174   return manager_->Get(extension_->id(), channel_id);
175 }
176
177 void CastChannelAsyncApiFunction::SetResultFromChannelInfo(
178     const ChannelInfo& channel_info) {
179   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
180   SetResult(channel_info.ToValue().release());
181 }
182
183 CastChannelOpenFunction::CastChannelOpenFunction()
184   : new_channel_id_(0) { }
185
186 CastChannelOpenFunction::~CastChannelOpenFunction() { }
187
188 bool CastChannelOpenFunction::PrePrepare() {
189   api_ = CastChannelAPI::Get(GetProfile());
190   return CastChannelAsyncApiFunction::PrePrepare();
191 }
192
193 bool CastChannelOpenFunction::Prepare() {
194   params_ = Open::Params::Create(*args_);
195   EXTENSION_FUNCTION_VALIDATE(params_.get());
196   return true;
197 }
198
199 void CastChannelOpenFunction::AsyncWorkStart() {
200   DCHECK(api_);
201   scoped_ptr<CastSocket> socket = api_->CreateCastSocket(extension_->id(),
202                                                          GURL(params_->url));
203   new_channel_id_ = AddSocket(socket.release());
204   GetSocket(new_channel_id_)->Connect(
205       base::Bind(&CastChannelOpenFunction::OnOpen, this));
206 }
207
208 void CastChannelOpenFunction::OnOpen(int result) {
209   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
210   SetResultFromSocket(new_channel_id_);
211   AsyncWorkCompleted();
212 }
213
214 CastChannelSendFunction::CastChannelSendFunction() { }
215
216 CastChannelSendFunction::~CastChannelSendFunction() { }
217
218 bool CastChannelSendFunction::Prepare() {
219   params_ = Send::Params::Create(*args_);
220   EXTENSION_FUNCTION_VALIDATE(params_.get());
221   return true;
222 }
223
224 void CastChannelSendFunction::AsyncWorkStart() {
225   CastSocket* socket = GetSocketOrCompleteWithError(
226       params_->channel.channel_id);
227   if (socket)
228     socket->SendMessage(params_->message,
229                         base::Bind(&CastChannelSendFunction::OnSend, this));
230 }
231
232 void CastChannelSendFunction::OnSend(int result) {
233   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
234   if (result < 0) {
235     SetResultFromError(cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
236   } else {
237     SetResultFromSocket(params_->channel.channel_id);
238   }
239   AsyncWorkCompleted();
240 }
241
242 CastChannelCloseFunction::CastChannelCloseFunction() { }
243
244 CastChannelCloseFunction::~CastChannelCloseFunction() { }
245
246 bool CastChannelCloseFunction::Prepare() {
247   params_ = Close::Params::Create(*args_);
248   EXTENSION_FUNCTION_VALIDATE(params_.get());
249   return true;
250 }
251
252 void CastChannelCloseFunction::AsyncWorkStart() {
253   CastSocket* socket = GetSocketOrCompleteWithError(
254       params_->channel.channel_id);
255   if (socket)
256     socket->Close(base::Bind(&CastChannelCloseFunction::OnClose, this));
257 }
258
259 void CastChannelCloseFunction::OnClose(int result) {
260   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
261   DVLOG(1) << "CastChannelCloseFunction::OnClose result = " << result;
262   if (result < 0) {
263     SetResultFromError(cast_channel::CHANNEL_ERROR_SOCKET_ERROR);
264   } else {
265     int channel_id = params_->channel.channel_id;
266     SetResultFromSocket(channel_id);
267     RemoveSocket(channel_id);
268   }
269   AsyncWorkCompleted();
270 }
271
272 }  // namespace extensions