blob: d1c3c9a73e6fbe9b71ffbd4e49c67a1e9a549d4b [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/events/event_ack_data.h"
#include "base/callback.h"
#include "base/guid.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/service_worker_context.h"
namespace extensions {
namespace {
// Information about an unacked event.
// std::string - GUID of the Service Worker's external request for the event.
// int - RenderProcessHost id.
using EventInfo = std::pair<std::string, int>;
} // namespace
// Class that holds map of unacked event information keyed by event id, accessed
// on IO thread.
// TODO(lazyboy): Could this potentially be owned exclusively (and deleted) on
// the IO thread, thus not requiring RefCounted?
class EventAckData::IOEventInfo
: public base::RefCountedThreadSafe<IOEventInfo> {
public:
IOEventInfo() = default;
// Map of event information keyed by event_id.
std::map<int, EventInfo> event_map;
private:
friend class base::RefCountedThreadSafe<IOEventInfo>;
~IOEventInfo() = default;
DISALLOW_COPY_AND_ASSIGN(IOEventInfo);
};
// static
void EventAckData::StartExternalRequestOnIO(
content::ServiceWorkerContext* context,
int render_process_id,
int64_t version_id,
int event_id,
scoped_refptr<IOEventInfo> unacked_events) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
std::string request_uuid = base::GenerateGUID();
if (!context->StartingExternalRequest(version_id, request_uuid)) {
LOG(ERROR) << "StartExternalRequest failed";
return;
}
// TODO(lazyboy): Clean up |unacked_events_| if RenderProcessHost died before
// it got a chance to ack |event_id|. This shouldn't happen in common cases.
std::map<int, EventInfo>& unacked_events_map = unacked_events->event_map;
auto insert_result = unacked_events_map.insert(std::make_pair(
event_id, std::make_pair(request_uuid, render_process_id)));
DCHECK(insert_result.second) << "EventAckData: Duplicate event_id.";
}
// static
void EventAckData::FinishExternalRequestOnIO(
content::ServiceWorkerContext* context,
int render_process_id,
int64_t version_id,
int event_id,
scoped_refptr<IOEventInfo> unacked_events,
base::OnceClosure failure_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
std::map<int, EventInfo>& unacked_events_map = unacked_events->event_map;
auto request_info_iter = unacked_events_map.find(event_id);
if (request_info_iter == unacked_events_map.end() ||
request_info_iter->second.second != render_process_id) {
std::move(failure_callback).Run();
return;
}
std::string request_uuid = std::move(request_info_iter->second.first);
unacked_events_map.erase(request_info_iter);
if (!context->FinishedExternalRequest(version_id, request_uuid))
std::move(failure_callback).Run();
}
EventAckData::EventAckData()
: unacked_events_(base::MakeRefCounted<IOEventInfo>()),
weak_factory_(this) {}
EventAckData::~EventAckData() = default;
void EventAckData::IncrementInflightEvent(
content::ServiceWorkerContext* context,
int render_process_id,
int64_t version_id,
int event_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::ServiceWorkerContext::RunTask(
base::CreateSingleThreadTaskRunnerWithTraits(
{content::BrowserThread::IO}),
FROM_HERE, context,
base::BindOnce(&EventAckData::StartExternalRequestOnIO, context,
render_process_id, version_id, event_id, unacked_events_));
}
void EventAckData::DecrementInflightEvent(
content::ServiceWorkerContext* context,
int render_process_id,
int64_t version_id,
int event_id,
base::OnceClosure failure_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::ServiceWorkerContext::RunTask(
base::CreateSingleThreadTaskRunnerWithTraits(
{content::BrowserThread::IO}),
FROM_HERE, context,
base::BindOnce(&EventAckData::FinishExternalRequestOnIO, context,
render_process_id, version_id, event_id, unacked_events_,
std::move(failure_callback)));
}
} // namespace extensions