forked from insidegui/WWDC
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Modernized transcripts XPC, exposing progress to client. Fixes crash …
…when changing language.
- Loading branch information
Showing
11 changed files
with
323 additions
and
195 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// | ||
// TranscriptIndexingClient.swift | ||
// ConfCore | ||
// | ||
// Created by Guilherme Rambo on 27/05/20. | ||
// Copyright © 2020 Guilherme Rambo. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import RxSwift | ||
import os.log | ||
|
||
final class TranscriptIndexingClient: NSObject, TranscriptIndexingClientProtocol { | ||
|
||
private let log = OSLog(subsystem: "ConfCore", category: String(describing: TranscriptIndexingClient.self)) | ||
|
||
var transcriptLanguage: String { | ||
didSet { | ||
guard transcriptLanguage != oldValue else { return } | ||
|
||
didRunService = false | ||
startIndexing(ignoringCache: true) | ||
} | ||
} | ||
|
||
private let storage: Storage | ||
private let appleClient: AppleAPIClient | ||
|
||
init(language: String, storage: Storage, appleClient: AppleAPIClient) { | ||
self.transcriptLanguage = language | ||
self.storage = storage | ||
self.appleClient = appleClient | ||
|
||
super.init() | ||
|
||
transcriptIndexingConnection.resume() | ||
} | ||
|
||
let isIndexing = BehaviorSubject<Bool>(value: false) | ||
let indexingProgress = BehaviorSubject<Float>(value: 0) | ||
|
||
private var didRunService = false | ||
|
||
private lazy var transcriptIndexingConnection: NSXPCConnection = { | ||
let c = NSXPCConnection(serviceName: "io.wwdc.app.TranscriptIndexingService") | ||
|
||
c.remoteObjectInterface = NSXPCInterface(with: TranscriptIndexingServiceProtocol.self) | ||
c.exportedInterface = NSXPCInterface(with: TranscriptIndexingClientProtocol.self) | ||
c.exportedObject = self | ||
|
||
return c | ||
}() | ||
|
||
private var transcriptIndexingService: TranscriptIndexingServiceProtocol? { | ||
return transcriptIndexingConnection.remoteObjectProxyWithErrorHandler { [weak self] error in | ||
guard let self = self else { return } | ||
os_log("Failed to get remote object proxy: %{public}@", log: self.log, type: .fault, String(describing: error)) | ||
} as? TranscriptIndexingServiceProtocol | ||
} | ||
|
||
private var migratedTranscriptsToNativeVersion: Bool { | ||
get { UserDefaults.standard.bool(forKey: #function) } | ||
set { UserDefaults.standard.set(newValue, forKey: #function) } | ||
} | ||
|
||
func startIndexing(ignoringCache ignoreCache: Bool) { | ||
guard !ProcessInfo.processInfo.arguments.contains("--disable-transcripts") else { return } | ||
|
||
if !migratedTranscriptsToNativeVersion { | ||
os_log("Transcripts need migration", log: self.log, type: .debug) | ||
} | ||
|
||
if !ignoreCache && migratedTranscriptsToNativeVersion { | ||
guard TranscriptIndexer.needsUpdate(in: storage) else { return } | ||
} | ||
|
||
guard !didRunService else { return } | ||
didRunService = true | ||
|
||
appleClient.fetchConfig { [weak self] result in | ||
guard let self = self else { return } | ||
|
||
switch result { | ||
case .success(let config): | ||
self.doStartTranscriptIndexing(with: config, ignoringCache: ignoreCache) | ||
case .failure(let error): | ||
os_log("Config fetch failed: %{public}@", log: self.log, type: .error, String(describing: error)) | ||
} | ||
} | ||
} | ||
|
||
private func doStartTranscriptIndexing(with config: RootConfig, ignoringCache ignoreCache: Bool) { | ||
os_log("%{public}@", log: log, type: .debug, #function) | ||
|
||
guard let feeds = config.feeds[transcriptLanguage] ?? config.feeds[RootConfig.fallbackFeedLanguage] else { | ||
os_log("No feeds found for currently set language (%@) or fallback language (%@)", log: self.log, type: .error, transcriptLanguage, RootConfig.fallbackFeedLanguage) | ||
return | ||
} | ||
|
||
guard let storageURL = storage.realmConfig.fileURL else { return } | ||
|
||
TranscriptIndexer.lastManifestBasedUpdateDate = Date() | ||
migratedTranscriptsToNativeVersion = true | ||
|
||
transcriptIndexingService?.indexTranscriptsIfNeeded( | ||
manifestURL: feeds.transcripts.url, | ||
ignoringCache: ignoreCache, | ||
storageURL: storageURL, | ||
schemaVersion: storage.realmConfig.schemaVersion | ||
) | ||
} | ||
|
||
func transcriptIndexingStarted() { | ||
os_log("%{public}@", log: log, type: .debug, #function) | ||
|
||
isIndexing.on(.next(true)) | ||
} | ||
|
||
func transcriptIndexingProgressDidChange(_ progress: Float) { | ||
indexingProgress.on(.next(progress)) | ||
} | ||
|
||
func transcriptIndexingStopped() { | ||
os_log("%{public}@", log: log, type: .debug, #function) | ||
|
||
isIndexing.on(.next(false)) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// | ||
// TranscriptIndexingClientProtocol.swift | ||
// ConfCore | ||
// | ||
// Created by Guilherme Rambo on 27/05/20. | ||
// Copyright © 2020 Guilherme Rambo. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
@objc public protocol TranscriptIndexingClientProtocol: NSObjectProtocol { | ||
|
||
func transcriptIndexingStarted() | ||
func transcriptIndexingProgressDidChange(_ progress: Float) | ||
func transcriptIndexingStopped() | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// | ||
// TranscriptIndexingService.swift | ||
// WWDC | ||
// | ||
// Created by Guilherme Rambo on 28/05/17. | ||
// Copyright © 2017 Guilherme Rambo. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import RealmSwift | ||
import os.log | ||
|
||
@objcMembers public final class TranscriptIndexingService: NSObject, TranscriptIndexingServiceProtocol { | ||
|
||
private var indexer: TranscriptIndexer! | ||
private let log = OSLog(subsystem: "TranscriptIndexingService", category: "TranscriptIndexingService") | ||
|
||
public func indexTranscriptsIfNeeded(manifestURL: URL, ignoringCache: Bool, storageURL: URL, schemaVersion: UInt64) { | ||
do { | ||
let config = Realm.Configuration(fileURL: storageURL, schemaVersion: schemaVersion) | ||
let storage = try Storage(config) | ||
|
||
indexer = TranscriptIndexer(storage, manifestURL: manifestURL) | ||
|
||
indexer.didStart = { [weak self] in | ||
self?.clients.forEach { $0.transcriptIndexingStarted() } | ||
} | ||
indexer.progressChanged = { [weak self] progress in | ||
self?.clients.forEach { $0.transcriptIndexingProgressDidChange(progress) } | ||
} | ||
indexer.didStop = { [weak self] in | ||
self?.clients.forEach { $0.transcriptIndexingStopped() } | ||
} | ||
|
||
indexer.manifestURL = manifestURL | ||
indexer.ignoreExistingEtags = ignoringCache | ||
|
||
indexer.downloadTranscriptsIfNeeded() | ||
} catch { | ||
os_log("Error initializing indexing service: %{public}@", log: self.log, type: .fault, String(describing: error)) | ||
return | ||
} | ||
} | ||
|
||
private lazy var listener: NSXPCListener = { | ||
let l = NSXPCListener.service() | ||
|
||
l.delegate = self | ||
|
||
return l | ||
}() | ||
|
||
public func resume() { | ||
listener.resume() | ||
} | ||
|
||
private var connections: [NSXPCConnection] = [] | ||
|
||
private var clients: [TranscriptIndexingClientProtocol] { | ||
connections.compactMap { $0.remoteObjectProxy as? TranscriptIndexingClientProtocol } | ||
} | ||
|
||
} | ||
|
||
extension TranscriptIndexingService: NSXPCListenerDelegate { | ||
|
||
public func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { | ||
newConnection.exportedInterface = NSXPCInterface(with: TranscriptIndexingServiceProtocol.self) | ||
newConnection.exportedObject = self | ||
|
||
newConnection.remoteObjectInterface = NSXPCInterface(with: TranscriptIndexingClientProtocol.self) | ||
|
||
newConnection.invalidationHandler = { [weak self] in | ||
guard let self = self else { return } | ||
|
||
os_log("Connection invalidated: %{public}@", log: self.log, type: .debug, String(describing: newConnection)) | ||
|
||
self.connections.removeAll(where: { $0 == newConnection }) | ||
} | ||
|
||
connections.append(newConnection) | ||
|
||
newConnection.resume() | ||
|
||
return true | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.