mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 02:25:20 +00:00
Refactor parsing inbound messages (#577)
* DRY + helper extension to get data from Message * Flatten guard > do > if > switch + use `try?` * Use failable init instead of a global function
This commit is contained in:
@@ -382,26 +382,12 @@ final class NostrRelayManager: ObservableObject {
|
|||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let message):
|
case .success(let message):
|
||||||
switch message {
|
// Parse off-main to reduce UI jank, then hop back for state updates
|
||||||
case .string(let text):
|
Task.detached(priority: .utility) {
|
||||||
// Parse off-main to reduce UI jank, then hop back for state updates
|
guard let parsed = ParsedInbound(message) else { return }
|
||||||
Task.detached(priority: .utility) {
|
await MainActor.run {
|
||||||
guard let parsed = parseInboundMessage(text) else { return }
|
NostrRelayManager.shared.handleParsedMessage(parsed, from: relayUrl)
|
||||||
await MainActor.run {
|
|
||||||
NostrRelayManager.shared.handleParsedMessage(parsed, from: relayUrl)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case .data(let data):
|
|
||||||
if let text = String(data: data, encoding: .utf8) {
|
|
||||||
Task.detached(priority: .utility) {
|
|
||||||
guard let parsed = parseInboundMessage(text) else { return }
|
|
||||||
await MainActor.run {
|
|
||||||
NostrRelayManager.shared.handleParsedMessage(parsed, from: relayUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@unknown default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue receiving
|
// Continue receiving
|
||||||
@@ -634,42 +620,55 @@ private enum ParsedInbound {
|
|||||||
case ok(eventId: String, success: Bool, reason: String)
|
case ok(eventId: String, success: Bool, reason: String)
|
||||||
case eose(subscriptionId: String)
|
case eose(subscriptionId: String)
|
||||||
case notice(String)
|
case notice(String)
|
||||||
|
|
||||||
|
init?(_ message: URLSessionWebSocketTask.Message) {
|
||||||
|
guard let data = message.data,
|
||||||
|
let array = try? JSONSerialization.jsonObject(with: data) as? [Any],
|
||||||
|
array.count >= 2,
|
||||||
|
let type = array[0] as? String
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case "EVENT":
|
||||||
|
if array.count >= 3,
|
||||||
|
let subId = array[1] as? String,
|
||||||
|
let eventDict = array[2] as? [String: Any],
|
||||||
|
let event = try? NostrEvent(from: eventDict) {
|
||||||
|
self = .event(subId: subId, event: event)
|
||||||
|
}
|
||||||
|
case "EOSE":
|
||||||
|
if let subId = array[1] as? String {
|
||||||
|
self = .eose(subscriptionId: subId)
|
||||||
|
}
|
||||||
|
case "OK":
|
||||||
|
if array.count >= 3,
|
||||||
|
let eventId = array[1] as? String,
|
||||||
|
let success = array[2] as? Bool {
|
||||||
|
let reason = array.count >= 4 ? (array[3] as? String ?? "no reason given") : "no reason given"
|
||||||
|
self = .ok(eventId: eventId, success: success, reason: reason)
|
||||||
|
}
|
||||||
|
case "NOTICE":
|
||||||
|
if array.count >= 2, let msg = array[1] as? String {
|
||||||
|
self = .notice(msg)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Off-main JSON parse to avoid UI jank; pure function, not actor-isolated
|
private extension URLSessionWebSocketTask.Message {
|
||||||
private func parseInboundMessage(_ message: String) -> ParsedInbound? {
|
var data: Data? {
|
||||||
guard let data = message.data(using: .utf8) else { return nil }
|
switch self {
|
||||||
do {
|
case .string(let text): text.data(using: .utf8)
|
||||||
if let array = try JSONSerialization.jsonObject(with: data) as? [Any],
|
case .data(let data): data
|
||||||
array.count >= 2,
|
@unknown default: nil
|
||||||
let type = array[0] as? String {
|
|
||||||
switch type {
|
|
||||||
case "EVENT":
|
|
||||||
if array.count >= 3,
|
|
||||||
let subId = array[1] as? String,
|
|
||||||
let eventDict = array[2] as? [String: Any] {
|
|
||||||
let event = try NostrEvent(from: eventDict)
|
|
||||||
return .event(subId: subId, event: event)
|
|
||||||
}
|
|
||||||
case "EOSE":
|
|
||||||
if let subId = array[1] as? String { return .eose(subscriptionId: subId) }
|
|
||||||
case "OK":
|
|
||||||
if array.count >= 3,
|
|
||||||
let eventId = array[1] as? String,
|
|
||||||
let success = array[2] as? Bool {
|
|
||||||
let reason = array.count >= 4 ? (array[3] as? String ?? "no reason given") : "no reason given"
|
|
||||||
return .ok(eventId: eventId, success: success, reason: reason)
|
|
||||||
}
|
|
||||||
case "NOTICE":
|
|
||||||
if array.count >= 2, let msg = array[1] as? String { return .notice(msg) }
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
// Ignore
|
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Nostr Protocol Types
|
// MARK: - Nostr Protocol Types
|
||||||
|
|||||||
Reference in New Issue
Block a user