mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Add ability to asynchronously hold onto a resource to prevent removal while clearing cache
This commit is contained in:
parent
c04611d809
commit
a0661618f6
@ -287,6 +287,7 @@ final class FFMpegMediaFrameSourceContext: NSObject {
|
|||||||
|
|
||||||
fileprivate var requestedDataOffset: Int?
|
fileprivate var requestedDataOffset: Int?
|
||||||
fileprivate let fetchedDataDisposable = MetaDisposable()
|
fileprivate let fetchedDataDisposable = MetaDisposable()
|
||||||
|
fileprivate let keepDataDisposable = MetaDisposable()
|
||||||
fileprivate let fetchedFullDataDisposable = MetaDisposable()
|
fileprivate let fetchedFullDataDisposable = MetaDisposable()
|
||||||
fileprivate var requestedCompleteFetch = false
|
fileprivate var requestedCompleteFetch = false
|
||||||
|
|
||||||
@ -294,6 +295,7 @@ final class FFMpegMediaFrameSourceContext: NSObject {
|
|||||||
didSet {
|
didSet {
|
||||||
self.fetchedDataDisposable.dispose()
|
self.fetchedDataDisposable.dispose()
|
||||||
self.fetchedFullDataDisposable.dispose()
|
self.fetchedFullDataDisposable.dispose()
|
||||||
|
self.keepDataDisposable.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,6 +318,7 @@ final class FFMpegMediaFrameSourceContext: NSObject {
|
|||||||
|
|
||||||
self.fetchedDataDisposable.dispose()
|
self.fetchedDataDisposable.dispose()
|
||||||
self.fetchedFullDataDisposable.dispose()
|
self.fetchedFullDataDisposable.dispose()
|
||||||
|
self.keepDataDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeState(postbox: Postbox, resourceReference: MediaResourceReference, tempFilePath: String?, streamable: Bool, video: Bool, preferSoftwareDecoding: Bool, fetchAutomatically: Bool, maximumFetchSize: Int?) {
|
func initializeState(postbox: Postbox, resourceReference: MediaResourceReference, tempFilePath: String?, streamable: Bool, video: Bool, preferSoftwareDecoding: Bool, fetchAutomatically: Bool, maximumFetchSize: Int?) {
|
||||||
@ -341,6 +344,10 @@ final class FFMpegMediaFrameSourceContext: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.tempFilePath == nil {
|
||||||
|
self.keepDataDisposable.set(postbox.mediaBox.keepResource(id: resourceReference.resource.id).start())
|
||||||
|
}
|
||||||
|
|
||||||
if streamable {
|
if streamable {
|
||||||
if self.tempFilePath == nil {
|
if self.tempFilePath == nil {
|
||||||
self.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, range: (0 ..< Int(Int32.max), .elevated), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start())
|
self.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, range: (0 ..< Int(Int32.max), .elevated), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start())
|
||||||
|
@ -132,6 +132,14 @@ public enum ResourceDataRequestOption {
|
|||||||
case incremental(waitUntilFetchStatus: Bool)
|
case incremental(waitUntilFetchStatus: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class MediaBoxKeepResourceContext {
|
||||||
|
let subscribers = Bag<Void>()
|
||||||
|
|
||||||
|
var isEmpty: Bool {
|
||||||
|
return self.subscribers.isEmpty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final class MediaBox {
|
public final class MediaBox {
|
||||||
public let basePath: String
|
public let basePath: String
|
||||||
|
|
||||||
@ -145,6 +153,7 @@ public final class MediaBox {
|
|||||||
private var cachedRepresentationContexts: [CachedMediaResourceRepresentationKey: CachedMediaResourceRepresentationContext] = [:]
|
private var cachedRepresentationContexts: [CachedMediaResourceRepresentationKey: CachedMediaResourceRepresentationContext] = [:]
|
||||||
|
|
||||||
private var fileContexts: [WrappedMediaResourceId: MediaBoxFileContext] = [:]
|
private var fileContexts: [WrappedMediaResourceId: MediaBoxFileContext] = [:]
|
||||||
|
private var keepResourceContexts: [WrappedMediaResourceId: MediaBoxKeepResourceContext] = [:]
|
||||||
|
|
||||||
private var wrappedFetchResource = Promise<(MediaResource, Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>>()
|
private var wrappedFetchResource = Promise<(MediaResource, Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>>()
|
||||||
public var preFetchedResourcePath: (MediaResource) -> String? = { _ in return nil }
|
public var preFetchedResourcePath: (MediaResource) -> String? = { _ in return nil }
|
||||||
@ -204,6 +213,10 @@ public final class MediaBox {
|
|||||||
return ResourceStorePaths(partial: "\(self.basePath)/\(fileNameForId(id))_partial", complete: "\(self.basePath)/\(fileNameForId(id))")
|
return ResourceStorePaths(partial: "\(self.basePath)/\(fileNameForId(id))_partial", complete: "\(self.basePath)/\(fileNameForId(id))")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func fileNamesForId(_ id: MediaResourceId) -> ResourceStorePaths {
|
||||||
|
return ResourceStorePaths(partial: "\(fileNameForId(id))_partial", complete: "\(fileNameForId(id))")
|
||||||
|
}
|
||||||
|
|
||||||
private func cachedRepresentationPathsForId(_ id: MediaResourceId, representation: CachedMediaResourceRepresentation) -> ResourceStorePaths {
|
private func cachedRepresentationPathsForId(_ id: MediaResourceId, representation: CachedMediaResourceRepresentation) -> ResourceStorePaths {
|
||||||
let cacheString: String
|
let cacheString: String
|
||||||
switch representation.keepDuration {
|
switch representation.keepDuration {
|
||||||
@ -697,6 +710,38 @@ public final class MediaBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func keepResource(id: MediaResourceId) -> Signal<Never, NoError> {
|
||||||
|
return Signal { subscriber in
|
||||||
|
let disposable = MetaDisposable()
|
||||||
|
|
||||||
|
let dataQueue = self.dataQueue
|
||||||
|
self.dataQueue.async {
|
||||||
|
let context: MediaBoxKeepResourceContext
|
||||||
|
if let current = self.keepResourceContexts[WrappedMediaResourceId(id)] {
|
||||||
|
context = current
|
||||||
|
} else {
|
||||||
|
context = MediaBoxKeepResourceContext()
|
||||||
|
self.keepResourceContexts[WrappedMediaResourceId(id)] = context
|
||||||
|
}
|
||||||
|
let index = context.subscribers.add(Void())
|
||||||
|
|
||||||
|
disposable.set(ActionDisposable { [weak self, weak context] in
|
||||||
|
dataQueue.async {
|
||||||
|
guard let strongSelf = self, let context = context, let currentContext = strongSelf.keepResourceContexts[WrappedMediaResourceId(id)], currentContext === context else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentContext.subscribers.remove(index)
|
||||||
|
if currentContext.isEmpty {
|
||||||
|
strongSelf.keepResourceContexts.removeValue(forKey: WrappedMediaResourceId(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return disposable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func cancelInteractiveResourceFetch(_ resource: MediaResource) {
|
public func cancelInteractiveResourceFetch(_ resource: MediaResource) {
|
||||||
self.dataQueue.async {
|
self.dataQueue.async {
|
||||||
if let (fileContext, releaseContext) = self.fileContext(for: resource) {
|
if let (fileContext, releaseContext) = self.fileContext(for: resource) {
|
||||||
@ -991,7 +1036,20 @@ public final class MediaBox {
|
|||||||
public func removeOtherCachedResources(paths: [String]) -> Signal<Void, NoError> {
|
public func removeOtherCachedResources(paths: [String]) -> Signal<Void, NoError> {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
self.dataQueue.async {
|
self.dataQueue.async {
|
||||||
for path in paths {
|
var keepPrefixes: [String] = []
|
||||||
|
for id in self.keepResourceContexts.keys {
|
||||||
|
let resourcePaths = self.fileNamesForId(id.id)
|
||||||
|
keepPrefixes.append(resourcePaths.partial)
|
||||||
|
keepPrefixes.append(resourcePaths.complete)
|
||||||
|
}
|
||||||
|
|
||||||
|
outer: for path in paths {
|
||||||
|
for prefix in keepPrefixes {
|
||||||
|
if path.starts(with: prefix) {
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unlink(self.basePath + "/" + path)
|
unlink(self.basePath + "/" + path)
|
||||||
}
|
}
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
@ -1007,6 +1065,9 @@ public final class MediaBox {
|
|||||||
if self.fileContexts[id] != nil {
|
if self.fileContexts[id] != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if self.keepResourceContexts[id] != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
let paths = self.storePathsForId(id.id)
|
let paths = self.storePathsForId(id.id)
|
||||||
unlink(paths.complete)
|
unlink(paths.complete)
|
||||||
unlink(paths.partial)
|
unlink(paths.partial)
|
||||||
@ -1044,35 +1105,4 @@ public final class MediaBox {
|
|||||||
return EmptyDisposable
|
return EmptyDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func clearFileContexts() -> Signal<Void, NoError> {
|
|
||||||
return Signal { subscriber in
|
|
||||||
self.dataQueue.async {
|
|
||||||
for (id, _) in self.fileContexts {
|
|
||||||
let paths = self.storePathsForId(id.id)
|
|
||||||
unlink(paths.complete)
|
|
||||||
unlink(paths.partial)
|
|
||||||
unlink(paths.partial + ".meta")
|
|
||||||
}
|
|
||||||
self.fileContexts.removeAll()
|
|
||||||
subscriber.putCompletion()
|
|
||||||
}
|
|
||||||
return EmptyDisposable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func fileConxtets() -> Signal<[(partial: String, complete: String)], NoError> {
|
|
||||||
return Signal { subscriber in
|
|
||||||
self.dataQueue.async {
|
|
||||||
var result: [(partial: String, complete: String)] = []
|
|
||||||
for (id, _) in self.fileContexts {
|
|
||||||
let paths = self.storePathsForId(id.id)
|
|
||||||
result.append((partial: paths.partial, complete: paths.complete))
|
|
||||||
}
|
|
||||||
subscriber.putNext(result)
|
|
||||||
subscriber.putCompletion()
|
|
||||||
}
|
|
||||||
return EmptyDisposable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user