Skip to content

Commit db9698b

Browse files
tutman96Nevexo
authored andcommitted
Refactor jsonrpc server into its own package
1 parent b77f82d commit db9698b

File tree

5 files changed

+229
-185
lines changed

5 files changed

+229
-185
lines changed

internal/jsonrpc/rpc_server.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package jsonrpc
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"io"
8+
"reflect"
9+
)
10+
11+
type JSONRPCServer struct {
12+
writer io.Writer
13+
14+
handlers map[string]*RPCHandler
15+
}
16+
17+
func NewJSONRPCServer(writer io.Writer, handlers map[string]*RPCHandler) *JSONRPCServer {
18+
return &JSONRPCServer{
19+
writer: writer,
20+
handlers: handlers,
21+
}
22+
}
23+
24+
func (s *JSONRPCServer) HandleMessage(data []byte) error {
25+
var request JSONRPCRequest
26+
err := json.Unmarshal(data, &request)
27+
if err != nil {
28+
errorResponse := JSONRPCResponse{
29+
JSONRPC: "2.0",
30+
Error: map[string]interface{}{
31+
"code": -32700,
32+
"message": "Parse error",
33+
},
34+
ID: 0,
35+
}
36+
return s.writeResponse(errorResponse)
37+
}
38+
39+
//log.Printf("Received RPC request: Method=%s, Params=%v, ID=%d", request.Method, request.Params, request.ID)
40+
handler, ok := s.handlers[request.Method]
41+
if !ok {
42+
errorResponse := JSONRPCResponse{
43+
JSONRPC: "2.0",
44+
Error: map[string]interface{}{
45+
"code": -32601,
46+
"message": "Method not found",
47+
},
48+
ID: request.ID,
49+
}
50+
return s.writeResponse(errorResponse)
51+
}
52+
53+
result, err := callRPCHandler(handler, request.Params)
54+
if err != nil {
55+
errorResponse := JSONRPCResponse{
56+
JSONRPC: "2.0",
57+
Error: map[string]interface{}{
58+
"code": -32603,
59+
"message": "Internal error",
60+
"data": err.Error(),
61+
},
62+
ID: request.ID,
63+
}
64+
return s.writeResponse(errorResponse)
65+
}
66+
67+
response := JSONRPCResponse{
68+
JSONRPC: "2.0",
69+
Result: result,
70+
ID: request.ID,
71+
}
72+
return s.writeResponse(response)
73+
}
74+
75+
func (s *JSONRPCServer) writeResponse(response JSONRPCResponse) error {
76+
responseBytes, err := json.Marshal(response)
77+
if err != nil {
78+
return err
79+
}
80+
_, err = s.writer.Write(responseBytes)
81+
return err
82+
}
83+
84+
func callRPCHandler(handler *RPCHandler, params map[string]interface{}) (interface{}, error) {
85+
handlerValue := reflect.ValueOf(handler.Func)
86+
handlerType := handlerValue.Type()
87+
88+
if handlerType.Kind() != reflect.Func {
89+
return nil, errors.New("handler is not a function")
90+
}
91+
92+
numParams := handlerType.NumIn()
93+
args := make([]reflect.Value, numParams)
94+
// Get the parameter names from the RPCHandler
95+
paramNames := handler.Params
96+
97+
if len(paramNames) != numParams {
98+
return nil, errors.New("mismatch between handler parameters and defined parameter names")
99+
}
100+
101+
for i := 0; i < numParams; i++ {
102+
paramType := handlerType.In(i)
103+
paramName := paramNames[i]
104+
paramValue, ok := params[paramName]
105+
if !ok {
106+
return nil, errors.New("missing parameter: " + paramName)
107+
}
108+
109+
convertedValue := reflect.ValueOf(paramValue)
110+
if !convertedValue.Type().ConvertibleTo(paramType) {
111+
if paramType.Kind() == reflect.Slice && (convertedValue.Kind() == reflect.Slice || convertedValue.Kind() == reflect.Array) {
112+
newSlice := reflect.MakeSlice(paramType, convertedValue.Len(), convertedValue.Len())
113+
for j := 0; j < convertedValue.Len(); j++ {
114+
elemValue := convertedValue.Index(j)
115+
if elemValue.Kind() == reflect.Interface {
116+
elemValue = elemValue.Elem()
117+
}
118+
if !elemValue.Type().ConvertibleTo(paramType.Elem()) {
119+
// Handle float64 to uint8 conversion
120+
if elemValue.Kind() == reflect.Float64 && paramType.Elem().Kind() == reflect.Uint8 {
121+
intValue := int(elemValue.Float())
122+
if intValue < 0 || intValue > 255 {
123+
return nil, fmt.Errorf("value out of range for uint8: %v", intValue)
124+
}
125+
newSlice.Index(j).SetUint(uint64(intValue))
126+
} else {
127+
fromType := elemValue.Type()
128+
toType := paramType.Elem()
129+
return nil, fmt.Errorf("invalid element type in slice for parameter %s: from %v to %v", paramName, fromType, toType)
130+
}
131+
} else {
132+
newSlice.Index(j).Set(elemValue.Convert(paramType.Elem()))
133+
}
134+
}
135+
args[i] = newSlice
136+
} else if paramType.Kind() == reflect.Struct && convertedValue.Kind() == reflect.Map {
137+
jsonData, err := json.Marshal(convertedValue.Interface())
138+
if err != nil {
139+
return nil, fmt.Errorf("failed to marshal map to JSON: %v", err)
140+
}
141+
142+
newStruct := reflect.New(paramType).Interface()
143+
if err := json.Unmarshal(jsonData, newStruct); err != nil {
144+
return nil, fmt.Errorf("failed to unmarshal JSON into struct: %v", err)
145+
}
146+
args[i] = reflect.ValueOf(newStruct).Elem()
147+
} else {
148+
return nil, fmt.Errorf("invalid parameter type for: %s", paramName)
149+
}
150+
} else {
151+
args[i] = convertedValue.Convert(paramType)
152+
}
153+
}
154+
155+
results := handlerValue.Call(args)
156+
157+
if len(results) == 0 {
158+
return nil, nil
159+
}
160+
161+
if len(results) == 1 {
162+
if results[0].Type().Implements(reflect.TypeOf((*error)(nil)).Elem()) {
163+
if !results[0].IsNil() {
164+
return nil, results[0].Interface().(error)
165+
}
166+
return nil, nil
167+
}
168+
return results[0].Interface(), nil
169+
}
170+
171+
if len(results) == 2 && results[1].Type().Implements(reflect.TypeOf((*error)(nil)).Elem()) {
172+
if !results[1].IsNil() {
173+
return nil, results[1].Interface().(error)
174+
}
175+
return results[0].Interface(), nil
176+
}
177+
178+
return nil, errors.New("unexpected return values from handler")
179+
}

internal/jsonrpc/types.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package jsonrpc
2+
3+
type JSONRPCRequest struct {
4+
JSONRPC string `json:"jsonrpc"`
5+
Method string `json:"method"`
6+
Params map[string]interface{} `json:"params,omitempty"`
7+
ID interface{} `json:"id,omitempty"`
8+
}
9+
10+
type JSONRPCResponse struct {
11+
JSONRPC string `json:"jsonrpc"`
12+
Result interface{} `json:"result,omitempty"`
13+
Error interface{} `json:"error,omitempty"`
14+
ID interface{} `json:"id"`
15+
}
16+
17+
type JSONRPCEvent struct {
18+
JSONRPC string `json:"jsonrpc"`
19+
Method string `json:"method"`
20+
Params interface{} `json:"params,omitempty"`
21+
}
22+
23+
type RPCHandler struct {
24+
Func interface{}
25+
Params []string
26+
}

0 commit comments

Comments
 (0)