telegram - media resouce data
fozu
on
Jan 18, 20222022-01-18T00:00:00+08:00
Updated
Apr 10, 20232023-04-10T14:35:37+08:00
3 min read
class
MediaResourceData
1
2
3
4
| public let path: String
public let offset: Int
public let size: Int
public let complete: Bool
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| public func resourceData(_ resource: MediaResource, size: Int, in range: Range<Int>, mode: ResourceDataRangeMode = .complete) -> Signal<Data, NoError> {
return Signal { subscriber in
let disposable = MetaDisposable()
self.dataQueue.async {
guard let (fileContext, releaseContext) = self.fileContext(for: resource) else {
subscriber.putCompletion()
return
}
let range = Int32(range.lowerBound) ..< Int32(range.upperBound)
let dataDisposable = fileContext.data(range: range, waitUntilAfterInitialFetch: false, next: { result in
if let file = ManagedFile(queue: self.dataQueue, path: result.path, mode: .read), let fileSize = file.getSize() {
if result.complete {
if result.offset + result.size <= fileSize {
if fileSize >= result.offset + result.size {
file.seek(position: Int64(result.offset))
let resultData = file.readData(count: result.size)
subscriber.putNext(resultData)
subscriber.putCompletion()
} else {
assertionFailure("data.count >= result.offset + result.size")
}
} else {
assertionFailure()
}
} else {
switch mode {
case .complete:
break
case .incremental:
break
case .partial:
subscriber.putNext(Data())
}
}
}
})
disposable.set(ActionDisposable {
dataDisposable.dispose()
releaseContext()
})
}
return disposable
}
}
|
class
MediaBoxFileContext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| private let queue: Queue
private let path: String
private let partialPath: String
private let metaPath: String
private var content: MediaBoxFileContent
private let references = CounterBag()
var isEmpty: Bool {
return self.references.isEmpty
}
func data(range: Range<Int32>, waitUntilAfterInitialFetch: Bool, next: @escaping (MediaResourceData) -> Void) -> Disposable {
switch self.content {
case let .complete(path, size):
next(MediaResourceData(path: path, offset: Int(range.lowerBound), size: min(Int(range.upperBound), size) - Int(range.lowerBound), complete: true))
return EmptyDisposable
case let .partial(file):
return file.data(range: range, waitUntilAfterInitialFetch: waitUntilAfterInitialFetch, next: next)
}
}
|
maybePredownloadedImageResource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| private func maybePredownloadedImageResource(postbox: Postbox, peerId: PeerId, resource: MediaResource, forceRefresh: Bool) -> Signal<PredownloadedResource, PendingMessageUploadError> {
if peerId.namespace == Namespaces.Peer.SecretChat {
return .single(.none)
}
return Signal<Signal<PredownloadedResource, PendingMessageUploadError>, PendingMessageUploadError> { subscriber in
let data = postbox.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false)).start(next: { data in
if data.complete {
if data.size < 5 * 1024 * 1024, let fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: .mappedRead) {
let md5 = IncrementalMD5()
fileData.withUnsafeBytes { (bytes: UnsafePointer<Int8>) -> Void in
var offset = 0
let bufferSize = 32 * 1024
while offset < fileData.count {
let partSize = min(fileData.count - offset, bufferSize)
md5.update(bytes.advanced(by: offset), count: Int32(partSize))
offset += bufferSize
}
}
let res = md5.complete()
let reference: CachedSentMediaReferenceKey = .image(hash: res)
if forceRefresh {
subscriber.putNext(.single(.localReference(reference)))
} else {
subscriber.putNext(cachedSentMediaReference(postbox: postbox, key: reference)
|> mapError { _ -> PendingMessageUploadError in return .generic } |> map { media -> PredownloadedResource in
if let media = media {
return .media(media)
} else {
return .localReference(reference)
}
})
}
subscriber.putCompletion()
} else {
subscriber.putNext(.single(.localReference(nil)))
subscriber.putCompletion()
}
}
})
let fetched = postbox.mediaBox.fetchedResource(resource, parameters: nil).start(error: { _ in
subscriber.putError(.generic)
})
return ActionDisposable {
data.dispose()
fetched.dispose()
}
}
|> switchToLatest
}
|
This post is licensed under
CC BY 4.0
by the author.