damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit b148fb735e597397b7bb1dbb5a2480d7ba929a2c
parent 0a9bcb6189251e1f0a27f3378c318a9e40d59923
Author: Daniel D’Aquino <daniel@daquino.me>
Date:   Fri, 17 May 2024 16:20:41 -0700

Move device token sending logic to its own component

This commit moves the device token logic to a new
PushNotificationClient, to move complexity from this specific feature
away from damusApp.swift

This commit also slightly improves the handling of device tokens, by
caching it on the client struct even if the user is using local
notifications, so that the device token can be sent to the server immediately after
switching to push notifications mode.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Mdamus/ContentView.swift | 2+-
Mdamus/Models/DamusState.swift | 2++
Adamus/Models/PushNotificationClient.swift | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdamus/damusApp.swift | 48++++--------------------------------------------
5 files changed, 73 insertions(+), 45 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -615,6 +615,7 @@ D7CE1B472B0BE719002EDAD4 /* NativeObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C32B9462A9AD44700DC3548 /* NativeObject.swift */; }; D7CE1B482B0BE719002EDAD4 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C32B93D2A9AD44700DC3548 /* Message.swift */; }; D7CE1B492B0BE729002EDAD4 /* DisplayName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9BB83029C0ED4F00FC4E37 /* DisplayName.swift */; }; + D7D2A3812BF815D000E4B42B /* PushNotificationClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D2A3802BF815D000E4B42B /* PushNotificationClient.swift */; }; D7DBD41F2B02F15E002A6197 /* NostrKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BEFD32819DE8F00B3DE84 /* NostrKind.swift */; }; D7DEEF2F2A8C021E00E0C99F /* NostrEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DEEF2E2A8C021E00E0C99F /* NostrEventTests.swift */; }; D7EDED152B11776B0018B19C /* LibreTranslateServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */; }; @@ -1437,6 +1438,7 @@ D7CB5D5E2B11770C00AD4105 /* FollowState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowState.swift; sourceTree = "<group>"; }; D7CBD1D32B8D21DC00BFD889 /* DamusPurpleNotificationManagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleNotificationManagement.swift; sourceTree = "<group>"; }; D7CBD1D52B8D509800BFD889 /* DamusPurpleImpendingExpirationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleImpendingExpirationTests.swift; sourceTree = "<group>"; }; + D7D2A3802BF815D000E4B42B /* PushNotificationClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotificationClient.swift; sourceTree = "<group>"; }; D7DEEF2E2A8C021E00E0C99F /* NostrEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrEventTests.swift; sourceTree = "<group>"; }; D7EDED1B2B1178FE0018B19C /* NoteContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteContent.swift; sourceTree = "<group>"; }; D7EDED1D2B11797D0018B19C /* LongformEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongformEvent.swift; sourceTree = "<group>"; }; @@ -1663,6 +1665,7 @@ D74AAFC12B153395006CF0F4 /* HeadlessDamusState.swift */, B5C60C1F2B530D5100C5ECA7 /* MuteItem.swift */, B533694D2B66D791008A805E /* MutelistManager.swift */, + D7D2A3802BF815D000E4B42B /* PushNotificationClient.swift */, ); path = Models; sourceTree = "<group>"; @@ -3291,6 +3294,7 @@ 5CF2DCCC2AA3AF0B00984B8D /* RelayPicView.swift in Sources */, 4C687C242A5FA86D0092C550 /* SearchHeaderView.swift in Sources */, 64FBD06F296255C400D9D3B2 /* Theme.swift in Sources */, + D7D2A3812BF815D000E4B42B /* PushNotificationClient.swift in Sources */, 4C1A9A2329DDDB8100516EAC /* IconLabel.swift in Sources */, 4CA352AC2A76C07F003BB08B /* NewUnmutesNotify.swift in Sources */, 4C3EA64928FF597700C48A62 /* bech32.c in Sources */, diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -308,7 +308,7 @@ struct ContentView: View { active_sheet = .onboardingSuggestions hasSeenOnboardingSuggestions = true } - self.appDelegate?.settings = damus_state?.settings + self.appDelegate?.state = damus_state } .sheet(item: $active_sheet) { item in switch item { diff --git a/damus/Models/DamusState.swift b/damus/Models/DamusState.swift @@ -36,6 +36,7 @@ class DamusState: HeadlessDamusState { let video: VideoController let ndb: Ndb var purple: DamusPurple + var push_notification_client: PushNotificationClient init(pool: RelayPool, keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, postbox: PostBox, bootstrap_relays: [RelayURL], replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: VideoController, ndb: Ndb, purple: DamusPurple? = nil, quote_reposts: EventCounter) { self.pool = pool @@ -68,6 +69,7 @@ class DamusState: HeadlessDamusState { keypair: keypair ) self.quote_reposts = quote_reposts + self.push_notification_client = PushNotificationClient(keypair: keypair, settings: settings) } @discardableResult diff --git a/damus/Models/PushNotificationClient.swift b/damus/Models/PushNotificationClient.swift @@ -0,0 +1,62 @@ +// +// PushNotificationClient.swift +// damus +// +// Created by Daniel D’Aquino on 2024-05-17. +// + +import Foundation + +struct PushNotificationClient { + let keypair: Keypair + let settings: UserSettingsStore + private(set) var device_token: Data? = nil + + mutating func set_device_token(new_device_token: Data) async throws { + self.device_token = new_device_token + if settings.enable_experimental_push_notifications && settings.notifications_mode == .push { + try await self.send_token() + } + } + + func send_token() async throws { + guard let device_token else { return } + // Send the device token and pubkey to the server + let token = device_token.map { String(format: "%02.2hhx", $0) }.joined() + + Log.info("Sending device token to server: %s", for: .push_notifications, token) + + let pubkey = self.keypair.pubkey + + // Send those as JSON to the server + let json: [String: Any] = ["deviceToken": token, "pubkey": pubkey.hex()] + + // create post request + let url = self.settings.send_device_token_to_localhost ? Constants.DEVICE_TOKEN_RECEIVER_TEST_URL : Constants.DEVICE_TOKEN_RECEIVER_PRODUCTION_URL + var request = URLRequest(url: url) + request.httpMethod = "POST" + + // insert json data to the request + request.httpBody = try? JSONSerialization.data(withJSONObject: json, options: []) + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + let task = URLSession.shared.dataTask(with: request) { data, response, error in + guard let data = data, error == nil else { + print(error?.localizedDescription ?? "No data") + return + } + + if let response = response as? HTTPURLResponse, !(200...299).contains(response.statusCode) { + print("Unexpected status code: \(response.statusCode)") + return + } + + let responseJSON = try? JSONSerialization.jsonObject(with: data, options: []) + if let responseJSON = responseJSON as? [String: Any] { + print(responseJSON) + } + } + + task.resume() + } +} diff --git a/damus/damusApp.swift b/damus/damusApp.swift @@ -54,14 +54,12 @@ struct MainView: View { .onAppear { orientationTracker.setDeviceMajorAxis() keypair = get_saved_keypair() - appDelegate.keypair = keypair } } } class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate { - var keypair: Keypair? = nil - var settings: UserSettingsStore? = nil + var state: DamusState? = nil func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { UNUserNotificationCenter.current().delegate = self @@ -71,51 +69,13 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { - // Return if this feature is disabled - guard let settings = self.settings else { return } - if !settings.enable_experimental_push_notifications || settings.notifications_mode == .local { + guard let state else { return } - // Send the device token and pubkey to the server - let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() - - print("Received device token: \(token)") - - guard let pubkey = keypair?.pubkey else { - return - } - - // Send those as JSON to the server - let json: [String: Any] = ["deviceToken": token, "pubkey": pubkey.hex()] - - // create post request - let url = settings.send_device_token_to_localhost ? Constants.DEVICE_TOKEN_RECEIVER_TEST_URL : Constants.DEVICE_TOKEN_RECEIVER_PRODUCTION_URL - var request = URLRequest(url: url) - request.httpMethod = "POST" - - // insert json data to the request - request.httpBody = try? JSONSerialization.data(withJSONObject: json, options: []) - request.setValue("application/json", forHTTPHeaderField: "Content-Type") - - let task = URLSession.shared.dataTask(with: request) { data, response, error in - guard let data = data, error == nil else { - print(error?.localizedDescription ?? "No data") - return - } - - if let response = response as? HTTPURLResponse, !(200...299).contains(response.statusCode) { - print("Unexpected status code: \(response.statusCode)") - return - } - - let responseJSON = try? JSONSerialization.jsonObject(with: data, options: []) - if let responseJSON = responseJSON as? [String: Any] { - print(responseJSON) - } + Task { + try await state.push_notification_client.set_device_token(new_device_token: deviceToken) } - - task.resume() } // Handle the notification in the foreground state