JSON-RPC 2.0

Реализация сервера JSON-RPC 2.0 на Go с использованием дженериков.

Требуется версия Go 1.18+
Возможности:

  • Транспорт HTTP/HTTPS
  • Транспорт TCP
  • Транспорт WebSocket

Использование (транспорт HTTP)

  1. Создайте сервер JSON-RPC с параметрами:
    import "neonxp.ru/go/jsonrpc2/rpc"
    ...
    s := rpc.New(
        rpc.WithTransport(&transport.HTTP{
            Bind: ":8000",       // Порт для привязки
            CORSOrigin: "*",     // Источник CORS
            TLS: &tls.Config{},  // Опциональный конфигурационный файл TLS (по умолчанию nil)
            Parallel: true,      // Разрешить параллельное выполнение пакетных методов (по умолчанию false)
        }),
        // Другие параметры, такие как транспорты/средства обработки промежуточного ПО...
    )
    
  2. Добавьте необходимые транспорты:
    import "neonxp.ru/go/jsonrpc2/transport"
    ...
    s.Use(
        rpc.WithTransport(&transport.TCP{Bind: ":3000"}),
        //...
    )
    
  3. Напишите обработчики:
    // Этот обработчик поддерживает параметры запроса
    func Multiply(ctx context.Context, args *Args) (int, error) {
        return args.A * args.B, nil
    }
    
    // Этот обработчик не имеет параметров запроса
    func Hello(ctx context.Context) (string, error) {
        return "Мир", nil
    }
    
    Обработчик должен иметь контекст в качестве первого параметра и может иметь второй параметр, представляющий параметры запроса (вход любого типа, сериализуемого в JSON). Обработчик всегда возвращает ровно два значения (выход любого типа, сериализуемого в JSON, и ошибку).
  4. Оберните обработчик одной из двух функций rpc.H (с поддержкой параметров запроса) или rpc.HS (без параметров) и зарегистрируйте его на сервере:
    // обработчик с параметрами
    s.Register("multiply", rpc.H(Multiply))
    
    // обработчик без параметров
    s.Register("hello", rpc.HS(Hello))
    
  5. Запустите сервер RPC:
    s.Run(ctx)
    

Пользовательский транспорт

Любой транспорт должен реализовывать простой интерфейс transport.Transport:

type Transport interface {
    Run(ctx context.Context, resolver Resolver) error
}

Полный пример

package main

import (
    "context"

    "neonxp.ru/go/jsonrpc2/rpc"
    "neonxp.ru/go/jsonrpc2/rpc/middleware"
    "neonxp.ru/go/jsonrpc2/transport"
)

func main() {
    s := rpc.New(
        rpc.WithLogger(rpc.StdLogger), // Опциональный логгер
        rpc.WithTransport(&transport.HTTP{Bind: ":8000"}), // Транспорт HTTP
    )

    // Установите параметры после конструктора
    s.Use(
        rpc.WithTransport(&transport.TCP{Bind: ":3000"}), // Транспорт TCP
        rpc.WithMiddleware(middleware.Logger(rpc.StdLogger)), // Логгер промежуточного ПО
    )

    s.Register("multiply", rpc.H(Multiply))
    s.Register("divide", rpc.H(Divide))
    s.Register("hello", rpc.HS(Hello))

    s.Run(context.Background())
}

func Multiply(ctx context.Context, args *Args) (int, error) {
    //...
}

func Divide(ctx context.Context, args *Args) (*Quotient, error) {
    //...
}

func Hello(ctx context.Context) (string, error) {
    // ...
}

type Args struct {
    A int `json:"a"`
    B int `json:"b"`
}

type Quotient struct {
    Quo int `json:"quo"`
    Rem int `json:"rem"`
}