This commit is contained in:
Isaac 2026-03-13 09:00:55 +01:00
parent 33d598cbe7
commit 3d3232eedc
13 changed files with 205 additions and 113 deletions

View file

@ -22,14 +22,36 @@ build --strategy=SwiftCompile=worker
#common --registry=https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/ #common --registry=https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/
# SourceKit BSP: Swift indexing features # rules_swift flags migration
common --features=swift.index_while_building # --swiftcopt and --host_swiftcopt are deprecated
common --features=swift.use_global_index_store common --flag_alias=swiftcopt=@build_bazel_rules_swift//swift:copt
common --features=swift.use_global_module_cache common --flag_alias=host_swiftcopt=@build_bazel_rules_swift//swift:exec_copt
common --features=oso_prefix_is_pwd #common --swiftcopt=-whole-module-optimization
#common --host_swiftcopt=-whole-module-optimization
# SourceKit BSP: Index build config (used for background indexing) common --check_visibility=false
# All of the following are Debug/Index setup configs inspired by the default rules_xcodeproj template
common --verbose_failures
common --cache_computed_file_digests=500000
common --action_cache_store_output_metadata
common --experimental_use_cpp_compile_action_args_params_file
common --define=apple.experimental.tree_artifact_outputs=1
common --features=apple.swizzle_absolute_xcttestsourcelocation
common --features=oso_prefix_is_pwd
common --features=relative_ast_path
common --features=swift.cacheable_swiftmodules
common --features=swift.index_while_building
common --features=swift.use_global_module_cache
common --features=swift.emit_swiftsourceinfo
common --nolegacy_important_outputs
build --noworker_sandboxing
build --spawn_strategy=remote,worker,local
# Only for BSP builds
common:index_build --experimental_convenience_symlinks=ignore common:index_build --experimental_convenience_symlinks=ignore
common:index_build --bes_backend= --bes_results_url=
common:index_build --show_result=0 common:index_build --show_result=0
common:index_build --noshow_loading_progress common:index_build --noshow_loading_progress
common:index_build --noshow_progress common:index_build --noshow_progress
@ -37,3 +59,4 @@ common:index_build --noannounce_rc
common:index_build --noshow_timestamps common:index_build --noshow_timestamps
common:index_build --curses=no common:index_build --curses=no
common:index_build --color=no common:index_build --color=no

View file

@ -23,5 +23,7 @@
] ]
} }
}, },
"swift.sourcekit-lsp.serverPath": "${workspaceFolder}/build-input/sourcekit-lsp" "swift.sourcekit-lsp.serverPath": "${workspaceFolder}/build-input/sourcekit-lsp",
"sourcekit-bazel-bsp.rulesAppleName": "build_bazel_rules_apple",
"cmake.sourceDirectory": "/Users/ali/build/telegram/telegram-ios/submodules/rlottie/rlottie/test"
} }

View file

@ -1,5 +1,7 @@
load("@sourcekit_bazel_bsp//rules:setup_sourcekit_bsp.bzl", "setup_sourcekit_bsp") load("@sourcekit_bazel_bsp//rules:setup_sourcekit_bsp.bzl", "setup_sourcekit_bsp")
exports_files(["versions.json"])
setup_sourcekit_bsp( setup_sourcekit_bsp(
name = "setup_sourcekit_bsp", name = "setup_sourcekit_bsp",
bazel_wrapper = "./build-input/bazel-8.4.2-darwin-arm64", bazel_wrapper = "./build-input/bazel-8.4.2-darwin-arm64",
@ -18,17 +20,12 @@ setup_sourcekit_bsp(
"submodules/**/*.cpp", "submodules/**/*.cpp",
], ],
aquery_flags = [ aquery_flags = [
"define=telegramVersion=12.5",
"define=buildNumber=100000",
], ],
index_flags = [ index_flags = [
"config=index_build", "config=index_build",
"define=telegramVersion=12.5",
"define=buildNumber=100000",
], ],
index_build_batch_size = 10, index_build_batch_size = 10,
targets = [ targets = [
"//Telegram:Telegram", "//Telegram:Telegram",
], ],
merge_lsp_config = False,
) )

View file

@ -385,7 +385,8 @@ plist_fragment(
""" """
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>{buildNumber}</string> <string>{buildNumber}</string>
""" """,
defaults = {"buildNumber": "1"},
) )
plist_fragment( plist_fragment(
@ -574,14 +575,23 @@ plist_fragment(
]) ])
) )
plist_fragment( genrule(
name = "VersionInfoPlist", name = "VersionInfoPlist",
extension = "plist", srcs = ["//:versions.json"],
template = outs = ["VersionInfoPlist.plist"],
""" cmd = """
version=$$(python3 -c "import json; print(json.load(open('$(location //:versions.json)'))['app'])")
cat > $@ <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>{telegramVersion}</string> <string>$$version</string>
""" </dict>
</plist>
PLIST
""",
) )
plist_fragment( plist_fragment(

View file

@ -43,14 +43,23 @@ plist_fragment(
""" """
) )
plist_fragment( genrule(
name = "VersionInfoPlist", name = "VersionInfoPlist",
extension = "plist", srcs = ["//:versions.json"],
template = outs = ["VersionInfoPlist.plist"],
""" cmd = """
version=$$(python3 -c "import json; print(json.load(open('$(location //:versions.json)'))['app'])")
cat > $@ <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>{telegramVersion}</string> <string>$$version</string>
""" </dict>
</plist>
PLIST
""",
) )
plist_fragment( plist_fragment(

View file

@ -212,7 +212,6 @@ class BazelCommandLine:
def get_define_arguments(self): def get_define_arguments(self):
return [ return [
'--define=buildNumber={}'.format(self.build_number), '--define=buildNumber={}'.format(self.build_number),
'--define=telegramVersion={}'.format(self.build_environment.app_version)
] ]
def get_project_generation_arguments(self): def get_project_generation_arguments(self):

@ -1 +1 @@
Subproject commit 39cc2529241335d20afcb6700c587d064e7a2870 Subproject commit f6aef7db5b649ffc3b7497ecc83a08ad3ab19559

View file

@ -18,6 +18,8 @@ def _plist_fragment(ctx):
resolved_values = dict() resolved_values = dict()
for key in found_keys: for key in found_keys:
value = ctx.var.get(key, None) value = ctx.var.get(key, None)
if value == None:
value = ctx.attr.defaults.get(key, None)
if value == None: if value == None:
fail("Expected value for --define={} was not found".format(key)) fail("Expected value for --define={} was not found".format(key))
resolved_values[key] = value resolved_values[key] = value
@ -38,6 +40,7 @@ plist_fragment = rule(
attrs = { attrs = {
"extension": attr.string(mandatory = True), "extension": attr.string(mandatory = True),
"template": attr.string(mandatory = True), "template": attr.string(mandatory = True),
"defaults": attr.string_dict(),
}, },
outputs = { outputs = {
"out": "%{name}.%{extension}" "out": "%{name}.%{extension}"

View file

@ -10,12 +10,9 @@ WORKSPACE_ROOT=$(pwd)
BAZEL_CMD="./build-input/bazel-8.4.2-darwin-arm64" BAZEL_CMD="./build-input/bazel-8.4.2-darwin-arm64"
export ADDITIONAL_FLAGS=() export ADDITIONAL_FLAGS=()
TELEGRAM_VERSION=$(python3 -c "import json; print(json.load(open('${WORKSPACE_ROOT}/versions.json'))['app'])")
ADDITIONAL_FLAGS+=("--keep_going") ADDITIONAL_FLAGS+=("--keep_going")
ADDITIONAL_FLAGS+=("--color=yes") ADDITIONAL_FLAGS+=("--color=yes")
ADDITIONAL_FLAGS+=("--define=telegramVersion=${TELEGRAM_VERSION}")
ADDITIONAL_FLAGS+=("--define=buildNumber=100000")
if [ -n "${BAZEL_EXTRA_BUILD_FLAGS:-}" ]; then if [ -n "${BAZEL_EXTRA_BUILD_FLAGS:-}" ]; then
ADDITIONAL_FLAGS+=("${BAZEL_EXTRA_BUILD_FLAGS[@]}") ADDITIONAL_FLAGS+=("${BAZEL_EXTRA_BUILD_FLAGS[@]}")

View file

@ -551,80 +551,94 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
} }
} }
let networkArguments = NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: PresentationCallManagerImpl.voipMaxLayer, voipVersions: PresentationCallManagerImpl.voipVersions(includeExperimental: true, includeReference: false).map { version, supportsVideo -> CallSessionManagerImplementationVersion in let networkArguments = NetworkInitializationArguments(
CallSessionManagerImplementationVersion(version: version, supportsVideo: supportsVideo) apiId: apiId,
}, appData: self.regularDeviceToken.get() apiHash: apiHash,
|> map { token in languagesCategory: languagesCategory,
let tokenEnvironment: String appVersion: appVersion,
#if DEBUG voipMaxLayer: PresentationCallManagerImpl.voipMaxLayer,
tokenEnvironment = "sandbox" voipVersions: PresentationCallManagerImpl.voipVersions(includeExperimental: true, includeReference: false).map { version, supportsVideo -> CallSessionManagerImplementationVersion in
#else CallSessionManagerImplementationVersion(version: version, supportsVideo: supportsVideo)
tokenEnvironment = "production" },
#endif appData: self.regularDeviceToken.get() |> map { token in
let tokenEnvironment: String
let data = buildConfig.bundleData(withAppToken: token, tokenType: "apns", tokenEnvironment: tokenEnvironment, signatureDict: signatureDict) #if DEBUG
if let data = data, let _ = String(data: data, encoding: .utf8) { tokenEnvironment = "sandbox"
} else { #else
Logger.shared.log("data", "can't deserialize") tokenEnvironment = "production"
} #endif
return data
}, externalRequestVerificationStream: self.firebaseRequestVerificationSecretStream.get(), externalRecaptchaRequestVerification: { method, siteKey in
return Signal { subscriber in
let recaptchaClient: Promise<RecaptchaClient>
if let current = self.recaptchaClientsBySiteKey[siteKey] {
recaptchaClient = current
} else {
recaptchaClient = Promise<RecaptchaClient>()
self.recaptchaClientsBySiteKey[siteKey] = recaptchaClient
Recaptcha.fetchClient(withSiteKey: siteKey) { client, error in
Queue.mainQueue().async {
guard let client else {
Logger.shared.log("App \(self.episodeId)", "RecaptchaClient creation error: \(String(describing: error)).")
return
}
recaptchaClient.set(.single(client))
}
}
}
return (recaptchaClient.get() let data = buildConfig.bundleData(withAppToken: token, tokenType: "apns", tokenEnvironment: tokenEnvironment, signatureDict: signatureDict)
|> take(1) if let data = data, let _ = String(data: data, encoding: .utf8) {
|> mapToSignal { recaptchaClient -> Signal<String?, NoError> in } else {
return Signal { subscriber in Logger.shared.log("data", "can't deserialize")
var recaptchaAction: RecaptchaAction? }
switch method { return data
case "signup": },
recaptchaAction = RecaptchaAction.signup externalRequestVerificationStream: self.firebaseRequestVerificationSecretStream.get(),
default: externalRecaptchaRequestVerification: { method, siteKey in
break return Signal<String?, NoError> { subscriber in
} let recaptchaClient: Promise<RecaptchaClient>
if let current = self.recaptchaClientsBySiteKey[siteKey] {
recaptchaClient = current
} else {
recaptchaClient = Promise<RecaptchaClient>()
self.recaptchaClientsBySiteKey[siteKey] = recaptchaClient
guard let recaptchaAction else { Recaptcha.fetchClient(withSiteKey: siteKey) { client, error in
subscriber.putNext(nil) Queue.mainQueue().async {
subscriber.putCompletion() guard let client else {
Logger.shared.log("App \(self.episodeId)", "RecaptchaClient creation error: \(String(describing: error)).")
return EmptyDisposable return
} }
recaptchaClient.execute(withAction: recaptchaAction) { token, error in recaptchaClient.set(.single(client))
if let token {
subscriber.putNext(token)
Logger.shared.log("App \(self.episodeId)", "RecaptchaClient executed successfully")
} else {
subscriber.putNext(nil)
Logger.shared.log("App \(self.episodeId)", "RecaptchaClient execute error: \(String(describing: error))")
} }
subscriber.putCompletion()
}
return ActionDisposable {
} }
} }
|> runOn(Queue.mainQueue())
}).startStandalone(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion) return (recaptchaClient.get()
} |> take(1)
|> runOn(Queue.mainQueue()) |> mapToSignal { recaptchaClient -> Signal<String?, NoError> in
}, autolockDeadine: autolockDeadine, encryptionProvider: OpenSSLEncryptionProvider(), deviceModelName: nil, useBetaFeatures: !buildConfig.isAppStoreBuild, isICloudEnabled: buildConfig.isICloudEnabled) return Signal { subscriber in
var recaptchaAction: RecaptchaAction?
switch method {
case "signup":
recaptchaAction = RecaptchaAction.signup
default:
break
}
guard let recaptchaAction else {
subscriber.putNext(nil)
subscriber.putCompletion()
return EmptyDisposable
}
recaptchaClient.execute(withAction: recaptchaAction) { token, error in
if let token {
subscriber.putNext(token)
Logger.shared.log("App \(self.episodeId)", "RecaptchaClient executed successfully")
} else {
subscriber.putNext(nil)
Logger.shared.log("App \(self.episodeId)", "RecaptchaClient execute error: \(String(describing: error))")
}
subscriber.putCompletion()
}
return ActionDisposable {
}
}
|> runOn(Queue.mainQueue())
}).startStandalone(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion)
}
|> runOn(Queue.mainQueue())
},
autolockDeadine: autolockDeadine,
encryptionProvider: OpenSSLEncryptionProvider(),
deviceModelName: nil,
useBetaFeatures: !buildConfig.isAppStoreBuild,
isICloudEnabled: buildConfig.isICloudEnabled
)
guard let appGroupUrl = maybeAppGroupUrl else { guard let appGroupUrl = maybeAppGroupUrl else {
self.mainWindow?.presentNative(UIAlertController(title: nil, message: "Error 2", preferredStyle: .alert)) self.mainWindow?.presentNative(UIAlertController(title: nil, message: "Error 2", preferredStyle: .alert))

View file

@ -433,6 +433,12 @@ func chatHistoryEntriesForView(
var i = 0 var i = 0
let unreadEntry: ChatHistoryEntry = .UnreadEntry(maxReadIndex, presentationData) let unreadEntry: ChatHistoryEntry = .UnreadEntry(maxReadIndex, presentationData)
for entry in entries { for entry in entries {
if case let .MessageGroupEntry(_, messages, _) = entry {
if !messages.isEmpty && maxReadIndex >= messages[0].0.index {
i += 1
continue
}
}
if entry > unreadEntry { if entry > unreadEntry {
if i != 0 { if i != 0 {
entries.insert(unreadEntry, at: i) entries.insert(unreadEntry, at: i)

View file

@ -65,7 +65,7 @@ func chatHistoryViewForLocation(
let combinedInitialData = ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData) let combinedInitialData = ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData)
if view.isLoading { if view.isLoading || (view.entries.isEmpty && (view.holeEarlier || view.holeLater)) {
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType)) return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
} }
@ -147,7 +147,7 @@ func chatHistoryViewForLocation(
if preloaded { if preloaded {
return .HistoryView(view: view, type: .Generic(type: updateType), scrollPosition: nil, flashIndicators: false, originalScrollPosition: nil, initialData: combinedInitialData, id: location.id) return .HistoryView(view: view, type: .Generic(type: updateType), scrollPosition: nil, flashIndicators: false, originalScrollPosition: nil, initialData: combinedInitialData, id: location.id)
} else { } else {
if view.isLoading { if view.isLoading || (view.entries.isEmpty && (view.holeEarlier || view.holeLater)) {
return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType)) return .Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
} }
var scrollPosition: ChatHistoryViewScrollPosition? var scrollPosition: ChatHistoryViewScrollPosition?
@ -311,7 +311,7 @@ func chatHistoryViewForLocation(
let combinedInitialData = ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData) let combinedInitialData = ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData)
if view.isLoading { if view.isLoading || (view.entries.isEmpty && (view.holeEarlier || view.holeLater)) {
return ChatHistoryViewUpdate.Loading(initialData: combinedInitialData, type: .Generic(type: updateType)) return ChatHistoryViewUpdate.Loading(initialData: combinedInitialData, type: .Generic(type: updateType))
} }
@ -461,7 +461,7 @@ func fetchAndPreloadReplyThreadInfo(context: AccountContext, subject: ReplyThrea
case .Loading: case .Loading:
return nil return nil
case let .HistoryView(view, _, _, _, _, _, _): case let .HistoryView(view, _, _, _, _, _, _):
if view.isLoading { if view.isLoading || (view.entries.isEmpty && (view.holeEarlier || view.holeLater)) {
return nil return nil
} }
return view.entries.isEmpty return view.entries.isEmpty

View file

@ -50,6 +50,8 @@ private struct AccountTasks {
} }
} }
private let backgroundTaskSubmissionDelay: Double = 10.0
private struct PendingMediaUploadKey: Hashable { private struct PendingMediaUploadKey: Hashable {
let accountId: AccountRecordId let accountId: AccountRecordId
let messageId: MessageId let messageId: MessageId
@ -99,7 +101,8 @@ public final class SharedWakeupManager {
private var backgroundProcessingTaskId: String? private var backgroundProcessingTaskId: String?
private var backgroundProcessingTaskLaunched: Bool = false private var backgroundProcessingTaskLaunched: Bool = false
private var backgroundProcessingTaskCancellationRequestedByApp: Bool = false private var backgroundProcessingTaskCancellationRequestedByApp: Bool = false
private var pendingBackgroundProcessingTaskTimer: SwiftSignalKit.Timer?
private var pendingStoryUploadsByKey: [PendingStoryUploadKey: Float] = [:] private var pendingStoryUploadsByKey: [PendingStoryUploadKey: Float] = [:]
private var pendingStoryUploadStatusesByKey: [PendingStoryUploadKey: PendingStoryUploadStatus] = [:] private var pendingStoryUploadStatusesByKey: [PendingStoryUploadKey: PendingStoryUploadStatus] = [:]
private var backgroundStoryProcessingTaskProgressByKey: [PendingStoryUploadKey: Float] = [:] private var backgroundStoryProcessingTaskProgressByKey: [PendingStoryUploadKey: Float] = [:]
@ -107,7 +110,8 @@ public final class SharedWakeupManager {
private var backgroundStoryProcessingTaskId: String? private var backgroundStoryProcessingTaskId: String?
private var backgroundStoryProcessingTaskLaunched: Bool = false private var backgroundStoryProcessingTaskLaunched: Bool = false
private var backgroundStoryProcessingTaskCancellationRequestedByApp: Bool = false private var backgroundStoryProcessingTaskCancellationRequestedByApp: Bool = false
private var pendingBackgroundStoryProcessingTaskTimer: SwiftSignalKit.Timer?
public init(beginBackgroundTask: @escaping (String, @escaping () -> Void) -> UIBackgroundTaskIdentifier?, endBackgroundTask: @escaping (UIBackgroundTaskIdentifier) -> Void, backgroundTimeRemaining: @escaping () -> Double, acquireIdleExtension: @escaping () -> Disposable?, activeAccounts: Signal<(primary: Account?, accounts: [(AccountRecordId, Account)]), NoError>, liveLocationPolling: Signal<AccountRecordId?, NoError>, watchTasks: Signal<AccountRecordId?, NoError>, inForeground: Signal<Bool, NoError>, hasActiveAudioSession: Signal<Bool, NoError>, notificationManager: SharedNotificationManager?, mediaManager: MediaManager, callManager: PresentationCallManager?, accountUserInterfaceInUse: @escaping (AccountRecordId) -> Signal<Bool, NoError>, presentationData: @escaping () -> PresentationData?) { public init(beginBackgroundTask: @escaping (String, @escaping () -> Void) -> UIBackgroundTaskIdentifier?, endBackgroundTask: @escaping (UIBackgroundTaskIdentifier) -> Void, backgroundTimeRemaining: @escaping () -> Double, acquireIdleExtension: @escaping () -> Disposable?, activeAccounts: Signal<(primary: Account?, accounts: [(AccountRecordId, Account)]), NoError>, liveLocationPolling: Signal<AccountRecordId?, NoError>, watchTasks: Signal<AccountRecordId?, NoError>, inForeground: Signal<Bool, NoError>, hasActiveAudioSession: Signal<Bool, NoError>, notificationManager: SharedNotificationManager?, mediaManager: MediaManager, callManager: PresentationCallManager?, accountUserInterfaceInUse: @escaping (AccountRecordId) -> Signal<Bool, NoError>, presentationData: @escaping () -> PresentationData?) {
assert(Queue.mainQueue().isCurrent()) assert(Queue.mainQueue().isCurrent())
@ -155,6 +159,10 @@ public final class SharedWakeupManager {
} }
strongSelf.allowBackgroundTimeExtensionDeadlineTimer?.invalidate() strongSelf.allowBackgroundTimeExtensionDeadlineTimer?.invalidate()
strongSelf.allowBackgroundTimeExtensionDeadlineTimer = nil strongSelf.allowBackgroundTimeExtensionDeadlineTimer = nil
strongSelf.pendingBackgroundProcessingTaskTimer?.invalidate()
strongSelf.pendingBackgroundProcessingTaskTimer = nil
strongSelf.pendingBackgroundStoryProcessingTaskTimer?.invalidate()
strongSelf.pendingBackgroundStoryProcessingTaskTimer = nil
} }
strongSelf.updateBackgroundProcessingTaskStateFromPendingMediaUploads() strongSelf.updateBackgroundProcessingTaskStateFromPendingMediaUploads()
strongSelf.updateBackgroundProcessingTaskStateFromPendingStoryUploads() strongSelf.updateBackgroundProcessingTaskStateFromPendingStoryUploads()
@ -356,6 +364,8 @@ public final class SharedWakeupManager {
self.pendingStoryUploadsDisposable?.dispose() self.pendingStoryUploadsDisposable?.dispose()
self.managedPausedInBackgroundPlayer?.dispose() self.managedPausedInBackgroundPlayer?.dispose()
self.keepIdleDisposable?.dispose() self.keepIdleDisposable?.dispose()
self.pendingBackgroundProcessingTaskTimer?.invalidate()
self.pendingBackgroundStoryProcessingTaskTimer?.invalidate()
if let (taskId, _, timer) = self.currentTask { if let (taskId, _, timer) = self.currentTask {
timer.invalidate() timer.invalidate()
self.endBackgroundTask(taskId) self.endBackgroundTask(taskId)
@ -369,19 +379,30 @@ public final class SharedWakeupManager {
let shouldHaveTask = !self.pendingMediaUploadsByKey.isEmpty && !self.inForeground let shouldHaveTask = !self.pendingMediaUploadsByKey.isEmpty && !self.inForeground
let hadTask = self.backgroundProcessingTaskId != nil let hadTask = self.backgroundProcessingTaskId != nil
if shouldHaveTask { if shouldHaveTask {
if !hadTask { if !hadTask && self.pendingBackgroundProcessingTaskTimer == nil {
self.startBackgroundProcessingTaskIfNeeded() let timer = SwiftSignalKit.Timer(timeout: backgroundTaskSubmissionDelay, repeat: false, completion: { [weak self] in
guard let self else {
return
}
self.pendingBackgroundProcessingTaskTimer = nil
self.startBackgroundProcessingTaskIfNeeded()
}, queue: .mainQueue())
self.pendingBackgroundProcessingTaskTimer = timer
timer.start()
} }
} else { } else {
self.pendingBackgroundProcessingTaskTimer?.invalidate()
self.pendingBackgroundProcessingTaskTimer = nil
if let backgroundProcessingTaskId = self.backgroundProcessingTaskId { if let backgroundProcessingTaskId = self.backgroundProcessingTaskId {
if !self.backgroundProcessingTaskCancellationRequestedByApp { if !self.backgroundProcessingTaskCancellationRequestedByApp {
self.backgroundProcessingTaskCancellationRequestedByApp = true self.backgroundProcessingTaskCancellationRequestedByApp = true
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: backgroundProcessingTaskId) BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: backgroundProcessingTaskId)
Logger.shared.log("Wakeup", "Requested BG task cancellation by app: \(backgroundProcessingTaskId)") Logger.shared.log("Wakeup", "Requested BG task cancellation by app: \(backgroundProcessingTaskId)")
} }
if !self.backgroundProcessingTaskLaunched { if !self.backgroundProcessingTaskLaunched {
self.backgroundProcessingTaskId = nil self.backgroundProcessingTaskId = nil
self.backgroundProcessingTaskProgressByKey = [:] self.backgroundProcessingTaskProgressByKey = [:]
@ -399,19 +420,30 @@ public final class SharedWakeupManager {
let shouldHaveTask = !self.pendingStoryUploadStatusesByKey.isEmpty && !self.inForeground let shouldHaveTask = !self.pendingStoryUploadStatusesByKey.isEmpty && !self.inForeground
let hadTask = self.backgroundStoryProcessingTaskId != nil let hadTask = self.backgroundStoryProcessingTaskId != nil
if shouldHaveTask { if shouldHaveTask {
if !hadTask { if !hadTask && self.pendingBackgroundStoryProcessingTaskTimer == nil {
self.startBackgroundStoryProcessingTaskIfNeeded() let timer = SwiftSignalKit.Timer(timeout: backgroundTaskSubmissionDelay, repeat: false, completion: { [weak self] in
guard let self else {
return
}
self.pendingBackgroundStoryProcessingTaskTimer = nil
self.startBackgroundStoryProcessingTaskIfNeeded()
}, queue: .mainQueue())
self.pendingBackgroundStoryProcessingTaskTimer = timer
timer.start()
} }
} else { } else {
self.pendingBackgroundStoryProcessingTaskTimer?.invalidate()
self.pendingBackgroundStoryProcessingTaskTimer = nil
if let backgroundStoryProcessingTaskId = self.backgroundStoryProcessingTaskId { if let backgroundStoryProcessingTaskId = self.backgroundStoryProcessingTaskId {
if !self.backgroundStoryProcessingTaskCancellationRequestedByApp { if !self.backgroundStoryProcessingTaskCancellationRequestedByApp {
self.backgroundStoryProcessingTaskCancellationRequestedByApp = true self.backgroundStoryProcessingTaskCancellationRequestedByApp = true
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: backgroundStoryProcessingTaskId) BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: backgroundStoryProcessingTaskId)
Logger.shared.log("Wakeup", "Requested story BG task cancellation by app: \(backgroundStoryProcessingTaskId)") Logger.shared.log("Wakeup", "Requested story BG task cancellation by app: \(backgroundStoryProcessingTaskId)")
} }
if !self.backgroundStoryProcessingTaskLaunched { if !self.backgroundStoryProcessingTaskLaunched {
self.backgroundStoryProcessingTaskId = nil self.backgroundStoryProcessingTaskId = nil
self.backgroundStoryProcessingTaskProgressByKey = [:] self.backgroundStoryProcessingTaskProgressByKey = [:]