methods.go 1.82 KB
Newer Older
inphi's avatar
inphi committed
1 2 3 4
package proxyd

import (
	"context"
5
	"crypto/sha256"
inphi's avatar
inphi committed
6
	"encoding/json"
7
	"fmt"
8
	"strings"
inphi's avatar
inphi committed
9
	"sync"
Felipe Andrade's avatar
Felipe Andrade committed
10 11

	"github.com/ethereum/go-ethereum/log"
inphi's avatar
inphi committed
12
)
inphi's avatar
inphi committed
13

inphi's avatar
inphi committed
14
type RPCMethodHandler interface {
inphi's avatar
inphi committed
15
	GetRPCMethod(context.Context, *RPCReq) (*RPCRes, error)
16
	PutRPCMethod(context.Context, *RPCReq, *RPCRes) error
inphi's avatar
inphi committed
17 18
}

inphi's avatar
inphi committed
19
type StaticMethodHandler struct {
20 21 22
	cache  Cache
	m      sync.RWMutex
	filter func(*RPCReq) bool
inphi's avatar
inphi committed
23 24
}

25
func (e *StaticMethodHandler) key(req *RPCReq) string {
26 27 28 29
	// signature is the hashed json.RawMessage param contents
	h := sha256.New()
	h.Write(req.Params)
	signature := fmt.Sprintf("%x", h.Sum(nil))
30
	return strings.Join([]string{"cache", req.Method, signature}, ":")
inphi's avatar
inphi committed
31 32
}

33
func (e *StaticMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*RPCRes, error) {
inphi's avatar
inphi committed
34
	if e.cache == nil {
35 36
		return nil, nil
	}
37 38 39 40
	if e.filter != nil && !e.filter(req) {
		return nil, nil
	}

41 42
	e.m.RLock()
	defer e.m.RUnlock()
inphi's avatar
inphi committed
43

44 45
	key := e.key(req)
	val, err := e.cache.Get(ctx, key)
46
	if err != nil {
47
		log.Error("error reading from cache", "key", key, "method", req.Method, "err", err)
48 49
		return nil, err
	}
50
	if val == "" {
51 52 53
		return nil, nil
	}

54 55
	var result interface{}
	if err := json.Unmarshal([]byte(val), &result); err != nil {
56
		log.Error("error unmarshalling value from cache", "key", key, "method", req.Method, "err", err)
57 58
		return nil, err
	}
59 60 61 62 63
	return &RPCRes{
		JSONRPC: req.JSONRPC,
		Result:  result,
		ID:      req.ID,
	}, nil
64 65
}

66 67
func (e *StaticMethodHandler) PutRPCMethod(ctx context.Context, req *RPCReq, res *RPCRes) error {
	if e.cache == nil {
68 69
		return nil
	}
70 71 72
	if e.filter != nil && !e.filter(req) {
		return nil
	}
73 74 75 76 77 78 79 80 81

	e.m.Lock()
	defer e.m.Unlock()

	key := e.key(req)
	value := mustMarshalJSON(res.Result)

	err := e.cache.Put(ctx, key, string(value))
	if err != nil {
Felipe Andrade's avatar
Felipe Andrade committed
82
		log.Error("error putting into cache", "key", key, "method", req.Method, "err", err)
83 84 85
		return err
	}
	return nil
inphi's avatar
inphi committed
86
}