RPC server
License: MIT Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
This commit is contained in:
parent
8417f515a1
commit
3375a72aea
@ -6,4 +6,4 @@ import (
|
||||
|
||||
var Commands = []*cli.Command{
|
||||
versionCmd,
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
var versionCmd = &cli.Command{
|
||||
Name: "version",
|
||||
Name: "version",
|
||||
Usage: "Print version",
|
||||
Action: func(context *cli.Context) error {
|
||||
// TODO: print more useful things
|
||||
|
@ -17,8 +17,8 @@ func main() {
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
Name: "lotus",
|
||||
Usage: "Filecoin decentralized storage network client",
|
||||
Name: "lotus",
|
||||
Usage: "Filecoin decentralized storage network client",
|
||||
Version: build.Version,
|
||||
|
||||
Commands: append(local, lcli.Commands...),
|
||||
|
@ -1,3 +1 @@
|
||||
package daemon
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
var Cmd = &cli.Command{
|
||||
Name: "daemon",
|
||||
Name: "daemon",
|
||||
Usage: "Start a lotus daemon process",
|
||||
Action: func(context *cli.Context) error {
|
||||
return serveRPC()
|
||||
|
@ -1,3 +1 @@
|
||||
package modules
|
||||
|
||||
|
||||
|
@ -1,31 +1,27 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/rpc/v2"
|
||||
"github.com/gorilla/rpc/v2/json"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/build"
|
||||
"github.com/filecoin-project/go-lotus/rpclib"
|
||||
)
|
||||
|
||||
type Filecoin struct {}
|
||||
type Filecoin struct{}
|
||||
|
||||
func (*Filecoin) ServerVersion(r *http.Request, _ *struct{}, out *string) error {
|
||||
*out = build.Version
|
||||
return nil
|
||||
func (*Filecoin) ServerVersion(in int) (string, error) {
|
||||
fmt.Println(in)
|
||||
return build.Version, nil
|
||||
}
|
||||
|
||||
func serveRPC() error {
|
||||
fc := new(Filecoin)
|
||||
|
||||
rpcServer := rpc.NewServer()
|
||||
rpcServer.RegisterCodec(json.NewCodec(), "application/json")
|
||||
if err := rpcServer.RegisterService(fc, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
rpcServer := rpclib.NewServer()
|
||||
|
||||
rpcServer.Register(fc)
|
||||
|
||||
http.Handle("/rpc/v0", rpcServer)
|
||||
return http.ListenAndServe(":1234", http.DefaultServeMux)
|
||||
}
|
||||
|
||||
|
164
rpclib/rpc.go
Normal file
164
rpclib/rpc.go
Normal file
@ -0,0 +1,164 @@
|
||||
package rpclib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"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 {
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (p *param) UnmarshalJSON(raw []byte) error {
|
||||
p.data = make([]byte, len(raw))
|
||||
copy(p.data, raw)
|
||||
return nil
|
||||
}
|
||||
|
||||
type request struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Id *int `json:"id,omitempty"`
|
||||
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"`
|
||||
Result interface{} `json:"result"`
|
||||
Id int `json:"id"`
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
json.NewEncoder(os.Stderr).Encode(resp)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
errOut := -1
|
||||
valOut := -1
|
||||
|
||||
switch funcType.NumOut() {
|
||||
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")
|
||||
}
|
||||
|
||||
s.methods[name+"."+method.Name] = rpcHandler{
|
||||
paramReceivers: recvs,
|
||||
nParams: ins,
|
||||
|
||||
handlerFunc: method.Func,
|
||||
receiver: val,
|
||||
|
||||
errOut: errOut,
|
||||
valOut: valOut,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user