2019-06-28 09:03:28 +00:00
|
|
|
package rpclib
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"reflect"
|
|
|
|
)
|
|
|
|
|
|
|
|
type rpcHandler struct {
|
|
|
|
paramReceivers []reflect.Type
|
|
|
|
nParams int
|
|
|
|
|
|
|
|
receiver reflect.Value
|
|
|
|
handlerFunc reflect.Value
|
|
|
|
|
|
|
|
errOut int
|
|
|
|
valOut int
|
|
|
|
}
|
|
|
|
|
|
|
|
type RPCServer struct {
|
|
|
|
methods map[string]rpcHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewServer() *RPCServer {
|
|
|
|
return &RPCServer{
|
|
|
|
methods: map[string]rpcHandler{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type param struct {
|
2019-06-28 13:49:34 +00:00
|
|
|
data []byte // from unmarshal
|
|
|
|
|
|
|
|
v reflect.Value // to marshal
|
2019-06-28 09:03:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *param) UnmarshalJSON(raw []byte) error {
|
|
|
|
p.data = make([]byte, len(raw))
|
|
|
|
copy(p.data, raw)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:49:34 +00:00
|
|
|
func (p *param) MarshalJSON() ([]byte, error) {
|
|
|
|
return json.Marshal(p.v.Interface())
|
|
|
|
}
|
|
|
|
|
2019-06-28 09:03:28 +00:00
|
|
|
type request struct {
|
|
|
|
Jsonrpc string `json:"jsonrpc"`
|
2019-06-28 13:49:34 +00:00
|
|
|
Id *int64 `json:"id,omitempty"`
|
2019-06-28 09:03:28 +00:00
|
|
|
Method string `json:"method"`
|
|
|
|
Params []param `json:"params"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type respError struct {
|
|
|
|
Code int `json:"code"`
|
|
|
|
Message string `json:"message"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type response struct {
|
|
|
|
Jsonrpc string `json:"jsonrpc"`
|
2019-06-28 13:49:34 +00:00
|
|
|
Result interface{} `json:"result,omitempty"`
|
|
|
|
Id int64 `json:"id"`
|
2019-06-28 09:03:28 +00:00
|
|
|
Error *respError `json:"error,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RPCServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
var req request
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
handler, ok := s.methods[req.Method]
|
|
|
|
if !ok {
|
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:49:34 +00:00
|
|
|
if len(req.Params) != handler.nParams {
|
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-06-28 09:03:28 +00:00
|
|
|
callParams := make([]reflect.Value, 1+handler.nParams)
|
|
|
|
callParams[0] = handler.receiver
|
|
|
|
for i := 0; i < handler.nParams; i++ {
|
|
|
|
rp := reflect.New(handler.paramReceivers[i])
|
|
|
|
if err := json.NewDecoder(bytes.NewReader(req.Params[i].data)).Decode(rp.Interface()); err != nil {
|
|
|
|
w.WriteHeader(500)
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
callParams[i+1] = reflect.ValueOf(rp.Elem().Interface())
|
|
|
|
}
|
|
|
|
|
|
|
|
callResult := handler.handlerFunc.Call(callParams)
|
|
|
|
if req.Id == nil {
|
|
|
|
return // notification
|
|
|
|
}
|
|
|
|
|
|
|
|
resp := response{
|
|
|
|
Jsonrpc: "2.0",
|
|
|
|
Id: *req.Id,
|
|
|
|
}
|
|
|
|
|
|
|
|
if handler.errOut != -1 {
|
|
|
|
err := callResult[handler.errOut].Interface()
|
|
|
|
if err != nil {
|
|
|
|
resp.Error = &respError{
|
|
|
|
Code: 1,
|
|
|
|
Message: err.(error).Error(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if handler.valOut != -1 {
|
|
|
|
resp.Result = callResult[handler.valOut].Interface()
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:49:34 +00:00
|
|
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
2019-06-28 09:03:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RPCServer) Register(r interface{}) {
|
|
|
|
val := reflect.ValueOf(r)
|
|
|
|
//TODO: expect ptr
|
|
|
|
|
|
|
|
name := val.Type().Elem().Name()
|
|
|
|
|
|
|
|
for i := 0; i < val.NumMethod(); i++ {
|
|
|
|
method := val.Type().Method(i)
|
|
|
|
|
|
|
|
fmt.Println(name + "." + method.Name)
|
|
|
|
|
|
|
|
funcType := method.Func.Type()
|
|
|
|
ins := funcType.NumIn() - 1
|
|
|
|
recvs := make([]reflect.Type, ins)
|
|
|
|
for i := 0; i < ins; i++ {
|
|
|
|
recvs[i] = method.Type.In(i + 1)
|
|
|
|
}
|
|
|
|
|
2019-06-28 13:49:34 +00:00
|
|
|
valOut, errOut, _ := processFuncOut(funcType)
|
2019-06-28 09:03:28 +00:00
|
|
|
|
|
|
|
s.methods[name+"."+method.Name] = rpcHandler{
|
|
|
|
paramReceivers: recvs,
|
|
|
|
nParams: ins,
|
|
|
|
|
|
|
|
handlerFunc: method.Func,
|
|
|
|
receiver: val,
|
|
|
|
|
|
|
|
errOut: errOut,
|
|
|
|
valOut: valOut,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-06-28 13:49:34 +00:00
|
|
|
|
|
|
|
func processFuncOut(funcType reflect.Type) (valOut int, errOut int, n int) {
|
|
|
|
errOut = -1
|
|
|
|
valOut = -1
|
|
|
|
n = funcType.NumOut()
|
|
|
|
|
|
|
|
switch n {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
if funcType.Out(0) == reflect.TypeOf(new(error)).Elem() {
|
|
|
|
errOut = 0
|
|
|
|
} else {
|
|
|
|
valOut = 0
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
valOut = 0
|
|
|
|
errOut = 1
|
|
|
|
if funcType.Out(1) != reflect.TypeOf(new(error)).Elem() {
|
|
|
|
panic("expected error as second return value")
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
panic("too many error values")
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|