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 "chrome/browser/extensions/api/copresence/copresence_translations.h"
7 #include "base/stl_util.h"
8 #include "chrome/common/extensions/api/copresence.h"
9 #include "components/copresence/proto/data.pb.h"
10 #include "components/copresence/proto/enums.pb.h"
11 #include "components/copresence/proto/rpcs.pb.h"
13 using copresence::AUDIO_CONFIGURATION_AUDIBLE
;
14 using copresence::AUDIO_CONFIGURATION_UNKNOWN
;
15 using copresence::BROADCAST_AND_SCAN
;
16 using copresence::BROADCAST_ONLY
;
17 using copresence::BROADCAST_SCAN_CONFIGURATION_UNKNOWN
;
18 using copresence::BroadcastScanConfiguration
;
19 using copresence::ReportRequest
;
20 using copresence::SCAN_ONLY
;
21 using copresence::TokenExchangeStrategy
;
23 using extensions::api::copresence::Strategy
;
27 const int kDefaultTimeToLiveMs
= 5 * 60 * 1000; // 5 minutes.
28 const int kMaxTimeToLiveMs
= 24 * 60 * 60 * 1000; // 24 hours.
30 // Checks and returns the ttl provided by the user. If invalid, returns -1.
31 int SanitizeTtl(int* user_ttl
) {
33 ? kDefaultTimeToLiveMs
34 : (*user_ttl
<= 0 || *user_ttl
> kMaxTimeToLiveMs
? -1 : *user_ttl
);
37 BroadcastScanConfiguration
TranslateStrategy(const Strategy
& strategy
) {
38 bool only_broadcast
= strategy
.only_broadcast
&& *strategy
.only_broadcast
;
39 bool only_scan
= strategy
.only_scan
&& *strategy
.only_scan
;
41 if (only_broadcast
&& only_scan
)
42 return BROADCAST_AND_SCAN
;
44 return BROADCAST_ONLY
;
48 return BROADCAST_SCAN_CONFIGURATION_UNKNOWN
;
51 // The strategy may be null (unspecified), so we pass it as a pointer.
52 void SetTokenExchangeStrategy(const Strategy
* strategy
,
53 BroadcastScanConfiguration default_config
,
54 TokenExchangeStrategy
* strategy_proto
) {
56 BroadcastScanConfiguration config
;
57 if (strategy
->low_power
&& *(strategy
->low_power
)) {
58 config
= BROADCAST_SCAN_CONFIGURATION_UNKNOWN
;
60 config
= TranslateStrategy(*strategy
);
61 if (config
== BROADCAST_SCAN_CONFIGURATION_UNKNOWN
)
62 config
= default_config
;
65 strategy_proto
->set_broadcast_scan_configuration(config
);
66 strategy_proto
->set_audio_configuration(
67 strategy
->audible
&& *strategy
->audible
? AUDIO_CONFIGURATION_AUDIBLE
68 : AUDIO_CONFIGURATION_UNKNOWN
);
70 strategy_proto
->set_broadcast_scan_configuration(default_config
);
71 strategy_proto
->set_audio_configuration(AUDIO_CONFIGURATION_UNKNOWN
);
77 namespace extensions
{
79 using api::copresence::Operation
;
81 // Adds a publish operation to the report request. Returns false if the
82 // publish operation was invalid.
83 bool AddPublishToRequest(const std::string
& app_id
,
84 const api::copresence::PublishOperation
& publish
,
85 ReportRequest
* request
) {
86 copresence::PublishedMessage
* publish_proto
=
87 request
->mutable_manage_messages_request()->add_message_to_publish();
88 publish_proto
->mutable_access_policy()->mutable_acl()->set_acl_type(
89 copresence::NO_ACL_CHECK
);
90 publish_proto
->set_id(publish
.id
);
91 publish_proto
->mutable_message()->mutable_type()->set_type(
92 publish
.message
.type
);
93 publish_proto
->mutable_message()->set_payload(
94 vector_as_array(&publish
.message
.payload
),
95 publish
.message
.payload
.size());
97 int ttl
= SanitizeTtl(publish
.time_to_live_millis
.get());
100 publish_proto
->mutable_access_policy()->set_ttl_millis(ttl
);
102 SetTokenExchangeStrategy(publish
.strategies
.get(),
104 publish_proto
->mutable_token_exchange_strategy());
106 DVLOG(2) << "Publishing message of type " << publish
.message
.type
<< ":\n"
107 << std::string(publish
.message
.payload
.begin(),
108 publish
.message
.payload
.end());
109 // TODO(ckehoe): Validate that required fields are non-empty, etc.
113 // Adds an unpublish operation to the report request. Returns false if the
114 // publish id was invalid.
115 bool AddUnpublishToRequest(const std::string
& publish_id
,
116 ReportRequest
* request
) {
117 if (publish_id
.empty())
120 request
->mutable_manage_messages_request()->add_id_to_unpublish(publish_id
);
121 DVLOG(2) << "Unpublishing message \"" << publish_id
<< "\"";
125 // Adds a subscribe operation to the report request. Returns false if the
126 // subscription operation was invalid.
127 bool AddSubscribeToRequest(
128 const std::string
& app_id
,
129 const api::copresence::SubscribeOperation
& subscription
,
130 SubscriptionToAppMap
* apps_by_subscription_id
,
131 ReportRequest
* request
) {
132 // Associate the subscription id with the app id.
133 SubscriptionToAppMap::iterator previous_subscription
=
134 apps_by_subscription_id
->find(subscription
.id
);
135 if (previous_subscription
== apps_by_subscription_id
->end()) {
136 (*apps_by_subscription_id
)[subscription
.id
] = app_id
;
137 } else if (previous_subscription
->second
== app_id
) {
138 VLOG(2) << "Overwriting subscription id \"" << subscription
.id
139 << "\" for app \"" << app_id
<< "\"";
141 // A conflicting association exists already.
142 VLOG(1) << "Subscription id \"" << subscription
.id
143 << "\" used by two apps: \"" << previous_subscription
->second
144 << "\" and \"" << app_id
<< "\"";
148 // Convert from IDL to server subscription format.
149 copresence::Subscription
* subscription_proto
=
150 request
->mutable_manage_subscriptions_request()->add_subscription();
151 subscription_proto
->set_id(subscription
.id
);
152 int ttl
= SanitizeTtl(subscription
.time_to_live_millis
.get());
155 subscription_proto
->set_ttl_millis(ttl
);
157 subscription_proto
->mutable_message_type()->set_type(
158 subscription
.filter
.type
);
160 SetTokenExchangeStrategy(
161 subscription
.strategies
.get(),
163 subscription_proto
->mutable_token_exchange_strategy());
165 DVLOG(2) << "Subscribing for messages of type " << subscription
.filter
.type
;
166 // TODO(ckehoe): Validate that required fields are non-empty, etc.
170 // Adds an unpublish operation to the report request. Returns false if the
171 // subscription id was invalid.
172 bool AddUnsubscribeToRequest(const std::string
& app_id
,
173 const std::string
& subscription_id
,
174 SubscriptionToAppMap
* apps_by_subscription_id
,
175 ReportRequest
* request
) {
176 if (subscription_id
.empty())
179 // Check that this subscription id belongs to this app.
180 SubscriptionToAppMap::iterator subscription
=
181 apps_by_subscription_id
->find(subscription_id
);
182 if (subscription
== apps_by_subscription_id
->end()) {
183 LOG(ERROR
) << "No such subscription \"" << subscription_id
184 << "\". Cannot unsubscribe.";
186 } else if (subscription
->second
!= app_id
) {
187 LOG(ERROR
) << "Subscription \"" << subscription_id
188 << "\" does not belong to app \"" << app_id
189 << "\". Cannot unsubscribe.";
192 apps_by_subscription_id
->erase(subscription
);
195 request
->mutable_manage_subscriptions_request()->add_id_to_unsubscribe(
197 DVLOG(2) << "Cancelling subscription \"" << subscription_id
<< "\" for app \""
202 bool PrepareReportRequestProto(
203 const std::vector
<linked_ptr
<Operation
>>& operations
,
204 const std::string
& app_id
,
205 SubscriptionToAppMap
* apps_by_subscription_id
,
206 ReportRequest
* request
) {
207 for (const linked_ptr
<Operation
>& op
: operations
) {
210 // Verify our object has exactly one operation.
211 if (static_cast<int>(op
->publish
!= nullptr) +
212 static_cast<int>(op
->subscribe
!= nullptr) +
213 static_cast<int>(op
->unpublish
!= nullptr) +
214 static_cast<int>(op
->unsubscribe
!= nullptr) != 1) {
219 if (!AddPublishToRequest(app_id
, *(op
->publish
), request
))
221 } else if (op
->subscribe
) {
222 if (!AddSubscribeToRequest(
223 app_id
, *(op
->subscribe
), apps_by_subscription_id
, request
))
225 } else if (op
->unpublish
) {
226 if (!AddUnpublishToRequest(op
->unpublish
->unpublish_id
, request
))
228 } else { // if (op->unsubscribe)
229 if (!AddUnsubscribeToRequest(app_id
,
230 op
->unsubscribe
->unsubscribe_id
,
231 apps_by_subscription_id
,
240 } // namespace extensions