jsonrpc2

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

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

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

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

  1. Создайте сервер JSON-RPC с параметрами:

     1import "neonxp.ru/go/jsonrpc2/rpc"
     2...
     3s := rpc.New(
     4    rpc.WithTransport(&transport.HTTP{
     5        Bind: ":8000",       // Порт для привязки
     6        CORSOrigin: "*",     // Источник CORS
     7        TLS: &tls.Config{},  // Опциональный конфигурационный файл TLS (по умолчанию nil)
     8        Parallel: true,      // Разрешить параллельное выполнение пакетных методов (по умолчанию false)
     9    }),
    10    // Другие параметры, такие как транспорты/средства обработки промежуточного ПО...
    11)
    
  2. Добавьте необходимые транспорты:

    1import "neonxp.ru/go/jsonrpc2/transport"
    2...
    3s.Use(
    4    rpc.WithTransport(&transport.TCP{Bind: ":3000"}),
    5    //...
    6)
    
  3. Напишите обработчики:

    1// Этот обработчик поддерживает параметры запроса
    2func Multiply(ctx context.Context, args *Args) (int, error) {
    3    return args.A * args.B, nil
    4}
    5
    6// Этот обработчик не имеет параметров запроса
    7func Hello(ctx context.Context) (string, error) {
    8    return "Мир", nil
    9}
    

    Обработчик должен иметь контекст в качестве первого параметра и может иметь второй параметр, представляющий параметры запроса (вход любого типа, сериализуемого в JSON). Обработчик всегда возвращает ровно два значения (выход любого типа, сериализуемого в JSON, и ошибку).

  4. Оберните обработчик одной из двух функций rpc.H (с поддержкой параметров запроса) или rpc.HS (без параметров) и зарегистрируйте его на сервере:

    1// обработчик с параметрами
    2s.Register("multiply", rpc.H(Multiply))
    3
    4// обработчик без параметров
    5s.Register("hello", rpc.HS(Hello))
    
  5. Запустите сервер RPC:

    1s.Run(ctx)
    

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

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

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

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

 1package main
 2
 3import (
 4    "context"
 5
 6    "neonxp.ru/go/jsonrpc2/rpc"
 7    "neonxp.ru/go/jsonrpc2/rpc/middleware"
 8    "neonxp.ru/go/jsonrpc2/transport"
 9)
10
11func main() {
12    s := rpc.New(
13        rpc.WithLogger(rpc.StdLogger), // Опциональный логгер
14        rpc.WithTransport(&transport.HTTP{Bind: ":8000"}), // Транспорт HTTP
15    )
16
17    // Установите параметры после конструктора
18    s.Use(
19        rpc.WithTransport(&transport.TCP{Bind: ":3000"}), // Транспорт TCP
20        rpc.WithMiddleware(middleware.Logger(rpc.StdLogger)), // Логгер промежуточного ПО
21    )
22
23    s.Register("multiply", rpc.H(Multiply))
24    s.Register("divide", rpc.H(Divide))
25    s.Register("hello", rpc.HS(Hello))
26
27    s.Run(context.Background())
28}
29
30func Multiply(ctx context.Context, args *Args) (int, error) {
31    //...
32}
33
34func Divide(ctx context.Context, args *Args) (*Quotient, error) {
35    //...
36}
37
38func Hello(ctx context.Context) (string, error) {
39    // ...
40}
41
42type Args struct {
43    A int `json:"a"`
44    B int `json:"b"`
45}
46
47type Quotient struct {
48    Quo int `json:"quo"`
49    Rem int `json:"rem"`
50}