-
Notifications
You must be signed in to change notification settings - Fork 10
/
go-ethereum.go
135 lines (112 loc) · 3.49 KB
/
go-ethereum.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package go_openrpc_reflect
import (
"context"
"go/ast"
"reflect"
"unicode"
meta_schema "github.com/open-rpc/meta-schema"
)
type EthereumReflectorT struct {
StandardReflectorT
}
var EthereumReflector = &EthereumReflectorT{}
func (e *EthereumReflectorT) ReceiverMethods(name string, receiver interface{}) ([]meta_schema.MethodObject, error) {
if e.FnReceiverMethods != nil {
return e.FnReceiverMethods(name, receiver)
}
return receiverMethods(e, name, receiver)
}
var contextType = reflect.TypeOf((*context.Context)(nil)).Elem()
// ------------------------------------------------------------------------------
func (e *EthereumReflectorT) IsMethodEligible(method reflect.Method) bool {
if e.FnIsMethodEligible != nil {
return e.FnIsMethodEligible(method)
}
// Method must be exported.
if !isExportedMethod(method) {
return false
}
// All arg types are permitted.
// If context.Context is the first arg type, it will be skipped.
// Verify return types. The function must return at most one error
// and/or one other non-error value.
outs := make([]reflect.Type, method.Func.Type().NumOut())
for i := 0; i < method.Func.Type().NumOut(); i++ {
outs[i] = method.Func.Type().Out(i)
}
isErrorType := func(ty reflect.Type) bool {
return ty == errType
}
// If an error is returned, it must be the last returned value.
switch {
case len(outs) > 2:
return false
case len(outs) == 1 && isErrorType(outs[0]):
return true
case len(outs) == 2:
if isErrorType(outs[0]) || !isErrorType(outs[1]) {
return false
}
}
return true
}
func firstToLower(str string) string {
ret := []rune(str)
if len(ret) > 0 {
ret[0] = unicode.ToLower(ret[0])
}
return string(ret)
}
func (e *EthereumReflectorT) GetMethodName(moduleName string, r reflect.Value, m reflect.Method, astFunc *ast.FuncDecl) (string, error) {
if e.FnGetMethodName != nil {
return e.FnGetMethodName(moduleName, r, m, astFunc)
}
if moduleName == "" {
ty := r.Type()
if ty.Kind() == reflect.Ptr {
ty = ty.Elem()
}
moduleName = firstToLower(ty.Name())
}
return moduleName + "_" + firstToLower(m.Name), nil
}
func (e *EthereumReflectorT) GetMethodParams(r reflect.Value, m reflect.Method, astFunc *ast.FuncDecl) ([]meta_schema.ContentDescriptorObject, error) {
if e.FnGetMethodParams != nil {
return e.FnGetMethodParams(r, m, astFunc)
}
if astFunc.Type.Params == nil {
return []meta_schema.ContentDescriptorObject{}, nil
}
out := []meta_schema.ContentDescriptorObject{}
expanded := expandedFieldNamesFromList(astFunc.Type.Params.List)
for i, field := range expanded {
ty := m.Type.In(i + 1)
// go-ethereum/rpc skips the first parameter if it is context.Context,
// which is used for subscriptions.
if i+1 == 1 && ty == contextType {
continue
}
cd, err := buildContentDescriptorObject(e, r, m, field, ty)
if err != nil {
return nil, err
}
out = append(out, cd)
}
return out, nil
}
func (e *EthereumReflectorT) GetMethodResult(r reflect.Value, m reflect.Method, astFunc *ast.FuncDecl) (meta_schema.ContentDescriptorObject, error) {
if e.FnGetMethodResult != nil {
return e.FnGetMethodResult(r, m, astFunc)
}
if astFunc.Type.Results == nil {
return nullContentDescriptor, nil
}
expandedFields := expandedFieldNamesFromList(astFunc.Type.Results.List)
if len(expandedFields) == 0 {
return nullContentDescriptor, nil
}
if m.Type.NumOut() == 0 || m.Type.Out(0) == errType {
return nullContentDescriptor, nil
}
return buildContentDescriptorObject(e, r, m, expandedFields[0], m.Type.Out(0))
}