Update client side navigator.connect API to use ServicePortCollection [2/3]
[chromium-blink-merge.git] / content / browser / navigator_connect / navigator_connect_context_impl.cc
blob94bdc82e7e64fd53297a5b806a017a62e638cfd3
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 "content/browser/navigator_connect/navigator_connect_context_impl.h"
7 #include "content/browser/message_port_message_filter.h"
8 #include "content/browser/message_port_service.h"
9 #include "content/browser/navigator_connect/service_port_service_impl.h"
10 #include "content/public/browser/message_port_provider.h"
11 #include "content/public/browser/navigator_connect_service_factory.h"
12 #include "content/public/common/navigator_connect_client.h"
14 namespace content {
16 struct NavigatorConnectContextImpl::Port {
17 int message_port_id;
18 // Set to nullptr when the ServicePortService goes away.
19 ServicePortServiceImpl* service;
22 NavigatorConnectContextImpl::NavigatorConnectContextImpl() {
25 NavigatorConnectContextImpl::~NavigatorConnectContextImpl() {
28 void NavigatorConnectContextImpl::AddFactory(
29 scoped_ptr<NavigatorConnectServiceFactory> factory) {
30 DCHECK_CURRENTLY_ON(BrowserThread::UI);
31 BrowserThread::PostTask(
32 BrowserThread::IO, FROM_HERE,
33 base::Bind(&NavigatorConnectContextImpl::AddFactoryOnIOThread, this,
34 base::Passed(&factory)));
37 void NavigatorConnectContextImpl::AddFactoryOnIOThread(
38 scoped_ptr<NavigatorConnectServiceFactory> factory) {
39 DCHECK_CURRENTLY_ON(BrowserThread::IO);
40 service_factories_.push_back(factory.release());
43 void NavigatorConnectContextImpl::Connect(
44 const GURL& target_url,
45 const GURL& origin,
46 ServicePortServiceImpl* service_port_service,
47 const ConnectCallback& callback) {
48 DCHECK_CURRENTLY_ON(BrowserThread::IO);
49 // Create a new message channel. Use |this| as delegate for both ports until
50 // the real delegate for the service port is known later on.
51 int client_port_id;
52 int service_port;
53 MessagePortProvider::CreateMessageChannel(this, &client_port_id,
54 &service_port);
55 // Hold messages send to the client while setting up connection.
56 MessagePortService::GetInstance()->HoldMessages(client_port_id);
58 Port& client_port = ports_[client_port_id];
59 client_port.message_port_id = client_port_id;
60 client_port.service = service_port_service;
62 // The message_port_id stored in the client object is the one associated with
63 // the service.
64 NavigatorConnectClient client(target_url, origin, service_port);
66 // Find factory to handle request, more recently added factories should take
67 // priority as per comment at NavigatorConnectContext::AddFactory..
68 NavigatorConnectServiceFactory* factory = nullptr;
69 for (auto it = service_factories_.rbegin(); it != service_factories_.rend();
70 ++it) {
71 if ((*it)->HandlesUrl(client.target_url)) {
72 factory = *it;
73 break;
77 if (!factory) {
78 // No factories found.
79 OnConnectResult(client, client_port_id, callback, nullptr, false);
80 return;
83 // Actually initiate connection.
84 factory->Connect(
85 client, base::Bind(&NavigatorConnectContextImpl::OnConnectResult, this,
86 client, client_port_id, callback));
89 void NavigatorConnectContextImpl::ServicePortServiceDestroyed(
90 ServicePortServiceImpl* service_port_service) {
91 for (auto& port : ports_) {
92 if (port.second.service != service_port_service)
93 continue;
94 port.second.service = nullptr;
95 // TODO(mek): Should actually inform other side of connections that the
96 // connection was closed, or in the case of service workers somehow keep
97 // track of the connection.
101 void NavigatorConnectContextImpl::SendMessage(
102 int route_id,
103 const MessagePortMessage& message,
104 const std::vector<TransferredMessagePort>& sent_message_ports) {
105 DCHECK(ports_.find(route_id) != ports_.end());
106 const Port& port = ports_[route_id];
107 if (!port.service) {
108 // TODO(mek): Figure out what to do in this situation.
109 return;
112 port.service->PostMessageToClient(route_id, message, sent_message_ports);
115 void NavigatorConnectContextImpl::SendMessagesAreQueued(int route_id) {
116 NOTREACHED() << "navigator.services endpoints should never queue messages.";
119 void NavigatorConnectContextImpl::OnConnectResult(
120 const NavigatorConnectClient& client,
121 int client_message_port_id,
122 const ConnectCallback& callback,
123 MessagePortDelegate* delegate,
124 bool data_as_values) {
125 DCHECK_CURRENTLY_ON(BrowserThread::IO);
126 if (delegate) {
127 DCHECK(!data_as_values) << "Data as values is not currently implemented";
128 // TODO(mek): Might have to do something else if the client connection got
129 // severed while the service side connection was being set up.
131 // Update service side port with delegate.
132 MessagePortService::GetInstance()->UpdateMessagePort(
133 client.message_port_id, delegate, client.message_port_id);
134 callback.Run(client_message_port_id, true);
135 MessagePortService::GetInstance()->ReleaseMessages(client_message_port_id);
136 } else {
137 // Destroy ports since connection failed.
138 MessagePortService::GetInstance()->Destroy(client.message_port_id);
139 MessagePortService::GetInstance()->Destroy(client_message_port_id);
140 ports_.erase(client_message_port_id);
141 callback.Run(MSG_ROUTING_NONE, false);
145 } // namespace content