good morning!!!!

Skip to content
Snippets Groups Projects
protocol.go 2.52 KiB
Newer Older
a's avatar
rpc
a committed
package jrpc

import (
	"context"
	"encoding/json"
)

type HandlerFunc func(w ResponseWriter, r *Request)

type Handler interface {
	ServeRPC(w ResponseWriter, r *Request)
}

a's avatar
a committed
type ResponseWriter interface {
	Send(v any, err error) error
a's avatar
a committed
	Notify(v any) error
a's avatar
a committed
}

func (fn HandlerFunc) ServeRPC(w ResponseWriter, r *Request) {
	(fn)(w, r)
}

a's avatar
rpc
a committed
type Request struct {
	ctx context.Context
	msg jsonrpcMessage
a's avatar
rpc
a committed
}

a's avatar
a committed
func NewRequest(ctx context.Context, id string, method string, params any) *Request {
	r := &Request{ctx: ctx}
a's avatar
a committed
	pms, _ := jzon.Marshal(params)
a's avatar
a committed
	r.msg = jsonrpcMessage{
a's avatar
a committed
		ID:     NewStringIDPtr(id),
		Method: method,
		Params: pms,
a's avatar
a committed
	}
	return r
}

a's avatar
rpc
a committed
func (r *Request) Method() string {
	return r.msg.Method
}
a's avatar
rpc
a committed
func (r *Request) Params() json.RawMessage {
	return r.msg.Params
}
func (r *Request) ParamSlice() []any {
	var params []any
a's avatar
a committed
	jzon.Unmarshal(r.msg.Params, &params)
	return params
}

a's avatar
a committed
func (r *Request) ParamArray(a ...any) error {
	var params []json.RawMessage
a's avatar
a committed
	jzon.Unmarshal(r.msg.Params, &params)
a's avatar
a committed
	for idx, v := range params {
		if len(v) > idx {
a's avatar
a committed
			err := jzon.Unmarshal(v, &a[idx])
a's avatar
a committed
			if err != nil {
				return err
			}
		} else {
			break
		}
	}
	return nil
}

func (r *Request) ParamInto(v any) error {
a's avatar
a committed
	return jzon.Unmarshal(r.msg.Params, &v)
a's avatar
rpc
a committed
func (r *Request) Context() context.Context {
	return r.ctx
}

func (r *Request) Remote() string {
	return r.peer.RemoteAddr
}

func (r *Request) Peer() PeerInfo {
	return r.peer
}

a's avatar
rpc
a committed
func (r *Request) WithContext(ctx context.Context) *Request {
	if ctx == nil {
		panic("nil context")
	}
	r.ctx = ctx
	r2 := new(Request)
	*r2 = *r
	r2.ctx = ctx
	r2.msg = r.msg
	return r2
}
a's avatar
rpc
a committed
func (r *Request) Msg() jsonrpcMessage {
	return r.msg
}

type ResponseWriterMsg struct {
a's avatar
a committed
	r             *Request
	msg           *jsonrpcMessage
	notifications chan *jsonrpcMessage
a's avatar
rpc
a committed
}

func NewReaderResponseWriterMsg(r *Request) *ResponseWriterMsg {
a's avatar
a committed
	rw := &ResponseWriterMsg{
a's avatar
rpc
a committed
		r: r,
	}
a's avatar
a committed
	switch r.Peer().Transport {
	case "http":
	default:
		rw.notifications = make(chan *jsonrpcMessage, 128)
	}
	return rw
a's avatar
rpc
a committed
}

func (w *ResponseWriterMsg) Send(args any, e error) (err error) {
	cm := w.r.Msg()
	if e != nil {
		w.msg = cm.errorResponse(e)
		return nil
	}
	w.msg = cm.response(args)
a's avatar
a committed
	if w.notifications != nil {
		close(w.notifications)
	}
a's avatar
a committed
	return nil
}

func (w *ResponseWriterMsg) Notify(args any) (err error) {
	if w.notifications == nil {
		return nil
	}
	cm := w.r.Msg()
	nf := cm.response(args)
	nf.ID = nil
	w.notifications <- nf
a's avatar
rpc
a committed
	return nil
}
a's avatar
a committed

func (w *ResponseWriterMsg) Result() *jsonrpcMessage {
	return w.msg
}