Chromium Code Reviews| Index: components/copresence/rpc/rpc_handler.cc |
| diff --git a/components/copresence/rpc/rpc_handler.cc b/components/copresence/rpc/rpc_handler.cc |
| index 7c751ab11814233f680b7fe7f14c41a574b72917..099e66fc5973e54f7f4c621cbda60c895df41ff9 100644 |
| --- a/components/copresence/rpc/rpc_handler.cc |
| +++ b/components/copresence/rpc/rpc_handler.cc |
| @@ -21,6 +21,7 @@ |
| #include "components/copresence/copresence_switches.h" |
| #include "components/copresence/handlers/directive_handler.h" |
| +#include "components/copresence/handlers/gcm_handler.h" |
| #include "components/copresence/proto/codes.pb.h" |
| #include "components/copresence/proto/data.pb.h" |
| #include "components/copresence/proto/rpcs.pb.h" |
| @@ -38,11 +39,15 @@ using google::protobuf::RepeatedPtrField; |
| const char RpcHandler::kReportRequestRpcName[] = "report"; |
| -// Number of characters of suffix to log for auth tokens |
| -const int kTokenSuffix = 5; |
| - |
| namespace { |
| +const int kTokenLoggingSuffix = 5; |
| +const int kInvalidTokenExpiryTimeMs = 10 * 60 * 1000; // 10 minutes. |
| +const int kMaxInvalidTokens = 10000; |
| +const char kRegisterDeviceRpcName[] = "registerdevice"; |
| +const char kDefaultCopresenceServer[] = |
| + "https://www.googleapis.com/copresence/v2/copresence"; |
| + |
| // UrlSafe is defined as: |
| // '/' represented by a '_' and '+' represented by a '-' |
| // TODO(rkc): Move this to the wrapper. |
| @@ -52,11 +57,6 @@ std::string ToUrlSafe(std::string token) { |
| return token; |
| } |
| -const int kInvalidTokenExpiryTimeMs = 10 * 60 * 1000; // 10 minutes. |
| -const int kMaxInvalidTokens = 10000; |
| -const char kRegisterDeviceRpcName[] = "registerdevice"; |
| -const char kDefaultCopresenceServer[] = |
| - "https://www.googleapis.com/copresence/v2/copresence"; |
| // Logging |
| @@ -94,6 +94,17 @@ bool ReportErrorLogged(const ReportResponse& response) { |
| return result; |
| } |
| +const std::string LoggingStrForToken(const std::string& auth_token) { |
| + std::string token_str = "anonymous"; |
| + if (!auth_token.empty()) { |
| + std::string token_suffix = auth_token.substr( |
| + auth_token.length() - kTokenLoggingSuffix, kTokenLoggingSuffix); |
| + token_str = base::StringPrintf("token ...%s", token_suffix.c_str()); |
| + } |
| + return token_str; |
| +} |
| + |
| + |
| // Request construction |
| // TODO(ckehoe): Move these into a separate file? |
| @@ -149,14 +160,6 @@ void AddTokenToRequest(const AudioToken& token, ReportRequest* request) { |
| signals->set_observed_time_millis(base::Time::Now().ToJsTime()); |
| } |
| -const std::string LoggingStrForToken(const std::string& auth_token) { |
| - std::string token_str = auth_token.empty() ? "anonymous" : |
| - base::StringPrintf("token ...%s", |
| - auth_token.substr(auth_token.length() - kTokenSuffix, |
| - kTokenSuffix).c_str()); |
| - return token_str; |
| -} |
| - |
| } // namespace |
| @@ -164,20 +167,28 @@ const std::string LoggingStrForToken(const std::string& auth_token) { |
| RpcHandler::RpcHandler(CopresenceDelegate* delegate, |
| DirectiveHandler* directive_handler, |
| + GCMHandler* gcm_handler, |
| const PostCallback& server_post_callback) |
| : delegate_(delegate), |
| directive_handler_(directive_handler), |
| + gcm_handler_(gcm_handler), |
| server_post_callback_(server_post_callback), |
| invalid_audio_token_cache_( |
| base::TimeDelta::FromMilliseconds(kInvalidTokenExpiryTimeMs), |
| kMaxInvalidTokens) { |
| DCHECK(delegate_); |
| DCHECK(directive_handler_); |
| + // |gcm_handler_| is optional. |
|
rkc
2014/11/07 20:24:15
Unnecessary comment.
Charlie
2014/11/07 20:50:12
Do you mean confusing? This is to explain why we'r
rkc
2014/11/07 21:05:11
No, just unnecessary. Not DCHECK'ing something isn
|
| if (server_post_callback_.is_null()) { |
| server_post_callback_ = |
| base::Bind(&RpcHandler::SendHttpPost, base::Unretained(this)); |
| } |
| + |
| + if (gcm_handler_) { |
| + gcm_handler_->GetGcmId( |
| + base::Bind(&RpcHandler::RegisterGcmId, base::Unretained(this))); |
| + } |
| } |
| RpcHandler::~RpcHandler() { |
| @@ -258,7 +269,8 @@ void RpcHandler::ReportTokens(const std::vector<AudioToken>& tokens) { |
| } |
| } |
| -// Private methods |
| + |
| +// Private functions. |
| RpcHandler::PendingRequest::PendingRequest(scoped_ptr<ReportRequest> report, |
| const std::string& app_id, |
| @@ -275,11 +287,17 @@ void RpcHandler::RegisterForToken(const std::string& auth_token) { |
| DVLOG(2) << "Sending " << LoggingStrForToken(auth_token) |
| << " registration to server."; |
| - // Mark registration as in progress. |
| - device_id_by_auth_token_[auth_token] = ""; |
| - |
| scoped_ptr<RegisterDeviceRequest> request(new RegisterDeviceRequest); |
| - request->mutable_push_service()->set_service(PUSH_SERVICE_NONE); |
| + |
| + // Add a GCM ID for authenticated registration, if we have one. |
| + if (auth_token.empty() || gcm_id_.empty()) { |
| + request->mutable_push_service()->set_service(PUSH_SERVICE_NONE); |
| + } else { |
| + DVLOG(2) << "Registering GCM ID with " << LoggingStrForToken(auth_token); |
| + request->mutable_push_service()->set_service(GCM); |
| + request->mutable_push_service()->mutable_gcm_registration() |
| + ->set_device_token(gcm_id_); |
| + } |
| // Only identify as a Chrome device if we're in anonymous mode. |
| // Authenticated calls come from a "GAIA device". |
| @@ -288,18 +306,28 @@ void RpcHandler::RegisterForToken(const std::string& auth_token) { |
| request->mutable_device_identifiers()->mutable_registrant(); |
| identity->set_type(CHROME); |
| identity->set_chrome_id(base::GenerateGUID()); |
| + |
| + // Since we're generating a new "Chrome ID" here, |
| + // we need to make sure this isn't a duplicate registration. |
| + DCHECK_EQ(0u, device_id_by_auth_token_.count(std::string())) |
| + << "Attempted anonymous re-registration"; |
| } |
| + bool gcm_pending = !auth_token.empty() && gcm_handler_ && gcm_id_.empty(); |
| SendServerRequest( |
| kRegisterDeviceRpcName, |
| - std::string(), // device ID |
| + // This will have the side effect of populating an empty device ID |
| + // for this auth token in the map. This is what we want, |
| + // to mark registration as being in progress. |
| + device_id_by_auth_token_[auth_token], |
| std::string(), // app ID |
| auth_token, |
| request.Pass(), |
| base::Bind(&RpcHandler::RegisterResponseHandler, |
| // On destruction, this request will be cancelled. |
| base::Unretained(this), |
| - auth_token)); |
| + auth_token, |
| + gcm_pending)); |
| } |
| void RpcHandler::ProcessQueuedRequests(const std::string& auth_token) { |
| @@ -343,8 +371,41 @@ void RpcHandler::SendReportRequest(scoped_ptr<ReportRequest> request, |
| StatusCallback()); |
| } |
| +// Store a GCM ID and send it to the server if needed. The constructor passes |
| +// this callback to the GCMHandler to receive the ID whenever it's ready. |
| +// It may be returned immediately, if the ID is cached, or require a server |
| +// round-trip. This ID must then be passed along to the copresence server. |
| +// There are a few ways this can happen for each auth token: |
| +// |
| +// 1. The GCM ID is available when we first register, and is passed along |
| +// with the RegisterDeviceRequest. |
| +// |
| +// 2. The GCM ID becomes available after the RegisterDeviceRequest has |
| +// completed. Then the loop in this function will invoke RegisterForToken() |
| +// again to pass on the ID. |
| +// |
| +// 3. The GCM ID becomes available after the RegisterDeviceRequest is sent, |
| +// but before it completes. In this case, the gcm_pending flag is passed |
| +// through to the RegisterResponseHandler, which invokes RegisterForToken() |
| +// again to pass on the ID. The loop here must skip pending registrations, |
| +// as the device ID will be empty. |
| +// |
| +// TODO(ckehoe): Add tests for these scenarios. |
| +void RpcHandler::RegisterGcmId(const std::string& gcm_id) { |
| + gcm_id_ = gcm_id; |
| + if (!gcm_id.empty()) { |
| + for (const auto& registration : device_id_by_auth_token_) { |
| + const std::string& auth_token = registration.first; |
| + const std::string& device_id = registration.second; |
| + if (!auth_token.empty() && !device_id.empty()) |
|
rkc
2014/11/07 20:24:15
If the device_id is not empty, doesn't that mean t
Charlie
2014/11/07 20:50:13
To pass the GCM ID up to the server. The new regis
rkc
2014/11/07 21:05:11
Ah right, case 2.
|
| + RegisterForToken(auth_token); |
| + } |
| + } |
| +} |
| + |
| void RpcHandler::RegisterResponseHandler( |
| const std::string& auth_token, |
| + bool gcm_pending, |
| HttpPost* completed_post, |
| int http_status_code, |
| const std::string& response_data) { |
| @@ -371,6 +432,10 @@ void RpcHandler::RegisterResponseHandler( |
| device_id_by_auth_token_[auth_token] = device_id; |
| DVLOG(2) << LoggingStrForToken(auth_token) |
| << " device registration successful. Id: " << device_id; |
| + |
| + // If we have a GCM ID now, and didn't before, pass it on to the server. |
| + if (gcm_pending && !gcm_id_.empty()) |
| + RegisterForToken(auth_token); |
| } |
| // Send or fail requests on this auth token. |