FetchV2 improvements

This commit is contained in:
Ali 2023-04-11 23:11:54 +04:00
parent 289367e28b
commit 4c72c3f75d
17 changed files with 158 additions and 52 deletions

View File

@ -21,6 +21,7 @@ swift_library(
"//submodules/rlottie:RLottieBinding", "//submodules/rlottie:RLottieBinding",
"//submodules/GZip:GZip", "//submodules/GZip:GZip",
"//submodules/PersistentStringHash:PersistentStringHash", "//submodules/PersistentStringHash:PersistentStringHash",
"//submodules/Utils/RangeSet",
], ],
visibility = [ visibility = [

View File

@ -15,6 +15,7 @@ import PersistentStringHash
import CallKit import CallKit
import AppLockState import AppLockState
import NotificationsPresentationData import NotificationsPresentationData
import RangeSet
private let queue = Queue() private let queue = Queue()
@ -1187,7 +1188,7 @@ private final class NotificationServiceHandler {
fetchMediaSignal = Signal { subscriber in fetchMediaSignal = Signal { subscriber in
final class DataValue { final class DataValue {
var data = Data() var data = Data()
var totalSize: Int64? var missingRanges = RangeSet<Int64>(0 ..< Int64.max)
} }
let collectedData = Atomic<DataValue>(value: DataValue()) let collectedData = Atomic<DataValue>(value: DataValue())
@ -1217,12 +1218,22 @@ private final class NotificationServiceHandler {
useMainConnection: true useMainConnection: true
).start(next: { result in ).start(next: { result in
switch result { switch result {
case let .dataPart(_, data, _, _): case let .dataPart(offset, data, dataRange, _):
var isCompleted = false var isCompleted = false
let _ = collectedData.modify { current in let _ = collectedData.modify { current in
let current = current let current = current
current.data.append(data)
if let totalSize = current.totalSize, Int64(current.data.count) >= totalSize { let fillRange = Int(offset) ..< (Int(offset) + data.count)
if current.data.count < fillRange.upperBound {
current.data.count = fillRange.upperBound
}
current.data.withUnsafeMutableBytes { buffer -> Void in
let bytes = buffer.baseAddress!.assumingMemoryBound(to: UInt8.self)
data.copyBytes(to: bytes.advanced(by: Int(offset)), from: Int(dataRange.lowerBound) ..< Int(dataRange.upperBound))
}
current.missingRanges.remove(contentsOf: Int64(fillRange.lowerBound) ..< Int64(fillRange.upperBound))
if current.missingRanges.isEmpty {
isCompleted = true isCompleted = true
} }
return current return current
@ -1235,8 +1246,8 @@ private final class NotificationServiceHandler {
var isCompleted = false var isCompleted = false
let _ = collectedData.modify { current in let _ = collectedData.modify { current in
let current = current let current = current
current.totalSize = size current.missingRanges.remove(contentsOf: size ..< Int64.max)
if Int64(current.data.count) >= size { if current.missingRanges.isEmpty {
isCompleted = true isCompleted = true
} }
return current return current

View File

@ -330,7 +330,7 @@ private final class AnimatedStickerDirectFrameSourceCache {
return .notFound return .notFound
} }
self.file.seek(position: Int64(index * 4 * 2)) let _ = self.file.seek(position: Int64(index * 4 * 2))
var offset: Int32 = 0 var offset: Int32 = 0
var length: Int32 = 0 var length: Int32 = 0
if self.file.read(&offset, 4) != 4 { if self.file.read(&offset, 4) != 4 {
@ -384,12 +384,12 @@ private final class AnimatedStickerDirectFrameSourceCache {
return return
} }
strongSelf.file.seek(position: Int64(index * 4 * 2)) let _ = strongSelf.file.seek(position: Int64(index * 4 * 2))
var offset = Int32(currentSize) var offset = Int32(currentSize)
var length = Int32(compressedData.data.count) var length = Int32(compressedData.data.count)
let _ = strongSelf.file.write(&offset, count: 4) let _ = strongSelf.file.write(&offset, count: 4)
let _ = strongSelf.file.write(&length, count: 4) let _ = strongSelf.file.write(&length, count: 4)
strongSelf.file.seek(position: Int64(currentSize)) let _ = strongSelf.file.seek(position: Int64(currentSize))
compressedData.data.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> Void in compressedData.data.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> Void in
if let baseAddress = buffer.baseAddress { if let baseAddress = buffer.baseAddress {
let _ = strongSelf.file.write(baseAddress, count: Int(length)) let _ = strongSelf.file.write(baseAddress, count: Int(length))
@ -427,12 +427,12 @@ private final class AnimatedStickerDirectFrameSourceCache {
return return
} }
strongSelf.file.seek(position: Int64(index * 4 * 2)) let _ = strongSelf.file.seek(position: Int64(index * 4 * 2))
var offset = Int32(currentSize) var offset = Int32(currentSize)
var length = Int32(compressedData.count) var length = Int32(compressedData.count)
let _ = strongSelf.file.write(&offset, count: 4) let _ = strongSelf.file.write(&offset, count: 4)
let _ = strongSelf.file.write(&length, count: 4) let _ = strongSelf.file.write(&length, count: 4)
strongSelf.file.seek(position: Int64(currentSize)) let _ = strongSelf.file.seek(position: Int64(currentSize))
compressedData.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> Void in compressedData.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> Void in
if let baseAddress = buffer.baseAddress { if let baseAddress = buffer.baseAddress {
let _ = strongSelf.file.write(baseAddress, count: Int(length)) let _ = strongSelf.file.write(baseAddress, count: Int(length))
@ -502,7 +502,7 @@ private final class AnimatedStickerDirectFrameSourceCache {
switch rangeResult { switch rangeResult {
case let .range(range): case let .range(range):
self.file.seek(position: Int64(range.lowerBound)) let _ = self.file.seek(position: Int64(range.lowerBound))
let length = range.upperBound - range.lowerBound let length = range.upperBound - range.lowerBound
let compressedData = self.file.readData(count: length) let compressedData = self.file.readData(count: length)
if compressedData.count != length { if compressedData.count != length {

View File

@ -100,7 +100,7 @@ private final class VideoStickerFrameSourceCache {
return true return true
} }
self.file.seek(position: 0) let _ = self.file.seek(position: 0)
var frameRate: Int32 = 0 var frameRate: Int32 = 0
if self.file.read(&frameRate, 4) != 4 { if self.file.read(&frameRate, 4) != 4 {
return false return false
@ -113,7 +113,7 @@ private final class VideoStickerFrameSourceCache {
} }
self.frameRate = frameRate self.frameRate = frameRate
self.file.seek(position: 4) let _ = self.file.seek(position: 4)
var frameCount: Int32 = 0 var frameCount: Int32 = 0
if self.file.read(&frameCount, 4) != 4 { if self.file.read(&frameCount, 4) != 4 {
@ -144,7 +144,7 @@ private final class VideoStickerFrameSourceCache {
return .notFound return .notFound
} }
self.file.seek(position: Int64(8 + index * 4 * 2)) let _ = self.file.seek(position: Int64(8 + index * 4 * 2))
var offset: Int32 = 0 var offset: Int32 = 0
var length: Int32 = 0 var length: Int32 = 0
if self.file.read(&offset, 4) != 4 { if self.file.read(&offset, 4) != 4 {
@ -167,11 +167,11 @@ private final class VideoStickerFrameSourceCache {
} }
func storeFrameRateAndCount(frameRate: Int, frameCount: Int) { func storeFrameRateAndCount(frameRate: Int, frameCount: Int) {
self.file.seek(position: 0) let _ = self.file.seek(position: 0)
var frameRate = Int32(frameRate) var frameRate = Int32(frameRate)
let _ = self.file.write(&frameRate, count: 4) let _ = self.file.write(&frameRate, count: 4)
self.file.seek(position: 4) let _ = self.file.seek(position: 4)
var frameCount = Int32(frameCount) var frameCount = Int32(frameCount)
let _ = self.file.write(&frameCount, count: 4) let _ = self.file.write(&frameCount, count: 4)
} }
@ -203,12 +203,12 @@ private final class VideoStickerFrameSourceCache {
return return
} }
strongSelf.file.seek(position: Int64(8 + index * 4 * 2)) let _ = strongSelf.file.seek(position: Int64(8 + index * 4 * 2))
var offset = Int32(currentSize) var offset = Int32(currentSize)
var length = Int32(compressedData.count) var length = Int32(compressedData.count)
let _ = strongSelf.file.write(&offset, count: 4) let _ = strongSelf.file.write(&offset, count: 4)
let _ = strongSelf.file.write(&length, count: 4) let _ = strongSelf.file.write(&length, count: 4)
strongSelf.file.seek(position: Int64(currentSize)) let _ = strongSelf.file.seek(position: Int64(currentSize))
compressedData.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> Void in compressedData.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> Void in
if let baseAddress = buffer.baseAddress { if let baseAddress = buffer.baseAddress {
let _ = strongSelf.file.write(baseAddress, count: Int(length)) let _ = strongSelf.file.write(baseAddress, count: Int(length))
@ -226,7 +226,7 @@ private final class VideoStickerFrameSourceCache {
switch rangeResult { switch rangeResult {
case let .range(range): case let .range(range):
self.file.seek(position: Int64(range.lowerBound)) let _ = self.file.seek(position: Int64(range.lowerBound))
let length = range.upperBound - range.lowerBound let length = range.upperBound - range.lowerBound
let compressedData = self.file.readData(count: length) let compressedData = self.file.readData(count: length)
if compressedData.count != length { if compressedData.count != length {

View File

@ -75,7 +75,7 @@ public final class MeshWriteBuffer {
} }
public func seek(offset: Int) { public func seek(offset: Int) {
self.file.seek(position: Int64(offset)) let _ = self.file.seek(position: Int64(offset))
self.offset = offset self.offset = offset
} }
} }

View File

@ -99,12 +99,14 @@ public final class ManagedFile {
return result return result
} }
public func seek(position: Int64) { @discardableResult
public func seek(position: Int64) -> Bool {
if let queue = self.queue { if let queue = self.queue {
assert(queue.isCurrent()) assert(queue.isCurrent())
} }
assert(!self.isClosed) assert(!self.isClosed)
lseek(self.fd, position, SEEK_SET) let result = lseek(self.fd, position, SEEK_SET)
return result == position
} }
public func truncate(count: Int64) { public func truncate(count: Int64) {

View File

@ -139,7 +139,7 @@ public final class MediaBox {
private let statusQueue = Queue() private let statusQueue = Queue()
private let concurrentQueue = Queue.concurrentDefaultQueue() private let concurrentQueue = Queue.concurrentDefaultQueue()
private let dataQueue = Queue() private let dataQueue = Queue(name: "MediaBox-Data")
private let dataFileManager: MediaBoxFileManager private let dataFileManager: MediaBoxFileManager
private let cacheQueue = Queue() private let cacheQueue = Queue()
private let timeBasedCleanup: TimeBasedCleanup private let timeBasedCleanup: TimeBasedCleanup
@ -209,6 +209,58 @@ public final class MediaBox {
let _ = self.ensureDirectoryCreated let _ = self.ensureDirectoryCreated
//self.updateResourceIndex() //self.updateResourceIndex()
/*#if DEBUG
self.dataQueue.async {
for _ in 0 ..< 5 {
let tempFile = TempBox.shared.tempFile(fileName: "file")
print("MediaBox test: file \(tempFile.path)")
let queue2 = Queue.concurrentDefaultQueue()
if let fileContext = MediaBoxFileContextV2Impl(queue: self.dataQueue, manager: self.dataFileManager, storageBox: self.storageBox, resourceId: tempFile.path.data(using: .utf8)!, path: tempFile.path + "_complete", partialPath: tempFile.path + "_partial", metaPath: tempFile.path + "_partial" + ".meta") {
let _ = fileContext.fetched(
range: 0 ..< Int64.max,
priority: .default,
fetch: { ranges in
return ranges
|> filter { !$0.isEmpty }
|> take(1)
|> castError(MediaResourceDataFetchError.self)
|> mapToSignal { _ in
return Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> { subscriber in
queue2.async {
subscriber.putNext(.resourceSizeUpdated(524288))
}
queue2.async {
subscriber.putNext(.resourceSizeUpdated(393216))
}
queue2.async {
subscriber.putNext(.resourceSizeUpdated(655360))
}
queue2.async {
subscriber.putNext(.resourceSizeUpdated(169608))
}
queue2.async {
subscriber.putNext(.dataPart(resourceOffset: 131072, data: Data(repeating: 0xbb, count: 38536), range: 0 ..< 38536, complete: true))
}
queue2.async {
subscriber.putNext(.dataPart(resourceOffset: 0, data: Data(repeating: 0xaa, count: 131072), range: 0 ..< 131072, complete: false))
}
return EmptyDisposable
}
}
},
error: { _ in
},
completed: {
assert(try! Data(contentsOf: URL(fileURLWithPath: tempFile.path + "_complete")) == Data(repeating: 0xaa, count: 131072) + Data(repeating: 0xbb, count: 38536))
let _ = fileContext.addReference()
}
)
}
}
}
#endif*/
} }
public func setMaxStoreTimes(general: Int32, shortLived: Int32, gigabytesLimit: Int32) { public func setMaxStoreTimes(general: Int32, shortLived: Int32, gigabytesLimit: Int32) {
@ -688,7 +740,7 @@ public final class MediaBox {
let clippedLowerBound = min(completeSize, max(0, range.lowerBound)) let clippedLowerBound = min(completeSize, max(0, range.lowerBound))
let clippedUpperBound = min(completeSize, max(0, range.upperBound)) let clippedUpperBound = min(completeSize, max(0, range.upperBound))
if clippedLowerBound < clippedUpperBound && (clippedUpperBound - clippedLowerBound) <= 64 * 1024 * 1024 { if clippedLowerBound < clippedUpperBound && (clippedUpperBound - clippedLowerBound) <= 64 * 1024 * 1024 {
file.seek(position: clippedLowerBound) let _ = file.seek(position: clippedLowerBound)
let data = file.readData(count: Int(clippedUpperBound - clippedLowerBound)) let data = file.readData(count: Int(clippedUpperBound - clippedLowerBound))
subscriber.putNext((data, true)) subscriber.putNext((data, true))
} else { } else {
@ -725,7 +777,7 @@ public final class MediaBox {
subscriber.putNext((Data(), true)) subscriber.putNext((Data(), true))
subscriber.putCompletion() subscriber.putCompletion()
} else if clippedUpperBound <= fileSize && (clippedUpperBound - clippedLowerBound) <= 64 * 1024 * 1024 { } else if clippedUpperBound <= fileSize && (clippedUpperBound - clippedLowerBound) <= 64 * 1024 * 1024 {
file.seek(position: Int64(clippedLowerBound)) let _ = file.seek(position: Int64(clippedLowerBound))
let resultData = file.readData(count: Int(clippedUpperBound - clippedLowerBound)) let resultData = file.readData(count: Int(clippedUpperBound - clippedLowerBound))
subscriber.putNext((resultData, true)) subscriber.putNext((resultData, true))
subscriber.putCompletion() subscriber.putCompletion()

View File

@ -88,7 +88,7 @@ final class MediaBoxPartialFile {
guard let clippedRange = fileMap.contains(range) else { guard let clippedRange = fileMap.contains(range) else {
return nil return nil
} }
fd.seek(position: Int64(clippedRange.lowerBound)) let _ = fd.seek(position: Int64(clippedRange.lowerBound))
return fd.readData(count: Int(clippedRange.upperBound - clippedRange.lowerBound)) return fd.readData(count: Int(clippedRange.upperBound - clippedRange.lowerBound))
} }
@ -227,7 +227,7 @@ final class MediaBoxPartialFile {
do { do {
try self.fd.access { fd in try self.fd.access { fd in
fd.seek(position: offset) let _ = fd.seek(position: offset)
let written = data.withUnsafeBytes { rawBytes -> Int in let written = data.withUnsafeBytes { rawBytes -> Int in
let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
@ -330,7 +330,7 @@ final class MediaBoxPartialFile {
do { do {
var result: Data? var result: Data?
try self.fd.access { fd in try self.fd.access { fd in
fd.seek(position: Int64(actualRange.lowerBound)) let _ = fd.seek(position: Int64(actualRange.lowerBound))
var data = Data(count: actualRange.count) var data = Data(count: actualRange.count)
let dataCount = data.count let dataCount = data.count
let readBytes = data.withUnsafeMutableBytes { rawBytes -> Int in let readBytes = data.withUnsafeMutableBytes { rawBytes -> Int in

View File

@ -421,21 +421,28 @@ final class MediaBoxFileContextV2Impl: MediaBoxFileContext {
private func processWrite(resourceOffset: Int64, data: Data, dataRange: Range<Int64>) { private func processWrite(resourceOffset: Int64, data: Data, dataRange: Range<Int64>) {
if let destinationFile = self.destinationFile { if let destinationFile = self.destinationFile {
do { do {
var success = true
try destinationFile.access { fd in try destinationFile.access { fd in
fd.seek(position: resourceOffset) if fd.seek(position: resourceOffset) {
let written = data.withUnsafeBytes { rawBytes -> Int in let written = data.withUnsafeBytes { rawBytes -> Int in
let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
return fd.write(bytes.advanced(by: Int(dataRange.lowerBound)), count: dataRange.count) return fd.write(bytes.advanced(by: Int(dataRange.lowerBound)), count: dataRange.count)
}
assert(written == dataRange.count)
} else {
success = false
} }
assert(written == dataRange.count)
} }
if success {
let range: Range<Int64> = resourceOffset ..< (resourceOffset + Int64(dataRange.count)) let range: Range<Int64> = resourceOffset ..< (resourceOffset + Int64(dataRange.count))
self.fileMap.fill(range) self.fileMap.fill(range)
self.fileMap.serialize(manager: self.manager, to: self.metaPath) self.fileMap.serialize(manager: self.manager, to: self.metaPath)
self.storageBox.update(id: self.resourceId, size: self.fileMap.sum) self.storageBox.update(id: self.resourceId, size: self.fileMap.sum)
} else {
postboxLog("MediaBoxFileContextV2Impl: error seeking file to \(resourceOffset) at \(self.partialPath)")
}
} catch let e { } catch let e {
postboxLog("MediaBoxFileContextV2Impl: error writing file at \(self.partialPath): \(e)") postboxLog("MediaBoxFileContextV2Impl: error writing file at \(self.partialPath): \(e)")
} }

View File

@ -32,8 +32,8 @@ final class MediaBoxFileManager {
return self.file.readData(count: count) return self.file.readData(count: count)
} }
func seek(position: Int64) { func seek(position: Int64) -> Bool {
self.file.seek(position: position) return self.file.seek(position: position)
} }
} }

View File

@ -203,7 +203,7 @@ final class MediaBoxFileMap {
} }
let _ = try? fileItem.access { file in let _ = try? fileItem.access { file in
file.seek(position: 0) let _ = file.seek(position: 0)
let buffer = WriteBuffer() let buffer = WriteBuffer()
var magic: UInt32 = 0x7bac1487 var magic: UInt32 = 0x7bac1487
buffer.write(&magic, offset: 0, length: 4) buffer.write(&magic, offset: 0, length: 4)

View File

@ -181,9 +181,17 @@ private func collectExternalShareItems(strings: PresentationStrings, dateTimeFor
case .progress: case .progress:
return .progress return .progress
case let .done(data): case let .done(data):
if let fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path)), let image = UIImage(data: fileData) { guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path)) else {
return .progress
}
if let image = UIImage(data: fileData) {
return .done(.image(image)) return .done(.image(image))
} else { } else {
#if DEBUG
if "".isEmpty {
return .done(.file(URL(fileURLWithPath: data.path), "image.bin", "application/octet-stream"))
}
#endif
return .progress return .progress
} }
} }

View File

@ -387,7 +387,7 @@ public func cacheVideoStickerFrames(path: String, size: CGSize, cacheKey: String
} }
if frameCount > 0 { if frameCount > 0 {
file.seek(position: 4) let _ = file.seek(position: 4)
let _ = file.write(&frameCount, count: 4) let _ = file.write(&frameCount, count: 4)
} }

View File

@ -647,8 +647,8 @@ private final class FetchImpl {
Logger.shared.log("FetchV2", "\(self.loggingIdentifier): setting known size to \(resultingSize)") Logger.shared.log("FetchV2", "\(self.loggingIdentifier): setting known size to \(resultingSize)")
self.knownSize = resultingSize self.knownSize = resultingSize
} }
Logger.shared.log("FetchV2", "\(self.loggingIdentifier): reporting resource size \(fetchRange.lowerBound + actualLength)") Logger.shared.log("FetchV2", "\(self.loggingIdentifier): reporting resource size \(resultingSize)")
self.onNext(.resourceSizeUpdated(fetchRange.lowerBound + actualLength)) self.onNext(.resourceSizeUpdated(resultingSize))
} }
state.completedRanges.formUnion(RangeSet<Int64>(partRange)) state.completedRanges.formUnion(RangeSet<Int64>(partRange))

View File

@ -186,7 +186,7 @@ private final class MultipartUploadManager {
self.bigTotalParts = nil self.bigTotalParts = nil
} else { } else {
self.bigParts = false self.bigParts = false
self.defaultPartSize = 16 * 1024 self.defaultPartSize = 128 * 1024
self.bigTotalParts = nil self.bigTotalParts = nil
} }
} }
@ -317,7 +317,7 @@ private final class MultipartUploadManager {
switch resourceData { switch resourceData {
case let .resourceData(data): case let .resourceData(data):
if let file = ManagedFile(queue: nil, path: data.path, mode: .read) { if let file = ManagedFile(queue: nil, path: data.path, mode: .read) {
file.seek(position: Int64(partOffset)) let _ = file.seek(position: Int64(partOffset))
let data = file.readData(count: Int(partSize)) let data = file.readData(count: Int(partSize))
if data.count == partSize { if data.count == partSize {
partData = data partData = data

View File

@ -172,6 +172,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case sendWhenOnlineTip = 38 case sendWhenOnlineTip = 38
case chatWallpaperLightPreviewTip = 39 case chatWallpaperLightPreviewTip = 39
case chatWallpaperDarkPreviewTip = 40 case chatWallpaperDarkPreviewTip = 40
case displayChatListContacts = 41
var key: ValueBoxKey { var key: ValueBoxKey {
let v = ValueBoxKey(length: 4) let v = ValueBoxKey(length: 4)
@ -389,6 +390,10 @@ private struct ApplicationSpecificNoticeKeys {
static func sendWhenOnlineTip() -> NoticeEntryKey { static func sendWhenOnlineTip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.sendWhenOnlineTip.key) return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.sendWhenOnlineTip.key)
} }
static func displayChatListContacts() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.displayChatListContacts.key)
}
} }
public struct ApplicationSpecificNotice { public struct ApplicationSpecificNotice {
@ -1420,6 +1425,26 @@ public struct ApplicationSpecificNotice {
} }
} }
public static func displayChatListContacts(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Bool, NoError> {
return accountManager.noticeEntry(key: ApplicationSpecificNoticeKeys.displayChatListContacts())
|> map { view -> Bool in
if let _ = view.value?.get(ApplicationSpecificBoolNotice.self) {
return true
} else {
return false
}
}
}
public static func setDisplayChatListContacts(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Never, NoError> {
return accountManager.transaction { transaction -> Void in
if let entry = CodableEntry(ApplicationSpecificBoolNotice()) {
transaction.setNotice(ApplicationSpecificNoticeKeys.displayChatListContacts(), entry)
}
}
|> ignoreValues
}
public static func reset(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Void, NoError> { public static func reset(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Void, NoError> {
return accountManager.transaction { transaction -> Void in return accountManager.transaction { transaction -> Void in
} }

View File

@ -605,10 +605,10 @@ private final class AnimationCacheItemWriterImpl: AnimationCacheItemWriter {
let metadataPosition = file.position() let metadataPosition = file.position()
let contentLength = Int(metadataPosition) - contentLengthOffset - 4 let contentLength = Int(metadataPosition) - contentLengthOffset - 4
file.seek(position: Int64(contentLengthOffset)) let _ = file.seek(position: Int64(contentLengthOffset))
file.write(UInt32(contentLength)) file.write(UInt32(contentLength))
file.seek(position: metadataPosition) let _ = file.seek(position: metadataPosition)
file.write(UInt32(self.frames.count)) file.write(UInt32(self.frames.count))
for frame in self.frames { for frame in self.frames {
file.write(Float32(frame.duration)) file.write(Float32(frame.duration))