osamingo/jsonrpc

View on GitHub
handler.go

Summary

Maintainability
A
0 mins
Test Coverage
package jsonrpc

import (
    "context"
    "fmt"
    "net/http"

    "github.com/goccy/go-json"
)

// Handler links a method of JSON-RPC request.
type Handler interface {
    ServeJSONRPC(c context.Context, params *json.RawMessage) (result any, err *Error)
}

// HandlerFunc type is an adapter to allow the use of
// ordinary functions as JSONRPC handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// jsonrpc.Handler that calls f.
type HandlerFunc func(c context.Context, params *json.RawMessage) (result any, err *Error)

// ServeJSONRPC calls f(w, r).
func (f HandlerFunc) ServeJSONRPC(c context.Context, params *json.RawMessage) (any, *Error) {
    return f(c, params)
}

// ServeHTTP provides basic JSON-RPC handling.
func (mr *MethodRepository) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    rs, batch, err := ParseRequest(r)
    if err != nil {
        err := SendResponse(w, []*Response{
            {
                Version: Version,
                Error:   err,
            },
        }, false)
        if err != nil {
            fmt.Fprint(w, "Failed to encode error objects")
            w.WriteHeader(http.StatusInternalServerError)
        }

        return
    }

    resp := make([]*Response, len(rs))
    for i := range rs {
        resp[i] = mr.InvokeMethod(r.Context(), rs[i])
    }

    if err := SendResponse(w, resp, batch); err != nil {
        fmt.Fprint(w, "Failed to encode result objects")
        w.WriteHeader(http.StatusInternalServerError)
    }
}

// InvokeMethod invokes JSON-RPC method.
func (mr *MethodRepository) InvokeMethod(c context.Context, r *Request) *Response {
    var md Metadata
    res := NewResponse(r)
    md, res.Error = mr.TakeMethodMetadata(r)
    if res.Error != nil {
        return res
    }

    wrappedContext := WithRequestID(c, r.ID)
    wrappedContext = WithMethodName(wrappedContext, r.Method)
    wrappedContext = WithMetadata(wrappedContext, md)
    res.Result, res.Error = md.Handler.ServeJSONRPC(wrappedContext, r.Params)
    if res.Error != nil {
        res.Result = nil
    }

    return res
}