mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
refactor and cleanup [skip ci]
This commit is contained in:
165
submodules/Postbox/Sources/TempBox.swift
Normal file
165
submodules/Postbox/Sources/TempBox.swift
Normal file
@@ -0,0 +1,165 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
|
||||
private final class TempBoxFileContext {
|
||||
let directory: String
|
||||
let fileName: String
|
||||
var subscribers = Set<Int>()
|
||||
|
||||
var path: String {
|
||||
return self.directory + "/" + self.fileName
|
||||
}
|
||||
|
||||
init(directory: String, fileName: String) {
|
||||
self.directory = directory
|
||||
self.fileName = fileName
|
||||
}
|
||||
}
|
||||
|
||||
private struct TempBoxKey: Equatable, Hashable {
|
||||
let path: String?
|
||||
let fileName: String
|
||||
let uniqueId: Int?
|
||||
}
|
||||
|
||||
public final class TempBoxFile {
|
||||
fileprivate let key: TempBoxKey
|
||||
fileprivate let id: Int
|
||||
public let path: String
|
||||
|
||||
fileprivate init(key: TempBoxKey, id: Int, path: String) {
|
||||
self.key = key
|
||||
self.id = id
|
||||
self.path = path
|
||||
}
|
||||
}
|
||||
|
||||
private final class TempBoxContexts {
|
||||
private var nextId: Int = 0
|
||||
private var contexts: [TempBoxKey: TempBoxFileContext] = [:]
|
||||
|
||||
func file(basePath: String, path: String, fileName: String) -> TempBoxFile {
|
||||
let key = TempBoxKey(path: path, fileName: fileName, uniqueId: nil)
|
||||
let context: TempBoxFileContext
|
||||
if let current = self.contexts[key] {
|
||||
context = current
|
||||
} else {
|
||||
let id = self.nextId
|
||||
self.nextId += 1
|
||||
let dirName = "\(id)"
|
||||
let dirPath = basePath + "/" + dirName
|
||||
var cleanName = fileName
|
||||
if cleanName.hasPrefix("..") {
|
||||
cleanName = "__" + String(cleanName[cleanName.index(cleanName.startIndex, offsetBy: 2)])
|
||||
}
|
||||
cleanName = cleanName.replacingOccurrences(of: "/", with: "_")
|
||||
context = TempBoxFileContext(directory: dirPath, fileName: cleanName)
|
||||
self.contexts[key] = context
|
||||
let _ = try? FileManager.default.createDirectory(atPath: dirPath, withIntermediateDirectories: true, attributes: nil)
|
||||
let _ = try? FileManager.default.linkItem(atPath: path, toPath: context.path)
|
||||
}
|
||||
let id = self.nextId
|
||||
self.nextId += 1
|
||||
context.subscribers.insert(id)
|
||||
return TempBoxFile(key: key, id: id, path: context.path)
|
||||
}
|
||||
|
||||
func tempFile(basePath: String, fileName: String) -> TempBoxFile {
|
||||
let id = self.nextId
|
||||
self.nextId += 1
|
||||
|
||||
let key = TempBoxKey(path: nil, fileName: fileName, uniqueId: id)
|
||||
let context: TempBoxFileContext
|
||||
|
||||
let dirName = "\(id)"
|
||||
let dirPath = basePath + "/" + dirName
|
||||
var cleanName = fileName
|
||||
if cleanName.hasPrefix("..") {
|
||||
cleanName = "__" + String(cleanName[cleanName.index(cleanName.startIndex, offsetBy: 2)])
|
||||
}
|
||||
cleanName = cleanName.replacingOccurrences(of: "/", with: "_")
|
||||
context = TempBoxFileContext(directory: dirPath, fileName: cleanName)
|
||||
self.contexts[key] = context
|
||||
let _ = try? FileManager.default.createDirectory(atPath: dirPath, withIntermediateDirectories: true, attributes: nil)
|
||||
|
||||
context.subscribers.insert(id)
|
||||
return TempBoxFile(key: key, id: id, path: context.path)
|
||||
}
|
||||
|
||||
func dispose(_ file: TempBoxFile) -> [String] {
|
||||
if let context = self.contexts[file.key] {
|
||||
context.subscribers.remove(file.id)
|
||||
if context.subscribers.isEmpty {
|
||||
self.contexts.removeValue(forKey: file.key)
|
||||
return [context.directory]
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
private var sharedValue: TempBox?
|
||||
|
||||
public final class TempBox {
|
||||
private let basePath: String
|
||||
private let processType: String
|
||||
private let launchSpecificId: Int64
|
||||
private let currentBasePath: String
|
||||
|
||||
private let contexts = Atomic<TempBoxContexts>(value: TempBoxContexts())
|
||||
|
||||
public static func initializeShared(basePath: String, processType: String, launchSpecificId: Int64) {
|
||||
sharedValue = TempBox(basePath: basePath, processType: processType, launchSpecificId: launchSpecificId)
|
||||
}
|
||||
|
||||
public static var shared: TempBox {
|
||||
return sharedValue!
|
||||
}
|
||||
|
||||
private init(basePath: String, processType: String, launchSpecificId: Int64) {
|
||||
self.basePath = basePath
|
||||
self.processType = processType
|
||||
self.launchSpecificId = launchSpecificId
|
||||
|
||||
self.currentBasePath = basePath + "/temp/" + processType + "/temp-" + String(UInt64(bitPattern: launchSpecificId), radix: 16)
|
||||
self.cleanupPreviousLaunches(path: basePath + "/temp/" + processType, currentLaunchSpecificId: launchSpecificId)
|
||||
}
|
||||
|
||||
private func cleanupPreviousLaunches(path: String, currentLaunchSpecificId: Int64) {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
let currentName = "temp-" + String(UInt64(bitPattern: currentLaunchSpecificId), radix: 16)
|
||||
if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: path), includingPropertiesForKeys: [], options: []) {
|
||||
for url in files {
|
||||
if url.lastPathComponent.hasPrefix("temp-") && url.lastPathComponent != currentName {
|
||||
let _ = try? FileManager.default.removeItem(atPath: url.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func file(path: String, fileName: String) -> TempBoxFile {
|
||||
return self.contexts.with { contexts in
|
||||
return contexts.file(basePath: self.currentBasePath, path: path, fileName: fileName)
|
||||
}
|
||||
}
|
||||
|
||||
public func tempFile(fileName: String) -> TempBoxFile {
|
||||
return self.contexts.with { contexts in
|
||||
return contexts.tempFile(basePath: self.currentBasePath, fileName: fileName)
|
||||
}
|
||||
}
|
||||
|
||||
public func dispose(_ file: TempBoxFile) {
|
||||
let removePaths = self.contexts.with { contexts in
|
||||
return contexts.dispose(file)
|
||||
}
|
||||
if !removePaths.isEmpty {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
for path in removePaths {
|
||||
let _ = try? FileManager.default.removeItem(atPath: path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user