damus

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

LNUrls.swift (2374B)


      1 //
      2 //  LNUrls.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2023-01-17.
      6 //
      7 
      8 import Foundation
      9 
     10 enum LNUrlState {
     11     case not_fetched
     12     case fetching(Task<LNUrlPayRequest?, Never>)
     13     case fetched(LNUrlPayRequest)
     14     case failed(tries: Int)
     15 }
     16 
     17 class LNUrls {
     18     var endpoints: [Pubkey: LNUrlState]
     19 
     20     init() {
     21         self.endpoints = [:]
     22     }
     23 
     24     @MainActor
     25     func lookup_or_fetch(pubkey: Pubkey, lnurl: String) async -> LNUrlPayRequest? {
     26         switch lookup(pubkey: pubkey) {
     27         case .failed(let tries):
     28             print("lnurls.lookup_or_fetch failed \(tries) \(lnurl)")
     29             guard tries < 5 else { return nil }
     30             self.endpoints[pubkey] = .failed(tries: tries + 1)
     31         case .fetched(let pr):
     32             //print("lnurls.lookup_or_fetch fetched \(lnurl)")
     33             return pr
     34         case .fetching(let task):
     35             //print("lnurls.lookup_or_fetch already fetching \(lnurl)")
     36             return await task.value
     37         case .not_fetched:
     38             print("lnurls.lookup_or_fetch not fetched \(lnurl)")
     39             break
     40         }
     41 
     42         let task = Task {
     43             let v = await fetch_static_payreq(lnurl)
     44             return v
     45         }
     46 
     47         self.endpoints[pubkey] = .fetching(task)
     48 
     49         let v = await task.value
     50 
     51         if let v {
     52             self.endpoints[pubkey] = .fetched(v)
     53         } else {
     54             self.endpoints[pubkey] = .failed(tries: 1)
     55         }
     56 
     57         return v
     58     }
     59 
     60     func lookup(pubkey: Pubkey) -> LNUrlState {
     61         return self.endpoints[pubkey] ?? .not_fetched
     62     }
     63 }
     64 
     65 func fetch_static_payreq(_ lnurl: String) async -> LNUrlPayRequest? {
     66     print("fetching static payreq \(lnurl)")
     67 
     68     guard let url = decode_lnurl(lnurl) else {
     69         return nil
     70     }
     71     
     72     guard let ret = try? await URLSession.shared.data(from: url) else {
     73         return nil
     74     }
     75     
     76     let json_str = String(decoding: ret.0, as: UTF8.self)
     77     
     78     guard let endpoint: LNUrlPayRequest = decode_json(json_str) else {
     79         return nil
     80     }
     81     
     82     return endpoint
     83 }
     84 
     85 func decode_lnurl(_ lnurl: String) -> URL? {
     86     guard let decoded = try? bech32_decode(lnurl) else {
     87         return nil
     88     }
     89     guard decoded.hrp == "lnurl" else {
     90         return nil
     91     }
     92     guard let url = URL(string: String(decoding: decoded.data, as: UTF8.self)) else {
     93         return nil
     94     }
     95     return url
     96 }