diff --git a/Telegram/BroadcastUpload/BroadcastUploadExtension.swift b/Telegram/BroadcastUpload/BroadcastUploadExtension.swift index e3149d6dae..b6b002f205 100644 --- a/Telegram/BroadcastUpload/BroadcastUploadExtension.swift +++ b/Telegram/BroadcastUpload/BroadcastUploadExtension.swift @@ -64,7 +64,7 @@ private func rootPathForBasePath(_ appGroupPath: String) -> String { let rootPath = rootPathForBasePath(appGroupUrl.path) - let logsPath = rootPath + "/broadcast-logs" + let logsPath = rootPath + "/logs/broadcast-logs" let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil) let screencastBufferClientContext = IpcGroupCallBufferBroadcastContext(basePath: rootPath + "/broadcast-coordination") diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index a7e6d5c589..5da944461f 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -639,7 +639,7 @@ private final class NotificationServiceHandler { TempBox.initializeShared(basePath: rootPath, processType: "notification", launchSpecificId: Int64.random(in: Int64.min ... Int64.max)) - let logsPath = rootPath + "/notification-logs" + let logsPath = rootPath + "/logs/notification-logs" let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil) setupSharedLogger(rootPath: rootPath, path: logsPath) @@ -699,8 +699,8 @@ private final class NotificationServiceHandler { var isCurrentAccount: Bool = false let loggingSettings = sharedData.entries[SharedDataKeys.loggingSettings]?.get(LoggingSettings.self) ?? LoggingSettings.defaultSettings - Logger.shared.logToFile = loggingSettings.logging.logToFile - Logger.shared.logToConsole = loggingSettings.logging.logToConsole + Logger.shared.logToFile = loggingSettings.logToFile + Logger.shared.logToConsole = loggingSettings.logToConsole if let keyId = notificationPayloadKeyId(data: payloadData) { outer: for listRecord in records.records { @@ -720,8 +720,6 @@ private final class NotificationServiceHandler { let inAppNotificationSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings]?.get(InAppNotificationSettings.self) ?? InAppNotificationSettings.defaultSettings - customSoundPath = inAppNotificationSettings.customSound - let voiceCallSettings: VoiceCallSettings if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings]?.get(VoiceCallSettings.self) { voiceCallSettings = value diff --git a/Telegram/SiriIntents/IntentHandler.swift b/Telegram/SiriIntents/IntentHandler.swift index b9e62875fb..2bbebcf1d5 100644 --- a/Telegram/SiriIntents/IntentHandler.swift +++ b/Telegram/SiriIntents/IntentHandler.swift @@ -113,7 +113,7 @@ class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo TempBox.initializeShared(basePath: rootPath, processType: "siri", launchSpecificId: Int64.random(in: Int64.min ... Int64.max)) - let logsPath = rootPath + "/siri-logs" + let logsPath = rootPath + "/logs/siri-logs" let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil) setupSharedLogger(rootPath: rootPath, path: logsPath) @@ -880,7 +880,7 @@ private final class WidgetIntentHandler { TempBox.initializeShared(basePath: rootPath, processType: "siri", launchSpecificId: Int64.random(in: Int64.min ... Int64.max)) - let logsPath = rootPath + "/siri-logs" + let logsPath = rootPath + "/logs/siri-logs" let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil) setupSharedLogger(rootPath: rootPath, path: logsPath) diff --git a/Telegram/WidgetKitWidget/TodayViewController.swift b/Telegram/WidgetKitWidget/TodayViewController.swift index 059ae8c119..6a852b13ff 100644 --- a/Telegram/WidgetKitWidget/TodayViewController.swift +++ b/Telegram/WidgetKitWidget/TodayViewController.swift @@ -91,7 +91,7 @@ private func getCommonTimeline(friends: [Friend]?, in context: TimelineProviderC TempBox.initializeShared(basePath: rootPath, processType: "widget", launchSpecificId: Int64.random(in: Int64.min ... Int64.max)) - let logsPath = rootPath + "/widget-logs" + let logsPath = rootPath + "/logs/widget-logs" let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil) setupSharedLogger(rootPath: rootPath, path: logsPath) diff --git a/submodules/DebugSettingsUI/Sources/DebugController.swift b/submodules/DebugSettingsUI/Sources/DebugController.swift index 692c372832..3eb015fef5 100644 --- a/submodules/DebugSettingsUI/Sources/DebugController.swift +++ b/submodules/DebugSettingsUI/Sources/DebugController.swift @@ -61,6 +61,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { case sendGroupCallLogs case sendNotificationLogs(PresentationTheme) case sendCriticalLogs(PresentationTheme) + case sendAllLogs case accounts(PresentationTheme) case logToFile(PresentationTheme, Bool) case logToConsole(PresentationTheme, Bool) @@ -102,7 +103,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { switch self { case .testStickerImport: return DebugControllerSection.sticker.rawValue - case .sendLogs, .sendOneLog, .sendShareLogs, .sendGroupCallLogs, .sendNotificationLogs, .sendCriticalLogs: + case .sendLogs, .sendOneLog, .sendShareLogs, .sendGroupCallLogs, .sendNotificationLogs, .sendCriticalLogs, .sendAllLogs: return DebugControllerSection.logs.rawValue case .accounts: return DebugControllerSection.logs.rawValue @@ -137,70 +138,72 @@ private enum DebugControllerEntry: ItemListNodeEntry { return 5 case .sendCriticalLogs: return 6 - case .accounts: + case .sendAllLogs: return 7 - case .logToFile: + case .accounts: return 8 - case .logToConsole: + case .logToFile: return 9 - case .redactSensitiveData: + case .logToConsole: return 10 - case .enableRaiseToSpeak: + case .redactSensitiveData: return 11 - case .keepChatNavigationStack: + case .enableRaiseToSpeak: return 12 - case .skipReadHistory: + case .keepChatNavigationStack: return 13 - case .crashOnSlowQueries: + case .skipReadHistory: return 14 - case .clearTips: + case .crashOnSlowQueries: return 15 - case .crash: + case .clearTips: return 16 - case .resetData: + case .crash: return 17 - case .resetDatabase: + case .resetData: return 18 - case .resetDatabaseAndCache: + case .resetDatabase: return 19 - case .resetHoles: + case .resetDatabaseAndCache: return 20 - case .reindexUnread: + case .resetHoles: return 21 - case .resetBiometricsData: + case .reindexUnread: return 22 - case .resetWebViewCache: + case .resetBiometricsData: return 23 - case .optimizeDatabase: + case .resetWebViewCache: return 24 - case .photoPreview: + case .optimizeDatabase: return 25 - case .knockoutWallpaper: + case .photoPreview: return 26 - case .experimentalCompatibility: + case .knockoutWallpaper: return 27 - case .enableDebugDataDisplay: + case .experimentalCompatibility: return 28 - case .acceleratedStickers: + case .enableDebugDataDisplay: return 29 - case .experimentalBackground: + case .acceleratedStickers: return 30 - case .inlineStickers: + case .experimentalBackground: return 31 - case .localTranscription: + case .inlineStickers: return 32 - case .enableReactionOverrides: + case .localTranscription: return 33 - case .restorePurchases: + case .enableReactionOverrides: return 34 - case .playerEmbedding: + case .restorePurchases: return 35 - case .playlistPlayback: + case .playerEmbedding: return 36 - case .voiceConference: + case .playlistPlayback: return 37 + case .voiceConference: + return 38 case let .preferredVideoCodec(index, _, _, _): - return 38 + index + return 39 + index case .disableVideoAspectScaling: return 100 case .enableVoipTcp: @@ -402,7 +405,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { }) case .sendShareLogs: return ItemListDisclosureItem(presentationData: presentationData, title: "Send Share Logs (Up to 40 MB)", label: "", sectionId: self.section, style: .blocks, action: { - let _ = (Logger.shared.collectLogs(prefix: "/share-logs") + let _ = (Logger.shared.collectLogs(prefix: "/logs/share-logs") |> deliverOnMainQueue).start(next: { logs in let presentationData = arguments.sharedContext.currentPresentationData.with { $0 } let actionSheet = ActionSheetController(presentationData: presentationData) @@ -570,7 +573,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { }) case .sendNotificationLogs: return ItemListDisclosureItem(presentationData: presentationData, title: "Send Notification Logs (Up to 40 MB)", label: "", sectionId: self.section, style: .blocks, action: { - let _ = (Logger(rootPath: arguments.sharedContext.basePath, basePath: arguments.sharedContext.basePath + "/notification-logs").collectLogs() + let _ = (Logger(rootPath: arguments.sharedContext.basePath, basePath: arguments.sharedContext.basePath + "/logs/notification-logs").collectLogs() |> deliverOnMainQueue).start(next: { logs in let presentationData = arguments.sharedContext.currentPresentationData.with { $0 } let actionSheet = ActionSheetController(presentationData: presentationData) @@ -705,6 +708,101 @@ private enum DebugControllerEntry: ItemListNodeEntry { arguments.presentController(actionSheet, nil) }) }) + case .sendAllLogs: + return ItemListDisclosureItem(presentationData: presentationData, title: "Send All Logs", label: "", sectionId: self.section, style: .blocks, action: { + let logTypes: [String] = [ + "app-logs", + "broadcast-logs", + "siri-logs", + "widget-logs", + "notificationcontent-logs", + "notification-logs" + ] + + var logByType: [Signal<(type: String, logs: [(String, String)]), NoError>] = [] + for type in logTypes { + logByType.append(Logger(rootPath: arguments.sharedContext.basePath, basePath: arguments.sharedContext.basePath + "/logs/\(type)").collectLogs() + |> map { result -> (type: String, logs: [(String, String)]) in + return (type, result) + }) + } + + let allLogs = combineLatest(logByType) + + let _ = (allLogs + |> deliverOnMainQueue).start(next: { allLogs in + let presentationData = arguments.sharedContext.currentPresentationData.with { $0 } + let actionSheet = ActionSheetController(presentationData: presentationData) + + var items: [ActionSheetButtonItem] = [] + + if let context = arguments.context, context.sharedContext.applicationBindings.isMainApp { + items.append(ActionSheetButtonItem(title: "Via Telegram", color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + + let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyWriteable, .excludeDisabled])) + controller.peerSelected = { [weak controller] peer in + let peerId = peer.id + + if let strongController = controller { + strongController.dismiss() + + let lineFeed = "\n".data(using: .utf8)! + + var tempSources: [TempBoxFile] = [] + for (type, logItems) in allLogs { + let tempSource = TempBox.shared.tempFile(fileName: "Log-\(type).txt") + + var rawLogData: Data = Data() + for (name, path) in logItems { + if !rawLogData.isEmpty { + rawLogData.append(lineFeed) + rawLogData.append(lineFeed) + } + + rawLogData.append("------ File: \(name) ------\n".data(using: .utf8)!) + + if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) { + rawLogData.append(data) + } + } + + let _ = try? rawLogData.write(to: URL(fileURLWithPath: tempSource.path)) + tempSources.append(tempSource) + } + + let tempZip = TempBox.shared.tempFile(fileName: "destination.zip") + SSZipArchive.createZipFile(atPath: tempZip.path, withFilesAtPaths: tempSources.map(\.path)) + + guard let gzippedData = try? Data(contentsOf: URL(fileURLWithPath: tempZip.path)) else { + return + } + + tempSources.forEach(TempBox.shared.dispose) + TempBox.shared.dispose(tempZip) + + let id = Int64.random(in: Int64.min ... Int64.max) + let fileResource = LocalFileMediaResource(fileId: id, size: Int64(gzippedData.count), isSecretRelated: false) + context.account.postbox.mediaBox.storeResourceData(fileResource.id, data: gzippedData) + + let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: fileResource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/zip", size: Int64(gzippedData.count), attributes: [.FileName(fileName: "Log-iOS-All.txt.zip")]) + let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil) + + let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start() + } + } + arguments.pushController(controller) + })) + } + + actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + }) + ])]) + arguments.presentController(actionSheet, nil) + }) + }) case .accounts: return ItemListDisclosureItem(presentationData: presentationData, title: "Accounts", label: "", sectionId: self.section, style: .blocks, action: { guard let context = arguments.context else { @@ -1083,6 +1181,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present entries.append(.sendGroupCallLogs) entries.append(.sendNotificationLogs(presentationData.theme)) entries.append(.sendCriticalLogs(presentationData.theme)) + entries.append(.sendAllLogs) if isMainApp { entries.append(.accounts(presentationData.theme)) } diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 4d6e67446b..e8bef330e6 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -473,7 +473,19 @@ private func extractAccountManagerState(records: AccountRecordsView