Files
damus/damus/Util/LNUrls.swift
Daniel D’Aquino 88f938d11c Bring local notification logic into the push notification target
This commit brings key local notification logic into the notification
extension target to allow the extension to reuse much of the
functionality surrounding the processing and formatting of
notifications. More specifically, the functions
`process_local_notification` and `create_local_notification` were
brought into the extension target.

This will enable us to reuse much of the pre-existing notification logic
(and avoid having to reimplement all of that)

However, those functions had high dependencies on other parts of the
code, so significant refactorings were needed to make this happen:

- `create_local_notification` and `process_local_notification` had its
  function signatures changed to avoid the need to `DamusState` (which
  pulls too many other dependecies)

- Other necessary dependencies, such as `Profiles`, `UserSettingsStore`
  had to be pulled into the extension target. Subsequently,
  sub-dependencies of those items had to be pulled in as well

- In several cases, files were split to avoid pulling too many
  dependencies (e.g. Some Model files depended on some functions in View
  files, so in those cases I moved those functions into their own
  separate file to avoid pulling in view logic into the extension
  target)

- Notification processing logic was changed a bit to remove dependency
  on `EventCache` in favor of using ndb directly (As instructed in a
  TODO comment in EventCache, and because EventCache has too many other
  dependencies)

tldr: A LOT of things were moved around, a bit of logic was changed
around local notifications to avoid using `EventCache`, but otherwise
this commit is meant to be a no-op without any new features or
user-facing functional changes.

Testing
-------

Device: iPhone 15 Pro
iOS: 17.0.1
Damus: This commit
Coverage:

1. Ran unit tests to check for regressions (none detected)

2. Launched the app and navigated around and did some interactions to
   perform a quick functional smoke test (no regressions found)

3. Sent a few push notifications to check they still work as expected (PASS)

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
2024-01-10 11:06:30 -08:00

97 lines
2.3 KiB
Swift

//
// LNUrls.swift
// damus
//
// Created by William Casarin on 2023-01-17.
//
import Foundation
enum LNUrlState {
case not_fetched
case fetching(Task<LNUrlPayRequest?, Never>)
case fetched(LNUrlPayRequest)
case failed(tries: Int)
}
class LNUrls {
var endpoints: [Pubkey: LNUrlState]
init() {
self.endpoints = [:]
}
@MainActor
func lookup_or_fetch(pubkey: Pubkey, lnurl: String) async -> LNUrlPayRequest? {
switch lookup(pubkey: pubkey) {
case .failed(let tries):
print("lnurls.lookup_or_fetch failed \(tries) \(lnurl)")
guard tries < 5 else { return nil }
self.endpoints[pubkey] = .failed(tries: tries + 1)
case .fetched(let pr):
//print("lnurls.lookup_or_fetch fetched \(lnurl)")
return pr
case .fetching(let task):
//print("lnurls.lookup_or_fetch already fetching \(lnurl)")
return await task.value
case .not_fetched:
print("lnurls.lookup_or_fetch not fetched \(lnurl)")
break
}
let task = Task {
let v = await fetch_static_payreq(lnurl)
return v
}
self.endpoints[pubkey] = .fetching(task)
let v = await task.value
if let v {
self.endpoints[pubkey] = .fetched(v)
} else {
self.endpoints[pubkey] = .failed(tries: 1)
}
return v
}
func lookup(pubkey: Pubkey) -> LNUrlState {
return self.endpoints[pubkey] ?? .not_fetched
}
}
func fetch_static_payreq(_ lnurl: String) async -> LNUrlPayRequest? {
print("fetching static payreq \(lnurl)")
guard let url = decode_lnurl(lnurl) else {
return nil
}
guard let ret = try? await URLSession.shared.data(from: url) else {
return nil
}
let json_str = String(decoding: ret.0, as: UTF8.self)
guard let endpoint: LNUrlPayRequest = decode_json(json_str) else {
return nil
}
return endpoint
}
func decode_lnurl(_ lnurl: String) -> URL? {
guard let decoded = try? bech32_decode(lnurl) else {
return nil
}
guard decoded.hrp == "lnurl" else {
return nil
}
guard let url = URL(string: String(decoding: decoded.data, as: UTF8.self)) else {
return nil
}
return url
}