mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
RPC work
This commit is contained in:
parent
eccc16237b
commit
bfb36cb9d1
7 changed files with 808 additions and 3 deletions
184
DynamicIsland/services/Extensions/ExtensionRPCMessages.swift
Normal file
184
DynamicIsland/services/Extensions/ExtensionRPCMessages.swift
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Atoll (DynamicIsland)
|
||||
* Copyright (C) 2024-2026 Atoll Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: - JSON-RPC 2.0 Message Types
|
||||
|
||||
/// Incoming JSON-RPC 2.0 request from a client.
|
||||
struct RPCRequest: Codable {
|
||||
let jsonrpc: String
|
||||
let method: String
|
||||
let params: RPCParams?
|
||||
let id: String
|
||||
}
|
||||
|
||||
/// Outgoing JSON-RPC 2.0 success response.
|
||||
struct RPCSuccessResponse: Codable {
|
||||
let jsonrpc: String
|
||||
let result: [String: RPCValue]
|
||||
let id: String
|
||||
|
||||
init(result: [String: RPCValue], id: String) {
|
||||
self.jsonrpc = "2.0"
|
||||
self.result = result
|
||||
self.id = id
|
||||
}
|
||||
}
|
||||
|
||||
/// Outgoing JSON-RPC 2.0 error response.
|
||||
struct RPCErrorResponse: Codable {
|
||||
let jsonrpc: String
|
||||
let error: RPCErrorObject
|
||||
let id: String?
|
||||
|
||||
init(error: RPCErrorObject, id: String?) {
|
||||
self.jsonrpc = "2.0"
|
||||
self.error = error
|
||||
self.id = id
|
||||
}
|
||||
}
|
||||
|
||||
/// JSON-RPC error object.
|
||||
struct RPCErrorObject: Codable {
|
||||
let code: Int
|
||||
let message: String
|
||||
let data: String?
|
||||
|
||||
init(code: Int, message: String, data: String? = nil) {
|
||||
self.code = code
|
||||
self.message = message
|
||||
self.data = data
|
||||
}
|
||||
}
|
||||
|
||||
/// Outgoing JSON-RPC 2.0 notification (server → client, no id).
|
||||
struct RPCNotification: Codable {
|
||||
let jsonrpc: String
|
||||
let method: String
|
||||
let params: [String: RPCValue]
|
||||
|
||||
init(method: String, params: [String: RPCValue]) {
|
||||
self.jsonrpc = "2.0"
|
||||
self.method = method
|
||||
self.params = params
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Standard Error Codes
|
||||
|
||||
enum RPCErrorCode {
|
||||
static let parseError = -32700
|
||||
static let invalidRequest = -32600
|
||||
static let methodNotFound = -32601
|
||||
static let invalidParams = -32602
|
||||
static let internalError = -32603
|
||||
// Application-specific codes
|
||||
static let unauthorized = -32001
|
||||
static let featureDisabled = -32002
|
||||
static let capacityExceeded = -32003
|
||||
static let descriptorInvalid = -32004
|
||||
static let unsupported = -32005
|
||||
}
|
||||
|
||||
// MARK: - Flexible JSON Value
|
||||
|
||||
/// Type-erased JSON value for RPC params and results.
|
||||
enum RPCValue: Codable {
|
||||
case string(String)
|
||||
case int(Int)
|
||||
case double(Double)
|
||||
case bool(Bool)
|
||||
case null
|
||||
case object([String: RPCValue])
|
||||
case array([RPCValue])
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
if container.decodeNil() {
|
||||
self = .null
|
||||
} else if let b = try? container.decode(Bool.self) {
|
||||
self = .bool(b)
|
||||
} else if let i = try? container.decode(Int.self) {
|
||||
self = .int(i)
|
||||
} else if let d = try? container.decode(Double.self) {
|
||||
self = .double(d)
|
||||
} else if let s = try? container.decode(String.self) {
|
||||
self = .string(s)
|
||||
} else if let obj = try? container.decode([String: RPCValue].self) {
|
||||
self = .object(obj)
|
||||
} else if let arr = try? container.decode([RPCValue].self) {
|
||||
self = .array(arr)
|
||||
} else {
|
||||
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Unsupported JSON type")
|
||||
}
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
switch self {
|
||||
case .string(let s): try container.encode(s)
|
||||
case .int(let i): try container.encode(i)
|
||||
case .double(let d): try container.encode(d)
|
||||
case .bool(let b): try container.encode(b)
|
||||
case .null: try container.encodeNil()
|
||||
case .object(let o): try container.encode(o)
|
||||
case .array(let a): try container.encode(a)
|
||||
}
|
||||
}
|
||||
|
||||
var stringValue: String? {
|
||||
if case .string(let s) = self { return s }
|
||||
return nil
|
||||
}
|
||||
var boolValue: Bool? {
|
||||
if case .bool(let b) = self { return b }
|
||||
return nil
|
||||
}
|
||||
var objectValue: [String: RPCValue]? {
|
||||
if case .object(let o) = self { return o }
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Flexible Params
|
||||
|
||||
/// JSON-RPC params can be an object or individual values.
|
||||
struct RPCParams: Codable {
|
||||
let values: [String: RPCValue]
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
self.values = try container.decode([String: RPCValue].self)
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(values)
|
||||
}
|
||||
|
||||
subscript(key: String) -> RPCValue? {
|
||||
values[key]
|
||||
}
|
||||
|
||||
/// Extract a JSON sub-object as raw Data for use with JSONDecoder.
|
||||
func jsonData(for key: String) -> Data? {
|
||||
guard let value = values[key] else { return nil }
|
||||
return try? JSONEncoder().encode(value)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue