From c6a93868c720a8e3cb32e8d170917d4ba57c3412 Mon Sep 17 00:00:00 2001 From: Aiden Vigue Date: Mon, 12 Jul 2021 21:14:14 -0400 Subject: [PATCH] start new logging agent --- JellyfinPlayer.xcodeproj/project.pbxproj | 31 +++++++++++++++ .../xcshareddata/swiftpm/Package.resolved | 24 ++++++++++-- JellyfinPlayer/SettingsView.swift | 2 +- Shared/ServerLocator/ServerDiscovery.swift | 2 + Shared/Singleton/LogManager.swift | 38 +++++++++++++++++++ Shared/Singleton/SessionManager.swift | 5 +-- .../ViewModels/ConnectToServerViewModel.swift | 33 +++++++++------- 7 files changed, 113 insertions(+), 22 deletions(-) create mode 100644 Shared/Singleton/LogManager.swift diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index 0243e837..2cdbadef 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -62,6 +62,10 @@ 535870AD2669D8DD00D05A09 /* Typings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535870AC2669D8DD00D05A09 /* Typings.swift */; }; 535BAE9F2649E569005FA86D /* ItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535BAE9E2649E569005FA86D /* ItemView.swift */; }; 535BAEA5264A151C005FA86D /* VideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535BAEA4264A151C005FA86D /* VideoPlayer.swift */; }; + 53649AAD269CFAEA00A2D8B7 /* Puppy in Frameworks */ = {isa = PBXBuildFile; productRef = 53649AAC269CFAEA00A2D8B7 /* Puppy */; }; + 53649AAF269CFAF600A2D8B7 /* Puppy in Frameworks */ = {isa = PBXBuildFile; productRef = 53649AAE269CFAF600A2D8B7 /* Puppy */; }; + 53649AB1269CFB1900A2D8B7 /* LogManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53649AB0269CFB1900A2D8B7 /* LogManager.swift */; }; + 53649AB2269D019100A2D8B7 /* LogManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53649AB0269CFB1900A2D8B7 /* LogManager.swift */; }; 5364F455266CA0DC0026ECBA /* APIExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5364F454266CA0DC0026ECBA /* APIExtensions.swift */; }; 5364F456266CA0DC0026ECBA /* APIExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5364F454266CA0DC0026ECBA /* APIExtensions.swift */; }; 536D3D74267BA8170004248C /* BackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536D3D73267BA8170004248C /* BackgroundManager.swift */; }; @@ -268,6 +272,7 @@ 5362E4C4267D40F0000E2F71 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 5362E4C6267D40F4000E2F71 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 5362E4C8267D40F7000E2F71 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 53649AB0269CFB1900A2D8B7 /* LogManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogManager.swift; sourceTree = ""; }; 5364F454266CA0DC0026ECBA /* APIExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIExtensions.swift; sourceTree = ""; }; 536D3D73267BA8170004248C /* BackgroundManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundManager.swift; sourceTree = ""; }; 536D3D75267BA9BB0004248C /* MainTabViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabViewModel.swift; sourceTree = ""; }; @@ -356,6 +361,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 53649AAF269CFAF600A2D8B7 /* Puppy in Frameworks */, 53EC6E1E267E80AC006DD26A /* Pods_JellyfinPlayer_tvOS.framework in Frameworks */, 53A431BF266B0FFE0016769F /* JellyfinAPI in Frameworks */, 535870912669D7A800D05A09 /* Introspect in Frameworks */, @@ -373,6 +379,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 53649AAD269CFAEA00A2D8B7 /* Puppy in Frameworks */, 62CB3F462685BAF7003D0A6F /* Defaults in Frameworks */, 5338F757263B7E2E0014BF09 /* KeychainSwift in Frameworks */, 53EC6E25267EB10F006DD26A /* SwiftyJSON in Frameworks */, @@ -664,6 +671,7 @@ 62EC352B26766675000E9F2D /* ServerEnvironment.swift */, 62EC352E267666A5000E9F2D /* SessionManager.swift */, 536D3D73267BA8170004248C /* BackgroundManager.swift */, + 53649AB0269CFB1900A2D8B7 /* LogManager.swift */, ); path = Singleton; sourceTree = ""; @@ -715,6 +723,7 @@ 536D3D83267BEA550004248C /* ParallaxView */, 62CB3F472685BB3B003D0A6F /* Defaults */, 53272534268BF9710035FBF1 /* SwiftUIFocusGuide */, + 53649AAE269CFAF600A2D8B7 /* Puppy */, ); productName = "JellyfinPlayer tvOS"; productReference = 535870602669D21600D05A09 /* JellyfinPlayer tvOS.app */; @@ -747,6 +756,7 @@ 625CB5792678C4A400530A6E /* ActivityIndicator */, 53EC6E24267EB10F006DD26A /* SwiftyJSON */, 62CB3F452685BAF7003D0A6F /* Defaults */, + 53649AAC269CFAEA00A2D8B7 /* Puppy */, ); productName = JellyfinPlayer; productReference = 5377CBF1263B596A003A4E83 /* JellyfinPlayer iOS.app */; @@ -817,6 +827,7 @@ 53EC6E23267EB10F006DD26A /* XCRemoteSwiftPackageReference "SwiftyJSON" */, 62CB3F442685BAF7003D0A6F /* XCRemoteSwiftPackageReference "Defaults" */, 53272533268BF9710035FBF1 /* XCRemoteSwiftPackageReference "SwiftUIFocusGuide" */, + 53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */, ); productRefGroup = 5377CBF2263B596A003A4E83 /* Products */; projectDirPath = ""; @@ -1010,6 +1021,7 @@ 62CB3F4C2685BB77003D0A6F /* DefaultsExtension.swift in Sources */, 62E632E4267D3BA60063E547 /* MovieItemViewModel.swift in Sources */, 5358706C2669D21700D05A09 /* PersistenceController.swift in Sources */, + 53649AB2269D019100A2D8B7 /* LogManager.swift in Sources */, 535870AA2669D8AE00D05A09 /* BlurHashDecode.swift in Sources */, 53ABFDE5267974EF00886593 /* ViewModel.swift in Sources */, 531069582684E7EE00CFFDBA /* MediaInfoView.swift in Sources */, @@ -1068,6 +1080,7 @@ 091B5A8B2683142E00D78B61 /* UDPBroadCastConnection.swift in Sources */, 6267B3D626710B8900A7371D /* CollectionExtensions.swift in Sources */, 53A089D0264DA9DA00D57806 /* MovieItemView.swift in Sources */, + 53649AB1269CFB1900A2D8B7 /* LogManager.swift in Sources */, 62E632E9267D3FF50063E547 /* SeasonItemViewModel.swift in Sources */, 625CB56A2678B71200530A6E /* SplashViewModel.swift in Sources */, 62E632F3267D54030063E547 /* DetailItemViewModel.swift in Sources */, @@ -1489,6 +1502,14 @@ minimumVersion = 19.0.0; }; }; + 53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/sushichop/Puppy"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.2.0; + }; + }; 536D3D82267BEA550004248C /* XCRemoteSwiftPackageReference "ParallaxView" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/PGSSoft/ParallaxView"; @@ -1570,6 +1591,16 @@ package = 621C637E26672A30004216EA /* XCRemoteSwiftPackageReference "NukeUI" */; productName = NukeUI; }; + 53649AAC269CFAEA00A2D8B7 /* Puppy */ = { + isa = XCSwiftPackageProductDependency; + package = 53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */; + productName = Puppy; + }; + 53649AAE269CFAF600A2D8B7 /* Puppy */ = { + isa = XCSwiftPackageProductDependency; + package = 53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */; + productName = Puppy; + }; 536D3D7C267BD5F90004248C /* ActivityIndicator */ = { isa = XCSwiftPackageProductDependency; package = 625CB5782678C4A400530A6E /* XCRemoteSwiftPackageReference "ActivityIndicator" */; diff --git a/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved b/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved index b5fac1e0..a423daff 100644 --- a/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -38,7 +38,7 @@ } }, { - "package": "JellyfinAPI", + "package": "jellyfin-sdk-swift", "repositoryURL": "https://github.com/jellyfin/jellyfin-sdk-swift", "state": { "branch": "main", @@ -47,7 +47,7 @@ } }, { - "package": "KeychainSwift", + "package": "keychain-swift", "repositoryURL": "https://github.com/evgenyneu/keychain-swift", "state": { "branch": null, @@ -83,7 +83,25 @@ } }, { - "package": "Introspect", + "package": "Puppy", + "repositoryURL": "https://github.com/sushichop/Puppy", + "state": { + "branch": null, + "revision": "dc82e65c749cee431ffbb8c0913680b61ccd7e08", + "version": "0.2.0" + } + }, + { + "package": "swift-log", + "repositoryURL": "https://github.com/apple/swift-log.git", + "state": { + "branch": null, + "revision": "5d66f7ba25daf4f94100e7022febf3c75e37a6c7", + "version": "1.4.2" + } + }, + { + "package": "SwiftUI-Introspect", "repositoryURL": "https://github.com/siteline/SwiftUI-Introspect", "state": { "branch": null, diff --git a/JellyfinPlayer/SettingsView.swift b/JellyfinPlayer/SettingsView.swift index eb2b4d6b..719514d3 100644 --- a/JellyfinPlayer/SettingsView.swift +++ b/JellyfinPlayer/SettingsView.swift @@ -23,7 +23,7 @@ struct SettingsView: View { @State private var username: String = "" func onAppear() { - username = SessionManager.current.user.username ?? "" + username = SessionManager.current.user?.username ?? "" } var body: some View { diff --git a/Shared/ServerLocator/ServerDiscovery.swift b/Shared/ServerLocator/ServerDiscovery.swift index 04dfec15..911239cd 100644 --- a/Shared/ServerLocator/ServerDiscovery.swift +++ b/Shared/ServerLocator/ServerDiscovery.swift @@ -77,6 +77,7 @@ public class ServerDiscovery { func receiveHandler(_ ipAddress: String, _ port: Int, _ data: Data) { do { let response = try JSONDecoder().decode(ServerLookupResponse.self, from: data) + LogManager.shared.log.debug("Received JellyfinServer from \"\(response.name)\"", tag: "ServerDiscovery") completion(response) } catch { completion(nil) @@ -85,6 +86,7 @@ public class ServerDiscovery { self.broadcastConn.handler = receiveHandler do { try broadcastConn.sendBroadcast("Who is JellyfinServer?") + LogManager.shared.log.debug("Discovery broadcast sent", tag: "ServerDiscovery") } catch { print(error) } diff --git a/Shared/Singleton/LogManager.swift b/Shared/Singleton/LogManager.swift new file mode 100644 index 00000000..146666bc --- /dev/null +++ b/Shared/Singleton/LogManager.swift @@ -0,0 +1,38 @@ +// + /* + * SwiftFin is subject to the terms of the Mozilla Public + * License, v2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * Copyright 2021 Aiden Vigue & Jellyfin Contributors + */ + +import Foundation +import Puppy + +final class LogManager { + static let shared = LogManager() + let log = Puppy() + + init() { + let console = ConsoleLogger("me.vigue.jellyfin.ConsoleLogger") + let fileURL = URL(fileURLWithPath: "./app.log").absoluteURL + let file = try? FileLogger("me.vigue.jellyfin", fileURL: fileURL) + console.format = LogFormatter(); + log.add(console, withLevel: .debug) + if(file != nil) { + file!.format = LogFormatter(); + log.add(file!, withLevel: .debug) + } + } +} + +class LogFormatter: LogFormattable { + func formatMessage(_ level: LogLevel, message: String, tag: String, function: String, + file: String, line: UInt, swiftLogInfo: [String : String], + label: String, date: Date, threadID: UInt64) -> String { + let date = dateFormatter(date) + let file = shortFileName(file) + return "\(date) \(threadID) [\(level.emoji) \(level)] \(file)#L.\(line) \(function) \(message)" + } +} diff --git a/Shared/Singleton/SessionManager.swift b/Shared/Singleton/SessionManager.swift index 8c4e29fc..bfbd0467 100644 --- a/Shared/Singleton/SessionManager.swift +++ b/Shared/Singleton/SessionManager.swift @@ -72,9 +72,7 @@ final class SessionManager { header.append("DeviceId=\"iOS_\(UIDevice.current.identifierForVendor!.uuidString)_\(String(Date().timeIntervalSince1970))\", ") deviceID = "iOS_\(UIDevice.current.identifierForVendor!.uuidString)_\(String(Date().timeIntervalSince1970))" #endif - print("generated device id: \(deviceID)") } else { - print("device id provided: \(devID!)") header.append("DeviceId=\"\(devID!)\", ") deviceID = devID! } @@ -116,7 +114,7 @@ final class SessionManager { func loginWithSavedSession(user: SignedInUser) { let accessToken = getAuthToken(userID: user.user_id!) - print("logging in with saved session") + self.user = user generateAuthHeader(with: accessToken, deviceID: user.device_uuid) @@ -161,7 +159,6 @@ final class SessionManager { func logout() { let nc = NotificationCenter.default nc.post(name: Notification.Name("didSignOut"), object: nil) - dump(user) let keychain = KeychainSwift() keychain.accessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain" keychain.delete("AccessToken_\(user?.user_id ?? "")") diff --git a/Shared/ViewModels/ConnectToServerViewModel.swift b/Shared/ViewModels/ConnectToServerViewModel.swift index 2a62b115..7361d4c0 100644 --- a/Shared/ViewModels/ConnectToServerViewModel.swift +++ b/Shared/ViewModels/ConnectToServerViewModel.swift @@ -37,15 +37,19 @@ final class ConnectToServerViewModel: ViewModel { func getPublicUsers() { if ServerEnvironment.current.server != nil { + LogManager.shared.log.debug("Attempting to read public users from \(ServerEnvironment.current.server.baseURI!)", tag: "getPublicUsers") UserAPI.getPublicUsers() .trackActivity(loading) .sink(receiveCompletion: { completion in self.handleAPIRequestCompletion(completion: completion) }, receiveValue: { response in self.publicUsers = response + LogManager.shared.log.debug("Received \(String(response.count)) public users.", tag: "getPublicUsers") self.isConnectedServer = true }) .store(in: &cancellables) + } else { + LogManager.shared.log.debug("Not getting users - server is nil", tag: "getPublicUsers") } } @@ -60,36 +64,30 @@ final class ConnectToServerViewModel: ViewModel { } func connectToServer() { + LogManager.shared.log.debug("Attempting to connect to server at \"\(uriSubject.value)\"", tag: "connectToServer") ServerEnvironment.current.create(with: uriSubject.value) .trackActivity(loading) .sink(receiveCompletion: { result in switch result { case let .failure(error): - print(error) + let err = error as NSError; + LogManager.shared.log.critical("Error connecting to server at \"\(self.uriSubject.value)\"", tag: "connectToServer") + LogManager.shared.log.critical(err.debugDescription, tag: "login") self.errorMessage = error.localizedDescription + break default: break } }, receiveValue: { _ in + LogManager.shared.log.debug("Connected to server at \"\(self.uriSubject.value)\"", tag: "connectToServer") self.getPublicUsers() }) .store(in: &cancellables) } func connectToServer(at url: URL) { - ServerEnvironment.current.create(with: url.absoluteString) - .trackActivity(loading) - .sink(receiveCompletion: { result in - switch result { - case let .failure(error): - self.errorMessage = error.localizedDescription - default: - break - } - }, receiveValue: { _ in - self.getPublicUsers() - }) - .store(in: &cancellables) + uriSubject.send(url.absoluteString); + self.connectToServer() } func discoverServers() { @@ -109,6 +107,8 @@ final class ConnectToServerViewModel: ViewModel { } func login() { + LogManager.shared.log.debug("Attempting to login to server at \"\(uriSubject.value)\"", tag: "login") + LogManager.shared.log.debug("username == \"\": \(usernameSubject.value.isEmpty), password == \"\": \(passwordSubject.value.isEmpty)", tag: "login") SessionManager.current.login(username: usernameSubject.value, password: passwordSubject.value) .trackActivity(loading) .sink(receiveCompletion: { completion in @@ -119,8 +119,13 @@ final class ConnectToServerViewModel: ViewModel { if let err = error as? ErrorResponse { switch err { case .error(401, _, _, _): + LogManager.shared.log.critical("Error connecting to server at \"\(self.uriSubject.value)\"", tag: "login") + LogManager.shared.log.critical("User provided invalid credentials, server returned a 401 error.", tag: "login") self.errorMessage = "Invalid credentials" case .error: + let err = error as NSError; + LogManager.shared.log.critical("Error logging in to server at \"\(self.uriSubject.value)\"", tag: "login") + LogManager.shared.log.critical(err.debugDescription, tag: "login") self.errorMessage = err.localizedDescription } }