Skip to content

Commit 0b9616f

Browse files
committed
Cleanup
1 parent ad776c6 commit 0b9616f

File tree

1 file changed

+63
-68
lines changed

1 file changed

+63
-68
lines changed

ios/Sources/GutenbergKit/Sources/Service/EditorService.swift

Lines changed: 63 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,14 @@ actor EditorService {
4242
self.siteURL = siteURL
4343
self.urlSession = urlSession
4444

45-
self.storeURL = URL.applicationDirectory
46-
.appendingPathComponent("GutenbergKit", isDirectory: true)
45+
self.storeURL = EditorService.rootURL
4746
.appendingPathComponent(siteURL.sha1, isDirectory: true)
4847
}
4948

49+
private static var rootURL: URL {
50+
URL.applicationDirectory.appendingPathComponent("GutenbergKit", isDirectory: true)
51+
}
52+
5053
/// Set up the editor for the given site.
5154
///
5255
/// - warning: The request make take a significant amount of time the first
@@ -194,43 +197,13 @@ actor EditorService {
194197
/// Returns the editor assets manifest as a JSON string, with JavaScript and stylesheet links
195198
/// modified so that their content can be cached and reused by the editor.
196199
///
197-
/// Verifies that all required assets are cached before returning the manifest.
198-
///
199200
/// - Parameter siteURL: The site URL to extract the scheme for scheme-less links
200201
/// - Returns: JSON string of the processed manifest
201-
/// - Throws: `EditorServiceError` if assets are missing or manifest processing fails
202202
private func getManifestForEditor(siteURL: String) throws -> String {
203203
// For scheme-less links (i.e. '//stats.wp.com/w.js'), use the scheme in `siteURL`.
204204
let siteURLScheme = URL(string: siteURL)?.scheme
205205
let data = try Data(contentsOf: manifestFileURL)
206206
let manifest = try JSONDecoder().decode(EditorAssetsManifest.self, from: data)
207-
let assetLinks = try manifest.parseAssetLinks()
208-
209-
// Verify all assets are cached
210-
let fileManager = FileManager.default
211-
var missingAssets: [String] = []
212-
213-
for urlString in assetLinks {
214-
let filename = cachedFilename(for: urlString)
215-
let localURL = assetsDirectoryURL.appendingPathComponent(filename)
216-
217-
if !fileManager.fileExists(atPath: localURL.path) {
218-
missingAssets.append(urlString)
219-
}
220-
}
221-
222-
if !missingAssets.isEmpty {
223-
log(.error, "Missing \(missingAssets.count) asset(s) from cache")
224-
for (index, asset) in missingAssets.prefix(5).enumerated() {
225-
log(.error, " [\(index + 1)] \(asset)")
226-
}
227-
if missingAssets.count > 5 {
228-
log(.error, " ... and \(missingAssets.count - 5) more")
229-
}
230-
throw URLError(.resourceUnavailable)
231-
}
232-
233-
log(.info, "All \(assetLinks.count) manifest assets verified in cache")
234207

235208
// Process manifest for editor
236209
let processedData = try manifest.renderForEditor(defaultScheme: siteURLScheme)
@@ -244,8 +217,10 @@ actor EditorService {
244217

245218
/// Fetches all assets from the manifest and stores them on the device
246219
private func fetchAssets(manifestData: Data) async throws {
220+
let startTime = CFAbsoluteTimeGetCurrent()
247221
let manifest = try JSONDecoder().decode(EditorAssetsManifest.self, from: manifestData)
248222
let assetLinks = try manifest.parseAssetLinks()
223+
.filter { isSupportedAsset($0) }
249224

250225
log(.info, "Found \(assetLinks.count) assets to fetch")
251226

@@ -258,71 +233,81 @@ actor EditorService {
258233
// Track statistics
259234
var fetchedCount = 0
260235
var cachedCount = 0
261-
var totalSize: Int64 = 0
236+
var assetURLs: [URL] = []
262237

263238
// Fetch all assets in parallel
264-
try await withThrowingTaskGroup(of: (Bool, Int64).self) { group in
239+
await withTaskGroup(of: Result<(Bool, URL), Error>.self) { group in
265240
for link in assetLinks {
266241
group.addTask {
267-
try await self.fetchAsset(from: link)
242+
await Result { try await self.fetchAsset(from: link) }
268243
}
269244
}
270245

271-
for try await (wasCached, size) in group {
272-
if wasCached {
273-
cachedCount += 1
274-
} else {
275-
fetchedCount += 1
246+
for await result in group {
247+
switch result {
248+
case .success(let (wasCached, url)):
249+
if wasCached {
250+
cachedCount += 1
251+
} else {
252+
fetchedCount += 1
253+
}
254+
assetURLs.append(url)
255+
case .failure(let error):
256+
log(.error, "Failed to fetch asset: \(error)")
276257
}
277-
totalSize += size
278258
}
279259
}
280260

281-
let totalSizeMB = Double(totalSize) / (1024 * 1024)
282-
log(.info, "Assets loaded: \(fetchedCount) fetched, \(cachedCount) cached, total size: \(String(format: "%.2f", totalSizeMB)) MB")
261+
let totalTime = CFAbsoluteTimeGetCurrent() - startTime
262+
log(.info, "Assets loaded: \(fetchedCount) fetched, \(cachedCount) cached, total size: \(assetURLs.reduce(0) { $0 + $1.fileSize }.formatted) in \(String(format: "%.2f", totalTime))s")
283263
}
284264

285-
/// Fetches a single asset and stores it on disk
286-
/// - Returns: A tuple indicating (wasCached, fileSize)
287-
private func fetchAsset(from urlString: String) async throws -> (Bool, Int64) {
265+
/// Checks if an asset URL is supported
266+
private func isSupportedAsset(_ urlString: String) -> Bool {
288267
guard let url = URL(string: urlString) else {
289268
log(.warn, "Malformed asset link: \(urlString)")
290-
return (false, 0)
269+
return false
291270
}
292271

293272
guard url.scheme == "http" || url.scheme == "https" else {
294273
log(.warn, "Unexpected asset link: \(urlString)")
295-
return (false, 0)
274+
return false
296275
}
297276

298277
let supportedResourceSuffixes = [".js", ".css", ".js.map"]
299278
guard supportedResourceSuffixes.contains(where: { url.lastPathComponent.hasSuffix($0) }) else {
300279
log(.warn, "Unsupported asset URL: \(url)")
301-
return (false, 0)
280+
return false
281+
}
282+
283+
return true
284+
}
285+
286+
/// Fetches a single asset and stores it on disk
287+
/// - Returns: A tuple indicating (wasCached, fileURL)
288+
private func fetchAsset(from urlString: String) async throws -> (Bool, URL) {
289+
guard let url = URL(string: urlString) else {
290+
throw URLError(.badURL)
302291
}
303292

304293
let localURL = assetsDirectoryURL.appendingPathComponent(cachedFilename(for: urlString))
305294

306-
// Check if already cached
307295
if FileManager.default.fileExists(atPath: localURL.path) {
308-
let size = try? FileManager.default.attributesOfItem(atPath: localURL.path)[.size] as? Int64 ?? 0
309-
return (true, size ?? 0)
296+
return (true, localURL)
310297
}
311298

299+
let startTime = CFAbsoluteTimeGetCurrent()
312300
let (downloadedURL, response) = try await urlSession.download(from: url)
313-
if let status = (response as? HTTPURLResponse)?.statusCode, (200..<300).contains(status) {
314-
let size = try? FileManager.default.attributesOfItem(atPath: downloadedURL.path)[.size] as? Int64 ?? 0
315-
do {
316-
try FileManager.default.moveItem(at: downloadedURL, to: localURL)
317-
} catch {
318-
log(.error, "Failed to move downloaded assets \(downloadedURL) \(localURL)")
319-
}
320-
log(.debug, "Downloaded asset: \(url.lastPathComponent) (\(size ?? 0) bytes)")
321-
return (false, size ?? 0)
322-
} else {
323-
log(.error, "Received unexpected HTTP response for URL: \(url)")
324-
return (false, 0)
301+
let downloadTime = CFAbsoluteTimeGetCurrent() - startTime
302+
303+
guard let status = (response as? HTTPURLResponse)?.statusCode, (200..<300).contains(status) else {
304+
throw URLError(.badServerResponse)
325305
}
306+
307+
try FileManager.default.moveItem(at: downloadedURL, to: localURL)
308+
309+
log(.debug, "Downloaded asset: \(url.lastPathComponent) (\(localURL.fileSize.formatted)) in \(String(format: "%.2f", downloadTime))s")
310+
return (false, localURL)
326311
}
327312

328313
/// Loads a cached asset from disk
@@ -347,11 +332,9 @@ actor EditorService {
347332

348333
/// Deletes all cached editor data for all sites
349334
static func deleteAllData() throws {
350-
let rootURL = URL.documentsDirectory.appendingPathComponent("GutenbergKit", isDirectory: true)
351-
guard FileManager.default.fileExists(atPath: rootURL.path) else {
352-
return
335+
if FileManager.default.fileExists(atPath: EditorService.rootURL.path()) {
336+
try FileManager.default.removeItem(at: EditorService.rootURL)
353337
}
354-
try FileManager.default.removeItem(at: rootURL)
355338
}
356339

357340
/// Generates a cached filename from an asset URL using SHA256 hash
@@ -393,3 +376,15 @@ private extension Result {
393376
}
394377
}
395378
}
379+
380+
private extension URL {
381+
var fileSize: Int64 {
382+
(try? FileManager.default.attributesOfItem(atPath: path())[.size] as? Int64) ?? 0
383+
}
384+
}
385+
386+
private extension Int64 {
387+
var formatted: String {
388+
ByteCountFormatter.string(fromByteCount: self, countStyle: .file)
389+
}
390+
}

0 commit comments

Comments
 (0)