ladybird/Libraries/LibWeb/IndexedDB/Internal/RequestList.cpp

104 lines
3.6 KiB
C++

/*
* Copyright (c) 2024, stelar7 <dudedbz@gmail.com>
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/IndexedDB/Internal/Algorithms.h>
#include <LibWeb/IndexedDB/Internal/IDBRequestObserver.h>
#include <LibWeb/IndexedDB/Internal/RequestList.h>
namespace Web::IndexedDB {
GC_DEFINE_ALLOCATOR(RequestList::PendingRequestProcess);
void RequestList::all_requests_processed(GC::Heap& heap, GC::Ref<GC::Function<void()>> on_complete)
{
GC::Ptr<PendingRequestProcess> pending_request_process;
for (auto const& entry : *this) {
if (!entry->processed()) {
if (!pending_request_process) {
pending_request_process = heap.allocate<PendingRequestProcess>();
}
pending_request_process->add_request_to_observe(*entry.cell());
}
}
if (pending_request_process) {
pending_request_process->after_all = GC::create_function(heap, [this, pending_request_process, on_complete] {
bool was_removed = m_pending_request_queue.remove_first_matching([pending_request_process](GC::Root<PendingRequestProcess> stored_pending_connection_process) {
return stored_pending_connection_process.ptr() == pending_request_process.ptr();
});
VERIFY(was_removed);
queue_a_database_task(on_complete);
});
m_pending_request_queue.append(pending_request_process);
} else {
queue_a_database_task(on_complete);
}
}
void RequestList::all_previous_requests_processed(GC::Heap& heap, GC::Ref<IDBRequest> const& request, GC::Ref<GC::Function<void()>> on_complete)
{
GC::Ptr<PendingRequestProcess> pending_request_process;
for (auto const& entry : *this) {
if (entry == request)
break;
if (!entry->processed()) {
if (!pending_request_process) {
pending_request_process = heap.allocate<PendingRequestProcess>();
}
pending_request_process->add_request_to_observe(*entry.cell());
}
}
if (pending_request_process) {
pending_request_process->after_all = GC::create_function(heap, [this, pending_request_process, on_complete] {
bool was_removed = m_pending_request_queue.remove_first_matching([pending_request_process](GC::Root<PendingRequestProcess> stored_pending_connection_process) {
return stored_pending_connection_process.ptr() == pending_request_process.ptr();
});
VERIFY(was_removed);
queue_a_database_task(on_complete);
});
m_pending_request_queue.append(*pending_request_process);
} else {
queue_a_database_task(on_complete);
}
}
void RequestList::PendingRequestProcess::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(requests_waiting_on);
visitor.visit(after_all);
}
void RequestList::PendingRequestProcess::add_request_to_observe(GC::Ref<IDBRequest> request)
{
auto request_observer = heap().allocate<IDBRequestObserver>(request);
request_observer->set_request_processed_changed_observer(GC::create_function(heap(), [this] {
VERIFY(!requests_waiting_on.is_empty());
requests_waiting_on.remove_all_matching([](GC::Ref<IDBRequestObserver> const& pending_request) {
if (pending_request->request()->processed()) {
pending_request->unobserve();
return true;
}
return false;
});
if (requests_waiting_on.is_empty()) {
queue_a_database_task(after_all.as_nonnull());
}
}));
requests_waiting_on.append(request_observer);
}
}