Home telegram - media resouce data
Post
Cancel

telegram - media resouce data

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.