Skip to content

Commit

Permalink
openrpc generation
Browse files Browse the repository at this point in the history
  • Loading branch information
xlc committed Nov 29, 2024
1 parent 72324d7 commit 87a4e24
Show file tree
Hide file tree
Showing 13 changed files with 515 additions and 76 deletions.
6 changes: 3 additions & 3 deletions RPC/Sources/RPC/Handlers/AllHandlers.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
enum AllHandlers {
static let handlers: [any RPCHandler.Type] =
public enum AllHandlers {
public static let handlers: [any RPCHandler.Type] =
ChainHandlers.handlers +
SystemHandlers.handlers +
TelemetryHandlers.handlers +
RPCHandlers.handlers

static func getHandlers(source: ChainDataSource & SystemDataSource & TelemetryDataSource) -> [any RPCHandler] {
public static func getHandlers(source: ChainDataSource & SystemDataSource & TelemetryDataSource) -> [any RPCHandler] {
ChainHandlers.getHandlers(source: source) +
SystemHandlers.getHandlers(source: source) +
TelemetryHandlers.getHandlers(source: source) +
Expand Down
21 changes: 11 additions & 10 deletions RPC/Sources/RPC/Handlers/ChainHandlers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,33 @@ import Blockchain
import Foundation
import Utils

enum ChainHandlers {
static let handlers: [any RPCHandler.Type] = [
public enum ChainHandlers {
public static let handlers: [any RPCHandler.Type] = [
GetBlock.self,
]

static func getHandlers(source: ChainDataSource) -> [any RPCHandler] {
public static func getHandlers(source: ChainDataSource) -> [any RPCHandler] {
[
GetBlock(source: source),
]
}

struct GetBlock: RPCHandler {
typealias Request = Data32?
typealias Response = BlockRef?
typealias DataSource = ChainDataSource
public struct GetBlock: RPCHandler {
public typealias Request = Request1<Data32?>
public typealias Response = BlockRef?
public typealias DataSource = ChainDataSource

static var method: String { "chain_getBlock" }
public static var method: String { "chain_getBlock" }
public static var summary: String? { "Get block by hash. If hash is not provided, returns the best block." }

private let source: ChainDataSource

init(source: ChainDataSource) {
self.source = source
}

func handle(request: Request) async throws -> Response? {
if let hash = request {
public func handle(request: Request) async throws -> Response? {
if let hash = request.value {
try await source.getBlock(hash: hash)
} else {
try await source.getBestBlock()
Expand Down
19 changes: 10 additions & 9 deletions RPC/Sources/RPC/Handlers/RPCHandlers.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import Utils

enum RPCHandlers {
static let handlers: [any RPCHandler.Type] = [
public enum RPCHandlers {
public static let handlers: [any RPCHandler.Type] = [
Methods.self,
]

static func getHandlers(source: [any RPCHandler.Type]) -> [any RPCHandler] {
public static func getHandlers(source: [any RPCHandler.Type]) -> [any RPCHandler] {
[Methods(source: source)]
}

struct Methods: RPCHandler {
typealias Request = VoidRequest
typealias Response = [String]
typealias DataSource = [any RPCHandler.Type]
public struct Methods: RPCHandler {
public typealias Request = VoidRequest
public typealias Response = [String]
public typealias DataSource = [any RPCHandler.Type]

static var method: String { "rpc_methods" }
public static var method: String { "rpc_methods" }
public static var summary: String? { "Returns a list of available RPC methods." }

private let methods: [String]

init(source: [any RPCHandler.Type]) {
methods = source.map { h in h.method }
}

func handle(request _: Request) async throws -> Response? {
public func handle(request _: Request) async throws -> Response? {
methods
}
}
Expand Down
40 changes: 27 additions & 13 deletions RPC/Sources/RPC/Handlers/SystemHandlers.swift
Original file line number Diff line number Diff line change
@@ -1,36 +1,50 @@
import Utils

enum SystemHandlers {
static let handlers: [any RPCHandler.Type] = [
public enum SystemHandlers {
public static let handlers: [any RPCHandler.Type] = [
Health.self,
Version.self,
]

static func getHandlers(source _: SystemDataSource) -> [any RPCHandler] {
public static func getHandlers(source _: SystemDataSource) -> [any RPCHandler] {
[
Health(),
Version(),
]
}

struct Health: RPCHandler {
typealias Request = VoidRequest
typealias Response = Bool
public struct Health: RPCHandler {
public typealias Request = VoidRequest
public typealias Response = Bool

static var method: String { "system_health" }
public static var method: String { "system_health" }
public static var summary: String? { "Returns true if the node is healthy." }

func handle(request _: Request) async throws -> Response? {
public func handle(request _: Request) async throws -> Response? {
true
}
}

struct Version: RPCHandler {
typealias Request = VoidRequest
typealias Response = String
public struct Implementation: RPCHandler {
public typealias Request = VoidRequest
public typealias Response = String

static var method: String { "system_version" }
public static var method: String { "system_implementation" }
public static var summary: String? { "Returns the implementation name of the node." }

func handle(request _: Request) async throws -> Response? {
public func handle(request _: Request) async throws -> Response? {
"Boka"
}
}

public struct Version: RPCHandler {
public typealias Request = VoidRequest
public typealias Response = String

public static var method: String { "system_version" }
public static var summary: String? { "Returns the version of the node." }

public func handle(request _: Request) async throws -> Response? {
"0.0.1"
}
}
Expand Down
31 changes: 16 additions & 15 deletions RPC/Sources/RPC/Handlers/TelemetryHandlers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,57 @@ import Blockchain
import Foundation
import Utils

enum TelemetryHandlers {
static let handlers: [any RPCHandler.Type] = [
public enum TelemetryHandlers {
public static let handlers: [any RPCHandler.Type] = [
GetUpdate.self,
Name.self,
]

static func getHandlers(source: TelemetryDataSource & ChainDataSource) -> [any RPCHandler] {
public static func getHandlers(source: TelemetryDataSource & ChainDataSource) -> [any RPCHandler] {
[
GetUpdate(source: source),
Name(source: source),
]
}

struct GetUpdate: RPCHandler {
typealias Request = VoidRequest
typealias Response = [String: String]
public struct GetUpdate: RPCHandler {
public typealias Request = VoidRequest
public typealias Response = [String: String]

static var method: String { "telemetry_getUpdate" }
public static var method: String { "telemetry_getUpdate" }
public static var summary: String? { "Returns the latest telemetry update." }

private let source: TelemetryDataSource & ChainDataSource

init(source: TelemetryDataSource & ChainDataSource) {
self.source = source
}

func handle(request _: Request) async throws -> Response? {
public func handle(request _: Request) async throws -> Response? {
let block = try await source.getBestBlock()
let peerCount = try await source.getPeersCount()
return try await [
"name": source.name(),
return [
"chainHead": block.header.timeslot.description,
"blockHash": block.hash.description,
"peerCount": peerCount.description,
]
}
}

struct Name: RPCHandler {
typealias Request = VoidRequest
typealias Response = String
public struct Name: RPCHandler {
public typealias Request = VoidRequest
public typealias Response = String

static var method: String { "telemetry_name" }
public static var method: String { "telemetry_name" }
public static var summary: String? { "Returns the name of the node." }

private let source: TelemetryDataSource

init(source: TelemetryDataSource) {
self.source = source
}

func handle(request _: Request) async throws -> Response? {
public func handle(request _: Request) async throws -> Response? {
try await source.name()
}
}
Expand Down
18 changes: 9 additions & 9 deletions RPC/Sources/RPC/JSONRPC/FromJSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ enum FromJSONError: Error {
case unexpectedJSON
}

protocol FromJSON {
public protocol FromJSON {
init(from: JSON?) throws
}

enum VoidRequest: FromJSON {
public enum VoidRequest: FromJSON {
case void

init(from _: JSON?) throws {
public init(from _: JSON?) throws {
// ignore
self = .void
}
}

extension Optional: FromJSON where Wrapped: FromJSON {
init(from json: JSON?) throws {
public init(from json: JSON?) throws {
guard let json else {
self = .none
return
Expand All @@ -35,7 +35,7 @@ extension Optional: FromJSON where Wrapped: FromJSON {
}

extension BinaryInteger where Self: FromJSON {
init(from json: JSON?) throws {
public init(from json: JSON?) throws {
guard let json else {
throw FromJSONError.null
}
Expand All @@ -60,7 +60,7 @@ extension UInt64: FromJSON {}
extension UInt: FromJSON {}

extension Data: FromJSON {
init(from json: JSON?) throws {
public init(from json: JSON?) throws {
guard let json else {
throw FromJSONError.null
}
Expand All @@ -73,14 +73,14 @@ extension Data: FromJSON {
}
}

extension Data32: FromJSON {
init(from json: JSON?) throws {
extension FixedSizeData: FromJSON {
public init(from json: JSON?) throws {
guard let json else {
throw FromJSONError.null
}
switch json {
case let .string(str):
self = try Data32(fromHexString: str).unwrap()
self = try FixedSizeData(fromHexString: str).unwrap()
default:
throw FromJSONError.unexpectedJSON
}
Expand Down
28 changes: 14 additions & 14 deletions RPC/Sources/RPC/JSONRPC/JSONRPC.swift
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
import Utils
import Vapor

struct JSONRequest: Content {
let jsonrpc: String
let method: String
let params: JSON?
let id: JSON
public struct JSONRequest: Content {
public let jsonrpc: String
public let method: String
public let params: JSON?
public let id: JSON
}

struct JSONResponse: Content {
let jsonrpc: String
let result: AnyCodable?
let error: JSONError?
let id: JSON?
public struct JSONResponse: Content {
public let jsonrpc: String
public let result: AnyCodable?
public let error: JSONError?
public let id: JSON?

init(id: JSON?, result: (any Encodable)?) {
public init(id: JSON?, result: (any Encodable)?) {
jsonrpc = "2.0"
self.result = result.map(AnyCodable.init)
error = nil
self.id = id
}

init(id: JSON?, error: JSONError) {
public init(id: JSON?, error: JSONError) {
jsonrpc = "2.0"
result = nil
self.error = error
self.id = id
}
}

struct JSONError: Content, Error {
public struct JSONError: Content, Error {
let code: Int
let message: String
}

extension JSONError {
static func methodNotFound(_ method: String) -> JSONError {
public static func methodNotFound(_ method: String) -> JSONError {
JSONError(code: -32601, message: "Method not found: \(method)")
}
}
18 changes: 16 additions & 2 deletions RPC/Sources/RPC/JSONRPC/RPCHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@ import Foundation
import Utils
import Vapor

protocol RPCHandler: Sendable {
associatedtype Request: FromJSON
public protocol RPCHandler: Sendable {
associatedtype Request: RequestParameter
associatedtype Response: Encodable

static var method: String { get }

func handle(request: Request) async throws -> Response?
func handle(jsonRequest: JSONRequest) async throws -> JSONResponse

// for OpenRPC spec generation
static var summary: String? { get }

static var requestType: any RequestParameter.Type { get }
static var responseType: any Encodable.Type { get }
}

extension RPCHandler {
Expand All @@ -21,4 +27,12 @@ extension RPCHandler {
result: res
)
}

public static var requestType: any RequestParameter.Type {
Request.self
}

public static var responseType: any Encodable.Type {
Response.self
}
}
Loading

0 comments on commit 87a4e24

Please sign in to comment.