p2p-swift / Sources / IrdP2PSignaling / Errors.swift
531 words
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
import Foundation
import IrdP2PCrypto

/// Every failure the SDK throws, tagged by kind.
public enum P2PError: Error, Sendable, Equatable {
    /// A misconfiguration detected before any request (blank room, mailbox disabled, ...).
    case config(String)
    /// The network layer failed (DNS, TLS, socket) — `detail` is the underlying description.
    case transport(String)
    /// A request or handshake exceeded its deadline.
    case timeout
    /// A non-2xx HTTP response. `code` is the node's error code when the body was `{"error":"<code>"}`.
    case http(status: Int, code: String?, body: Data?)
    /// The WebSocket upgrade was refused: 403 origin not allowed, 404 unknown app host, 429 too many connections.
    case upgradeRejected(status: Int)
    /// The relay answered with an `error` frame.
    case relay(RelayErrorCode)
    /// A frame would exceed the node's `max_frame_bytes`; sending it would close the connection.
    case frameTooLarge(bytes: Int, limit: Int)
    /// A send was attempted before the room was joined.
    case notJoined
    /// The addressed peer is not a verified member of the room.
    case peerUnknown(PeerId)
    /// The room or session has been closed.
    case closed
    /// A cryptographic operation failed on the local side (never used for remote tampering, which is dropped silently).
    case crypto(String)

    /// The mailbox error code, when this is an HTTP error from the mailbox node.
    public var mailboxCode: MailboxErrorCode? {
        if case .http(_, let code?, _) = self { return MailboxErrorCode(code) }
        return nil
    }
}

/// Error codes of the relay's `{"t":"error","code":...}` frames.
public enum RelayErrorCode: Sendable, Hashable {
    case badMessage, notJoined, tooManyRooms, roomFull, rateLimited
    case other(String)

    public init(_ raw: String) {
        switch raw {
        case "bad-message": self = .badMessage
        case "not-joined": self = .notJoined
        case "too-many-rooms": self = .tooManyRooms
        case "room-full": self = .roomFull
        case "rate-limited": self = .rateLimited
        default: self = .other(raw)
        }
    }

    public var rawValue: String {
        switch self {
        case .badMessage: return "bad-message"
        case .notJoined: return "not-joined"
        case .tooManyRooms: return "too-many-rooms"
        case .roomFull: return "room-full"
        case .rateLimited: return "rate-limited"
        case .other(let s): return s
        }
    }
}

/// Error codes of the mailbox node (`{"error":"<code>"}` bodies).
public enum MailboxErrorCode: Sendable, Hashable {
    case unknownApp, originNotAllowed, notFound, mailboxNotConfigured
    case missingToken, tokenExpired, invalidToken, tokenOutOfScope
    case rateLimited, unreadableBody, emptyBody, badLimit, badCursor
    case messageTooLarge, nodeStorageFull, storageUnavailable, storageError, methodNotAllowed
    case other(String)

    public init(_ raw: String) {
        switch raw {
        case "unknown_app": self = .unknownApp
        case "origin_not_allowed": self = .originNotAllowed
        case "not_found": self = .notFound
        case "mailbox_not_configured": self = .mailboxNotConfigured
        case "missing_token": self = .missingToken
        case "token_expired": self = .tokenExpired
        case "invalid_token": self = .invalidToken
        case "token_out_of_scope": self = .tokenOutOfScope
        case "rate_limited": self = .rateLimited
        case "unreadable_body": self = .unreadableBody
        case "empty_body": self = .emptyBody
        case "bad_limit": self = .badLimit
        case "bad_cursor": self = .badCursor
        case "message_too_large": self = .messageTooLarge
        case "node_storage_full": self = .nodeStorageFull
        case "storage_unavailable": self = .storageUnavailable
        case "storage_error": self = .storageError
        case "method_not_allowed": self = .methodNotAllowed
        default: self = .other(raw)
        }
    }

    /// Whether a later retry can succeed without changing the request.
    public var isRetryable: Bool {
        switch self {
        case .rateLimited, .nodeStorageFull, .storageUnavailable, .storageError: return true
        default: return false
        }
    }

    /// Whether the failure is about the bearer token (re-mint once, then give up).
    public var isAuth: Bool {
        switch self {
        case .missingToken, .tokenExpired, .invalidToken, .tokenOutOfScope: return true
        default: return false
        }
    }
}

static mirror of HEAD · about · clone: git clone https://ird.cod-sursa.ro/p2p-swift.git