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