damus

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

NostrResponse.swift (3690B)


      1 //
      2 //  NostrResponse.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2022-04-11.
      6 //
      7 
      8 import Foundation
      9 
     10 struct CommandResult {
     11     let event_id: NoteId
     12     let ok: Bool
     13     let msg: String
     14 }
     15 
     16 enum MaybeResponse {
     17     case bad
     18     case ok(NostrResponse)
     19 }
     20 
     21 enum NostrResponse {
     22     case event(String, NostrEvent)
     23     case notice(String)
     24     case eose(String)
     25     case ok(CommandResult)
     26     /// An [NIP-42](https://github.com/nostr-protocol/nips/blob/master/42.md) `auth` challenge.
     27     ///
     28     /// The associated type of this case is the challenge string sent by the server.
     29     case auth(String)
     30 
     31     var subid: String? {
     32         switch self {
     33         case .ok:
     34             return nil
     35         case .event(let sub_id, _):
     36             return sub_id
     37         case .eose(let sub_id):
     38             return sub_id
     39         case .notice:
     40             return nil
     41         case .auth(let challenge_string):
     42             return challenge_string
     43         }
     44     }
     45 
     46     static func owned_from_json(json: String) -> NostrResponse? {
     47         return json.withCString{ cstr in
     48             let bufsize: Int = max(Int(Double(json.utf8.count) * 4.0), Int(getpagesize()))
     49             let data = malloc(bufsize)
     50 
     51             if data == nil {
     52                 let r: NostrResponse? = nil
     53                 return r
     54             }
     55             //guard var json_cstr = json.cString(using: .utf8) else { return nil }
     56 
     57             //json_cs
     58             var tce = ndb_tce()
     59 
     60             let len = ndb_ws_event_from_json(cstr, Int32(json.utf8.count), &tce, data, Int32(bufsize), nil)
     61             if len <= 0 {
     62                 free(data)
     63                 return nil
     64             }
     65 
     66             switch tce.evtype {
     67             case NDB_TCE_OK:
     68                 defer { free(data) }
     69 
     70                 guard let evid_str = sized_cstr(cstr: tce.subid, len: tce.subid_len),
     71                       let evid = hex_decode_noteid(evid_str),
     72                       let msg  = sized_cstr(cstr: tce.command_result.msg, len: tce.command_result.msglen) else {
     73                     return nil
     74                 }
     75                 let cr = CommandResult(event_id: evid, ok: tce.command_result.ok == 1, msg: msg)
     76 
     77                 return .ok(cr)
     78             case NDB_TCE_EOSE:
     79                 defer { free(data) }
     80 
     81                 guard let subid = sized_cstr(cstr: tce.subid, len: tce.subid_len) else {
     82                     return nil
     83                 }
     84                 return .eose(subid)
     85             case NDB_TCE_EVENT:
     86 
     87                 // Create new Data with just the valid bytes
     88                 guard let note_data = realloc(data, Int(len)) else {
     89                     free(data)
     90                     return nil
     91                 }
     92                 let new_note = note_data.assumingMemoryBound(to: ndb_note.self)
     93                 let note = NdbNote(note: new_note, size: Int(len), owned: true, key: nil)
     94 
     95                 guard let subid = sized_cstr(cstr: tce.subid, len: tce.subid_len) else {
     96                     free(data)
     97                     return nil
     98                 }
     99                 return .event(subid, note)
    100             case NDB_TCE_NOTICE:
    101                 free(data)
    102                 return .notice("")
    103             case NDB_TCE_AUTH:
    104                 defer { free(data) }
    105 
    106                 guard let challenge_string = sized_cstr(cstr: tce.subid, len: tce.subid_len) else {
    107                     return nil
    108                 }
    109                 return .auth(challenge_string)
    110             default:
    111                 free(data)
    112                 return nil
    113             }
    114         }
    115     }
    116 }
    117 
    118 func sized_cstr(cstr: UnsafePointer<CChar>, len: Int32) -> String? {
    119     let msgbuf = Data(bytes: cstr, count: Int(len))
    120     return String(data: msgbuf, encoding: .utf8)
    121 }
    122