Fix service concurrency isolation warnings
This commit is contained in:
parent
2df126ebe2
commit
64f75e73df
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum MinecraftContentType: String, CaseIterable, Hashable, Sendable, Codable {
|
nonisolated enum MinecraftContentType: String, CaseIterable, Hashable, Sendable, Codable {
|
||||||
case world = "World"
|
case world = "World"
|
||||||
case behaviorPack = "Behavior Pack"
|
case behaviorPack = "Behavior Pack"
|
||||||
case resourcePack = "Resource Pack"
|
case resourcePack = "Resource Pack"
|
||||||
@ -56,13 +56,13 @@ enum MinecraftContentType: String, CaseIterable, Hashable, Sendable, Codable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PackSource: String, Hashable, Sendable, Codable {
|
nonisolated enum PackSource: String, Hashable, Sendable, Codable {
|
||||||
case referencedByWorld
|
case referencedByWorld
|
||||||
case embeddedInWorld
|
case embeddedInWorld
|
||||||
case foundInCollection
|
case foundInCollection
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContentPackReference: Identifiable, Hashable, Sendable, Codable {
|
nonisolated struct ContentPackReference: Identifiable, Hashable, Sendable, Codable {
|
||||||
let id: String
|
let id: String
|
||||||
let name: String
|
let name: String
|
||||||
let type: MinecraftContentType
|
let type: MinecraftContentType
|
||||||
@ -93,7 +93,7 @@ struct ContentPackReference: Identifiable, Hashable, Sendable, Codable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WorldMetadata: Hashable, Sendable, Codable {
|
nonisolated struct WorldMetadata: Hashable, Sendable, Codable {
|
||||||
var gameMode: String?
|
var gameMode: String?
|
||||||
var difficulty: String?
|
var difficulty: String?
|
||||||
var seed: String?
|
var seed: String?
|
||||||
@ -113,11 +113,11 @@ struct WorldMetadata: Hashable, Sendable, Codable {
|
|||||||
var networkVersion: String?
|
var networkVersion: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PackMetadataDetails: Hashable, Sendable, Codable {
|
nonisolated struct PackMetadataDetails: Hashable, Sendable, Codable {
|
||||||
var minimumEngineVersion: String?
|
var minimumEngineVersion: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MinecraftContentItem: Identifiable, Hashable, Sendable, Codable {
|
nonisolated struct MinecraftContentItem: Identifiable, Hashable, Sendable, Codable {
|
||||||
let id: URL
|
let id: URL
|
||||||
let folderURL: URL
|
let folderURL: URL
|
||||||
let folderName: String
|
let folderName: String
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct ConnectedDevice: Identifiable, Hashable, Sendable, Codable {
|
nonisolated struct ConnectedDevice: Identifiable, Hashable, Sendable, Codable {
|
||||||
let udid: String
|
let udid: String
|
||||||
var name: String
|
var name: String
|
||||||
var productType: String?
|
var productType: String?
|
||||||
@ -18,19 +18,19 @@ struct ConnectedDevice: Identifiable, Hashable, Sendable, Codable {
|
|||||||
var id: String { udid }
|
var id: String { udid }
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DeviceConnection: String, Hashable, Sendable, Codable {
|
nonisolated enum DeviceConnection: String, Hashable, Sendable, Codable {
|
||||||
case usb
|
case usb
|
||||||
case network
|
case network
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DeviceTrustState: String, Hashable, Sendable, Codable {
|
nonisolated enum DeviceTrustState: String, Hashable, Sendable, Codable {
|
||||||
case unavailable
|
case unavailable
|
||||||
case locked
|
case locked
|
||||||
case untrusted
|
case untrusted
|
||||||
case trusted
|
case trusted
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeviceAppContainer: Identifiable, Hashable, Sendable, Codable {
|
nonisolated struct DeviceAppContainer: Identifiable, Hashable, Sendable, Codable {
|
||||||
let deviceUDID: String
|
let deviceUDID: String
|
||||||
let appID: String
|
let appID: String
|
||||||
var appName: String
|
var appName: String
|
||||||
@ -42,12 +42,12 @@ struct DeviceAppContainer: Identifiable, Hashable, Sendable, Codable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DeviceContainerAccessMode: String, Hashable, Sendable, Codable {
|
nonisolated enum DeviceContainerAccessMode: String, Hashable, Sendable, Codable {
|
||||||
case documents
|
case documents
|
||||||
case container
|
case container
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MinecraftSourceOrigin: Hashable, Sendable, Codable {
|
nonisolated enum MinecraftSourceOrigin: Hashable, Sendable, Codable {
|
||||||
case localFolder(bookmarkData: Data?)
|
case localFolder(bookmarkData: Data?)
|
||||||
case connectedDevice(device: ConnectedDevice, container: DeviceAppContainer)
|
case connectedDevice(device: ConnectedDevice, container: DeviceAppContainer)
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ enum MinecraftSourceOrigin: Hashable, Sendable, Codable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MinecraftSourceKind: String, Hashable, Sendable, Codable {
|
nonisolated enum MinecraftSourceKind: String, Hashable, Sendable, Codable {
|
||||||
case localFolder
|
case localFolder
|
||||||
case connectedDevice
|
case connectedDevice
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import Foundation
|
|||||||
|
|
||||||
typealias SourceAccessorIdentifier = String
|
typealias SourceAccessorIdentifier = String
|
||||||
|
|
||||||
enum SourceAvailability: String, Hashable, Sendable, Codable {
|
nonisolated enum SourceAvailability: String, Hashable, Sendable, Codable {
|
||||||
case unknown
|
case unknown
|
||||||
case available
|
case available
|
||||||
case disconnected
|
case disconnected
|
||||||
@ -17,18 +17,18 @@ enum SourceAvailability: String, Hashable, Sendable, Codable {
|
|||||||
case unavailable
|
case unavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SourceRefreshStrategy: String, Hashable, Sendable, Codable {
|
nonisolated enum SourceRefreshStrategy: String, Hashable, Sendable, Codable {
|
||||||
case eagerFullScan
|
case eagerFullScan
|
||||||
case staged
|
case staged
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SourceAccessDescriptor: Hashable, Sendable, Codable {
|
nonisolated struct SourceAccessDescriptor: Hashable, Sendable, Codable {
|
||||||
var accessorIdentifier: SourceAccessorIdentifier
|
var accessorIdentifier: SourceAccessorIdentifier
|
||||||
var kind: MinecraftSourceKind
|
var kind: MinecraftSourceKind
|
||||||
var refreshStrategy: SourceRefreshStrategy
|
var refreshStrategy: SourceRefreshStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SourceRecord: Identifiable, Hashable, Sendable, Codable {
|
nonisolated struct SourceRecord: Identifiable, Hashable, Sendable, Codable {
|
||||||
let id: URL
|
let id: URL
|
||||||
var displayName: String
|
var displayName: String
|
||||||
var rootURL: URL
|
var rootURL: URL
|
||||||
|
|||||||
@ -39,7 +39,7 @@ enum SourceScanExecutor {
|
|||||||
let previousSource = source
|
let previousSource = source
|
||||||
let performanceContext = SourceScanPolicy.performanceContext(for: source)
|
let performanceContext = SourceScanPolicy.performanceContext(for: source)
|
||||||
|
|
||||||
await host.updateSource(sourceID) { source in
|
host.updateSource(sourceID) { source in
|
||||||
source.isScanning = true
|
source.isScanning = true
|
||||||
source.scanError = nil
|
source.scanError = nil
|
||||||
source.scanDiagnostic = nil
|
source.scanDiagnostic = nil
|
||||||
@ -51,11 +51,11 @@ enum SourceScanExecutor {
|
|||||||
source.sizeLoadedCount = 0
|
source.sizeLoadedCount = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
await host.updateSource(sourceID) { source in
|
host.updateSource(sourceID) { source in
|
||||||
source.accessDescriptor = sourceAccessMethod.accessDescriptor(for: source)
|
source.accessDescriptor = sourceAccessMethod.accessDescriptor(for: source)
|
||||||
}
|
}
|
||||||
let currentAvailability = await sourceAccessMethod.availability(for: source)
|
let currentAvailability = await sourceAccessMethod.availability(for: source)
|
||||||
await host.updateSource(sourceID) { source in
|
host.updateSource(sourceID) { source in
|
||||||
source.availability = currentAvailability
|
source.availability = currentAvailability
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ enum SourceScanExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await host.updateSource(sourceID) { source in
|
host.updateSource(sourceID) { source in
|
||||||
source.availability = .available
|
source.availability = .available
|
||||||
source.scanStatus = SourceScanPolicy.scanningLibraryStatus(for: source, mode: mode)
|
source.scanStatus = SourceScanPolicy.scanningLibraryStatus(for: source, mode: mode)
|
||||||
}
|
}
|
||||||
@ -86,7 +86,9 @@ enum SourceScanExecutor {
|
|||||||
|
|
||||||
let enrichedItem = await sourceAccessMethod.enrich(item, for: source)
|
let enrichedItem = await sourceAccessMethod.enrich(item, for: source)
|
||||||
if let snapshot = await index.applyEnrichedItem(enrichedItem) {
|
if let snapshot = await index.applyEnrichedItem(enrichedItem) {
|
||||||
await host.applySnapshot(snapshot, to: sourceID)
|
await MainActor.run {
|
||||||
|
host.applySnapshot(snapshot, to: sourceID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,7 +145,7 @@ enum SourceScanExecutor {
|
|||||||
itemForIndex,
|
itemForIndex,
|
||||||
discoveredCount: discoveredCount
|
discoveredCount: discoveredCount
|
||||||
) {
|
) {
|
||||||
await host.applySnapshot(snapshot, to: sourceID)
|
host.applySnapshot(snapshot, to: sourceID)
|
||||||
}
|
}
|
||||||
if itemForIndex.id == item.id, itemForIndex.metadataLoaded == false {
|
if itemForIndex.id == item.id, itemForIndex.metadataLoaded == false {
|
||||||
await enrichmentQueue.enqueue(item)
|
await enrichmentQueue.enqueue(item)
|
||||||
@ -170,13 +172,13 @@ enum SourceScanExecutor {
|
|||||||
cachedItem,
|
cachedItem,
|
||||||
discoveredCount: discoveredCount
|
discoveredCount: discoveredCount
|
||||||
) {
|
) {
|
||||||
await host.applySnapshot(snapshot, to: sourceID)
|
host.applySnapshot(snapshot, to: sourceID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await host.logScanStage(
|
host.logScanStage(
|
||||||
"Discovery",
|
"Discovery",
|
||||||
elapsed: Date().timeIntervalSince(discoveryStartTime),
|
elapsed: Date().timeIntervalSince(discoveryStartTime),
|
||||||
context: performanceContext,
|
context: performanceContext,
|
||||||
@ -184,7 +186,7 @@ enum SourceScanExecutor {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if let snapshot = await index.markDiscoveryFinished() {
|
if let snapshot = await index.markDiscoveryFinished() {
|
||||||
await host.applySnapshot(snapshot, to: sourceID)
|
host.applySnapshot(snapshot, to: sourceID)
|
||||||
}
|
}
|
||||||
await enrichmentQueue.finish()
|
await enrichmentQueue.finish()
|
||||||
let enrichmentStartTime = Date()
|
let enrichmentStartTime = Date()
|
||||||
@ -193,7 +195,7 @@ enum SourceScanExecutor {
|
|||||||
await workerTask.value
|
await workerTask.value
|
||||||
}
|
}
|
||||||
|
|
||||||
await host.logScanStage(
|
host.logScanStage(
|
||||||
"Enrichment",
|
"Enrichment",
|
||||||
elapsed: Date().timeIntervalSince(enrichmentStartTime),
|
elapsed: Date().timeIntervalSince(enrichmentStartTime),
|
||||||
context: performanceContext,
|
context: performanceContext,
|
||||||
@ -201,9 +203,9 @@ enum SourceScanExecutor {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if let snapshot = await index.markMetadataFinished() {
|
if let snapshot = await index.markMetadataFinished() {
|
||||||
await host.applySnapshot(snapshot, to: sourceID)
|
host.applySnapshot(snapshot, to: sourceID)
|
||||||
}
|
}
|
||||||
await host.persistSourceIfAvailable(withID: sourceID)
|
host.persistSourceIfAvailable(withID: sourceID)
|
||||||
|
|
||||||
let previewStageStartTime = Date()
|
let previewStageStartTime = Date()
|
||||||
let previewSeedItems = await index.currentItems()
|
let previewSeedItems = await index.currentItems()
|
||||||
@ -213,11 +215,11 @@ enum SourceScanExecutor {
|
|||||||
)
|
)
|
||||||
for previewItem in previewItems {
|
for previewItem in previewItems {
|
||||||
if let snapshot = await index.applyPreviewItem(previewItem) {
|
if let snapshot = await index.applyPreviewItem(previewItem) {
|
||||||
await host.applySnapshot(snapshot, to: sourceID)
|
host.applySnapshot(snapshot, to: sourceID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await host.logScanStage(
|
host.logScanStage(
|
||||||
"Previews",
|
"Previews",
|
||||||
elapsed: Date().timeIntervalSince(previewStageStartTime),
|
elapsed: Date().timeIntervalSince(previewStageStartTime),
|
||||||
context: performanceContext,
|
context: performanceContext,
|
||||||
@ -225,9 +227,9 @@ enum SourceScanExecutor {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if let snapshot = await index.markPreviewsFinished() {
|
if let snapshot = await index.markPreviewsFinished() {
|
||||||
await host.applySnapshot(snapshot, to: sourceID)
|
host.applySnapshot(snapshot, to: sourceID)
|
||||||
}
|
}
|
||||||
await host.persistSourceIfAvailable(withID: sourceID)
|
host.persistSourceIfAvailable(withID: sourceID)
|
||||||
|
|
||||||
if source.origin.kind == .connectedDevice {
|
if source.origin.kind == .connectedDevice {
|
||||||
try await finishConnectedDeviceScan(
|
try await finishConnectedDeviceScan(
|
||||||
@ -271,7 +273,7 @@ enum SourceScanExecutor {
|
|||||||
await sizeWorkerTask.value
|
await sizeWorkerTask.value
|
||||||
}
|
}
|
||||||
|
|
||||||
await host.logScanStage(
|
host.logScanStage(
|
||||||
"Size",
|
"Size",
|
||||||
elapsed: Date().timeIntervalSince(sizeStageStartTime),
|
elapsed: Date().timeIntervalSince(sizeStageStartTime),
|
||||||
context: performanceContext,
|
context: performanceContext,
|
||||||
@ -291,7 +293,7 @@ enum SourceScanExecutor {
|
|||||||
minimumVisibleScanDuration: minimumVisibleScanDuration
|
minimumVisibleScanDuration: minimumVisibleScanDuration
|
||||||
)
|
)
|
||||||
} catch {
|
} catch {
|
||||||
await host.updateSource(sourceID) { source in
|
host.updateSource(sourceID) { source in
|
||||||
if SourceScanRecovery.shouldPreservePartialResults(currentSource: source, previousSource: previousSource) {
|
if SourceScanRecovery.shouldPreservePartialResults(currentSource: source, previousSource: previousSource) {
|
||||||
source.scanStatus = source.indexedItemCount == 0
|
source.scanStatus = source.indexedItemCount == 0
|
||||||
? previousSource.scanStatus
|
? previousSource.scanStatus
|
||||||
@ -320,7 +322,7 @@ enum SourceScanExecutor {
|
|||||||
source.scanProgress = nil
|
source.scanProgress = nil
|
||||||
source.isScanning = false
|
source.isScanning = false
|
||||||
}
|
}
|
||||||
await host.persistSourceIfAvailable(withID: sourceID)
|
host.persistSourceIfAvailable(withID: sourceID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,11 +347,11 @@ enum SourceScanExecutor {
|
|||||||
)
|
)
|
||||||
for sizedItem in sizedItems {
|
for sizedItem in sizedItems {
|
||||||
if let snapshot = await index.applySizedItem(sizedItem) {
|
if let snapshot = await index.applySizedItem(sizedItem) {
|
||||||
await host.applySnapshot(snapshot, to: sourceID)
|
host.applySnapshot(snapshot, to: sourceID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await host.logScanStage(
|
host.logScanStage(
|
||||||
"Size",
|
"Size",
|
||||||
elapsed: Date().timeIntervalSince(sizeStageStartTime),
|
elapsed: Date().timeIntervalSince(sizeStageStartTime),
|
||||||
context: performanceContext,
|
context: performanceContext,
|
||||||
@ -390,24 +392,24 @@ enum SourceScanExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let snapshot = await index.finishScan() {
|
if let snapshot = await index.finishScan() {
|
||||||
await host.applySnapshot(snapshot, to: sourceID)
|
host.applySnapshot(snapshot, to: sourceID)
|
||||||
}
|
}
|
||||||
await host.updateSource(sourceID) { source in
|
host.updateSource(sourceID) { source in
|
||||||
if source.origin.kind == .localFolder {
|
if source.origin.kind == .localFolder {
|
||||||
source.snapshot = SourceScanPolicy.buildSnapshot(for: source, scanRootURL: scanContextURL)
|
source.snapshot = SourceScanPolicy.buildSnapshot(for: source, scanRootURL: scanContextURL)
|
||||||
} else {
|
} else {
|
||||||
source.snapshot = nil
|
source.snapshot = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await host.persistSourceIfAvailable(withID: sourceID)
|
host.persistSourceIfAvailable(withID: sourceID)
|
||||||
await host.logScanStage(
|
host.logScanStage(
|
||||||
"Total",
|
"Total",
|
||||||
elapsed: Date().timeIntervalSince(scanStartTime),
|
elapsed: Date().timeIntervalSince(scanStartTime),
|
||||||
context: performanceContext,
|
context: performanceContext,
|
||||||
itemCount: discoveredCount
|
itemCount: discoveredCount
|
||||||
)
|
)
|
||||||
|
|
||||||
if let completedSource = await host.source(withID: sourceID) {
|
if let completedSource = host.source(withID: sourceID) {
|
||||||
await notificationService.notifyScanCompleted(
|
await notificationService.notifyScanCompleted(
|
||||||
for: completedSource,
|
for: completedSource,
|
||||||
duration: Date().timeIntervalSince(scanStartTime)
|
duration: Date().timeIntervalSince(scanStartTime)
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
struct ZipArchiveEntry: Sendable, Hashable {
|
nonisolated struct ZipArchiveEntry: Sendable, Hashable {
|
||||||
let path: String
|
let path: String
|
||||||
let compressionMethod: UInt16
|
let compressionMethod: UInt16
|
||||||
let compressedSize: UInt32
|
let compressedSize: UInt32
|
||||||
@ -17,7 +17,7 @@ struct ZipArchiveEntry: Sendable, Hashable {
|
|||||||
let isDirectory: Bool
|
let isDirectory: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ZipArchiveReaderError: LocalizedError {
|
nonisolated enum ZipArchiveReaderError: LocalizedError {
|
||||||
case invalidArchive
|
case invalidArchive
|
||||||
case unsupportedCompressionMethod(UInt16)
|
case unsupportedCompressionMethod(UInt16)
|
||||||
case unsupportedFeatures(String)
|
case unsupportedFeatures(String)
|
||||||
@ -40,7 +40,7 @@ enum ZipArchiveReaderError: LocalizedError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ZipArchiveReader {
|
nonisolated struct ZipArchiveReader {
|
||||||
private let data: Data
|
private let data: Data
|
||||||
let entries: [ZipArchiveEntry]
|
let entries: [ZipArchiveEntry]
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ struct ZipArchiveReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension Data {
|
private nonisolated extension Data {
|
||||||
func readUInt16LE(at offset: Int) -> UInt16 {
|
func readUInt16LE(at offset: Int) -> UInt16 {
|
||||||
return self.withUnsafeBytes { bytes in
|
return self.withUnsafeBytes { bytes in
|
||||||
let base = bytes.baseAddress!.advanced(by: offset)
|
let base = bytes.baseAddress!.advanced(by: offset)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user