blob: e5dc1aea79cc2932cacfb65d1804dfec8fb290e9 [file] [log] [blame]
/*
* Copyright (C) 2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WorkerFileSystemStorageConnection.h"
#include "FileSystemHandleCloseScope.h"
#include "FileSystemSyncAccessHandle.h"
#include "WorkerGlobalScope.h"
#include "WorkerLoaderProxy.h"
#include "WorkerThread.h"
#include <wtf/Scope.h>
namespace WebCore {
Ref<WorkerFileSystemStorageConnection> WorkerFileSystemStorageConnection::create(WorkerGlobalScope& scope, Ref<FileSystemStorageConnection>&& mainThreadConnection)
{
return adoptRef(*new WorkerFileSystemStorageConnection(scope, WTFMove(mainThreadConnection)));
}
WorkerFileSystemStorageConnection::WorkerFileSystemStorageConnection(WorkerGlobalScope& scope, Ref<FileSystemStorageConnection>&& connection)
: m_scope(scope)
, m_mainThreadConnection(WTFMove(connection))
{
}
WorkerFileSystemStorageConnection::~WorkerFileSystemStorageConnection()
{
if (m_mainThreadConnection)
callOnMainThread([mainThreadConenction = WTFMove(m_mainThreadConnection)]() { });
}
void WorkerFileSystemStorageConnection::connectionClosed()
{
for (auto handle : m_syncAccessHandles.values())
handle->invalidate();
scopeClosed();
}
void WorkerFileSystemStorageConnection::scopeClosed()
{
auto sameEntryCallbacks = std::exchange(m_sameEntryCallbacks, { });
for (auto& callback : sameEntryCallbacks.values())
callback(Exception { InvalidStateError });
auto getHandleCallbacks = std::exchange(m_getHandleCallbacks, { });
for (auto& callback : getHandleCallbacks.values())
callback(Exception { InvalidStateError });
auto removeEntryCallbacks = std::exchange(m_voidCallbacks, { });
for (auto& callback : removeEntryCallbacks.values())
callback(Exception { InvalidStateError });
auto resolveCallbacks = std::exchange(m_resolveCallbacks, { });
for (auto& callback : resolveCallbacks.values())
callback(Exception { InvalidStateError });
auto stringCallbacks = std::exchange(m_stringCallbacks, { });
for (auto& callback : stringCallbacks.values())
callback(Exception { InvalidStateError });
m_scope = nullptr;
}
void WorkerFileSystemStorageConnection::closeHandle(FileSystemHandleIdentifier identifier)
{
callOnMainThread([mainThreadConnection = m_mainThreadConnection, identifier]() mutable {
if (mainThreadConnection)
mainThreadConnection->closeHandle(identifier);
});
}
void WorkerFileSystemStorageConnection::isSameEntry(FileSystemHandleIdentifier identifier, FileSystemHandleIdentifier otherIdentifier, FileSystemStorageConnection::SameEntryCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_sameEntryCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, otherIdentifier]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->didIsSameEntry(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->isSameEntry(identifier, otherIdentifier, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::didIsSameEntry(CallbackIdentifier callbackIdentifier, ExceptionOr<bool>&& result)
{
if (auto callback = m_sameEntryCallbacks.take(callbackIdentifier))
callback(WTFMove(result));
}
void WorkerFileSystemStorageConnection::getFileHandle(FileSystemHandleIdentifier identifier, const String& name, bool createIfNecessary, FileSystemStorageConnection::GetHandleCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_getHandleCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, name = name.isolatedCopy(), createIfNecessary]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->didGetHandle(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->getFileHandle(identifier, name, createIfNecessary, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::getDirectoryHandle(FileSystemHandleIdentifier identifier, const String& name, bool createIfNecessary, FileSystemStorageConnection::GetHandleCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_getHandleCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, name = name.isolatedCopy(), createIfNecessary]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->didGetHandle(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->getDirectoryHandle(identifier, name, createIfNecessary, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::didGetHandle(CallbackIdentifier callbackIdentifier, ExceptionOr<Ref<FileSystemHandleCloseScope>>&& result)
{
if (auto callback = m_getHandleCallbacks.take(callbackIdentifier))
callback(WTFMove(result));
}
void WorkerFileSystemStorageConnection::removeEntry(FileSystemHandleIdentifier identifier, const String& name, bool deleteRecursively, FileSystemStorageConnection::VoidCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_voidCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, name = name.isolatedCopy(), deleteRecursively]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->completeVoidCallback(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->removeEntry(identifier, name, deleteRecursively, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::resolve(FileSystemHandleIdentifier identifier, FileSystemHandleIdentifier otherIdentifier, FileSystemStorageConnection::ResolveCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_resolveCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, otherIdentifier]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->didResolve(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->resolve(identifier, otherIdentifier, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::didResolve(CallbackIdentifier callbackIdentifier, ExceptionOr<Vector<String>>&& result)
{
if (auto callback = m_resolveCallbacks.take(callbackIdentifier))
callback(WTFMove(result));
}
void WorkerFileSystemStorageConnection::getFile(FileSystemHandleIdentifier identifier, StringCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_stringCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->completeStringCallback(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->getFile(identifier, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::completeStringCallback(CallbackIdentifier callbackIdentifier, ExceptionOr<String>&& result)
{
if (auto callback = m_stringCallbacks.take(callbackIdentifier))
callback(WTFMove(result));
}
void WorkerFileSystemStorageConnection::didCreateSyncAccessHandle(CallbackIdentifier callbackIdentifier, ExceptionOr<std::pair<FileSystemSyncAccessHandleIdentifier, FileHandle>>&& result)
{
if (auto callback = m_getAccessHandlCallbacks.take(callbackIdentifier))
callback(WTFMove(result));
}
void WorkerFileSystemStorageConnection::completeVoidCallback(CallbackIdentifier callbackIdentifier, ExceptionOr<void>&& result)
{
if (auto callback = m_voidCallbacks.take(callbackIdentifier))
callback(WTFMove(result));
}
void WorkerFileSystemStorageConnection::createSyncAccessHandle(FileSystemHandleIdentifier identifier, FileSystemStorageConnection::GetAccessHandleCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_getAccessHandlCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->didCreateSyncAccessHandle(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->createSyncAccessHandle(identifier, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::closeSyncAccessHandle(FileSystemHandleIdentifier identifier, FileSystemSyncAccessHandleIdentifier accessHandleIdentifier, FileSystemStorageConnection::VoidCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_voidCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, accessHandleIdentifier]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->completeVoidCallback(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->closeSyncAccessHandle(identifier, accessHandleIdentifier, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::registerSyncAccessHandle(FileSystemSyncAccessHandleIdentifier identifier, FileSystemSyncAccessHandle& handle)
{
if (!m_scope)
return;
m_syncAccessHandles.add(identifier, WeakPtr { handle });
callOnMainThread([identifier, contextIdentifier = m_scope->identifier(), mainThreadConnection = m_mainThreadConnection]() mutable {
mainThreadConnection->registerSyncAccessHandle(identifier, contextIdentifier);
});
}
void WorkerFileSystemStorageConnection::unregisterSyncAccessHandle(FileSystemSyncAccessHandleIdentifier identifier)
{
m_syncAccessHandles.remove(identifier);
callOnMainThread([identifier, mainThreadConnection = m_mainThreadConnection]() mutable {
mainThreadConnection->unregisterSyncAccessHandle(identifier);
});
}
void WorkerFileSystemStorageConnection::invalidateAccessHandle(WebCore::FileSystemSyncAccessHandleIdentifier identifier)
{
if (auto handle = m_syncAccessHandles.get(identifier))
handle->invalidate();
}
void WorkerFileSystemStorageConnection::getHandleNames(FileSystemHandleIdentifier identifier, GetHandleNamesCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_getHandleNamesCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->didGetHandleNames(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->getHandleNames(identifier, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::didGetHandleNames(CallbackIdentifier callbackIdentifier, ExceptionOr<Vector<String>>&& result)
{
if (auto callback = m_getHandleNamesCallbacks.take(callbackIdentifier))
callback(WTFMove(result));
}
void WorkerFileSystemStorageConnection::getHandle(FileSystemHandleIdentifier identifier, const String& name, GetHandleCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_getHandleCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, name = name.isolatedCopy()]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->didGetHandle(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->getHandle(identifier, name, WTFMove(mainThreadCallback));
});
}
void WorkerFileSystemStorageConnection::move(FileSystemHandleIdentifier identifier, FileSystemHandleIdentifier destinationIdentifier, const String& newName, VoidCallback&& callback)
{
if (!m_scope)
return callback(Exception { InvalidStateError });
auto callbackIdentifier = CallbackIdentifier::generateThreadSafe();
m_voidCallbacks.add(callbackIdentifier, WTFMove(callback));
callOnMainThread([callbackIdentifier, workerThread = Ref { m_scope->thread() }, mainThreadConnection = m_mainThreadConnection, identifier, destinationIdentifier, name = crossThreadCopy(newName)]() mutable {
auto mainThreadCallback = [callbackIdentifier, workerThread = WTFMove(workerThread)](auto&& result) mutable {
workerThread->runLoop().postTaskForMode([callbackIdentifier, result = crossThreadCopy(WTFMove(result))] (auto& scope) mutable {
if (auto connection = downcast<WorkerGlobalScope>(scope).fileSystemStorageConnection())
connection->completeVoidCallback(callbackIdentifier, WTFMove(result));
}, WorkerRunLoop::defaultMode());
};
mainThreadConnection->move(identifier, destinationIdentifier, name, WTFMove(mainThreadCallback));
});
}
} // namespace WebCore