| 
									
										
										
										
											2024-05-19 17:58:06 +12:00
										 |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * Copyright (c) 2024, Shannon Booth <shannon@serenityos.org> | 
					
						
							| 
									
										
										
										
											2024-11-04 18:19:19 +01:00
										 |  |  |  |  * Copyright (c) 2024, stelar7 <dudedbz@gmail.com> | 
					
						
							| 
									
										
										
										
											2024-05-19 17:58:06 +12:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <LibWeb/Bindings/IDBFactoryPrototype.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/Bindings/Intrinsics.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-04 18:19:19 +01:00
										 |  |  |  | #include <LibWeb/DOM/Event.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/HTML/EventNames.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-04 19:10:07 +01:00
										 |  |  |  | #include <LibWeb/IndexedDB/IDBDatabase.h>
 | 
					
						
							| 
									
										
										
										
											2024-05-19 17:58:06 +12:00
										 |  |  |  | #include <LibWeb/IndexedDB/IDBFactory.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-04 19:10:07 +01:00
										 |  |  |  | #include <LibWeb/IndexedDB/Internal/Algorithms.h>
 | 
					
						
							| 
									
										
										
										
											2024-11-04 18:19:19 +01:00
										 |  |  |  | #include <LibWeb/Platform/EventLoopPlugin.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/StorageAPI/StorageKey.h>
 | 
					
						
							| 
									
										
										
										
											2024-05-19 17:58:06 +12:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | namespace Web::IndexedDB { | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |  | GC_DEFINE_ALLOCATOR(IDBFactory); | 
					
						
							| 
									
										
										
										
											2024-05-19 17:58:06 +12:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | IDBFactory::IDBFactory(JS::Realm& realm) | 
					
						
							|  |  |  |  |     : Bindings::PlatformObject(realm) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | IDBFactory::~IDBFactory() = default; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | void IDBFactory::initialize(JS::Realm& realm) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     Base::initialize(realm); | 
					
						
							|  |  |  |  |     WEB_SET_PROTOTYPE_FOR_INTERFACE(IDBFactory); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-04 18:19:19 +01:00
										 |  |  |  | // https://w3c.github.io/IndexedDB/#dom-idbfactory-open
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |  | WebIDL::ExceptionOr<GC::Ref<IDBOpenDBRequest>> IDBFactory::open(String const& name, Optional<u64> version) | 
					
						
							| 
									
										
										
										
											2024-11-04 18:19:19 +01:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |     auto& realm = this->realm(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 1. If version is 0 (zero), throw a TypeError.
 | 
					
						
							|  |  |  |  |     if (version.has_value() && version.value() == 0) | 
					
						
							|  |  |  |  |         return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "The version provided must not be 0"_string }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 2. Let environment be this's relevant settings object.
 | 
					
						
							|  |  |  |  |     auto& environment = HTML::relevant_settings_object(*this); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 3. Let storageKey be the result of running obtain a storage key given environment.
 | 
					
						
							|  |  |  |  |     //    If failure is returned, then throw a "SecurityError" DOMException and abort these steps.
 | 
					
						
							|  |  |  |  |     auto storage_key = StorageAPI::obtain_a_storage_key(environment); | 
					
						
							|  |  |  |  |     if (!storage_key.has_value()) | 
					
						
							|  |  |  |  |         return WebIDL::SecurityError::create(realm, "Failed to obtain a storage key"_string); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 4. Let request be a new open request.
 | 
					
						
							|  |  |  |  |     auto request = IDBOpenDBRequest::create(realm); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 5. Run these steps in parallel:
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |  |     Platform::EventLoopPlugin::the().deferred_invoke(GC::create_function(realm.heap(), [&realm, storage_key, name, version, request] { | 
					
						
							| 
									
										
										
										
											2024-11-04 18:19:19 +01:00
										 |  |  |  |         HTML::TemporaryExecutionContext context(realm, HTML::TemporaryExecutionContext::CallbacksEnabled::Yes); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-04 19:10:07 +01:00
										 |  |  |  |         // 1. Let result be the result of opening a database connection, with storageKey, name, version if given and undefined otherwise, and request.
 | 
					
						
							|  |  |  |  |         auto result = open_a_database_connection(realm, storage_key.value(), name, version, request); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         // 2. Queue a task to run these steps:
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |  |         HTML::queue_a_task(HTML::Task::Source::DatabaseAccess, nullptr, nullptr, GC::create_function(realm.heap(), [&realm, &request, result = move(result)]() mutable { | 
					
						
							| 
									
										
										
										
											2024-11-04 19:10:07 +01:00
										 |  |  |  |             // 1. If result is an error, then:
 | 
					
						
							|  |  |  |  |             if (result.is_error()) { | 
					
						
							|  |  |  |  |                 // 1. Set request’s result to undefined.
 | 
					
						
							|  |  |  |  |                 request->set_result(JS::js_undefined()); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // 2. Set request’s error to result.
 | 
					
						
							| 
									
										
										
										
											2024-11-15 04:01:23 +13:00
										 |  |  |  |                 request->set_error(result.exception().get<GC::Ref<WebIDL::DOMException>>()); | 
					
						
							| 
									
										
										
										
											2024-11-04 19:10:07 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // 3. Set request’s done flag to true.
 | 
					
						
							|  |  |  |  |                 request->set_done(true); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // 4. Fire an event named error at request with its bubbles and cancelable attributes initialized to true.
 | 
					
						
							|  |  |  |  |                 request->dispatch_event(DOM::Event::create(realm, HTML::EventNames::error)); | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 // 1. Set request’s result to result.
 | 
					
						
							|  |  |  |  |                 request->set_result(result.release_value()); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // 2. Set request’s done flag to true.
 | 
					
						
							|  |  |  |  |                 request->set_done(true); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 // 3. Fire an event named success at request.
 | 
					
						
							|  |  |  |  |                 request->dispatch_event(DOM::Event::create(realm, HTML::EventNames::success)); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         })); | 
					
						
							| 
									
										
										
										
											2024-11-04 18:19:19 +01:00
										 |  |  |  |     })); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // 6. Return a new IDBOpenDBRequest object for request.
 | 
					
						
							|  |  |  |  |     return request; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 17:58:06 +12:00
										 |  |  |  | } |