infra/proxyd/methods.go

93 lines
2.0 KiB
Go
Raw Normal View History

package proxyd
import (
"context"
"crypto/sha256"
"encoding/json"
"fmt"
"strings"
"sync"
2023-05-16 05:30:03 +03:00
"github.com/ethereum/go-ethereum/log"
)
type RPCMethodHandler interface {
GetRPCMethod(context.Context, *RPCReq) (*RPCRes, error)
PutRPCMethod(context.Context, *RPCReq, *RPCRes) error
}
type StaticMethodHandler struct {
cache Cache
m sync.RWMutex
filterGet func(*RPCReq) bool
filterPut func(*RPCReq, *RPCRes) bool
}
func (e *StaticMethodHandler) key(req *RPCReq) string {
// signature is the hashed json.RawMessage param contents
h := sha256.New()
h.Write(req.Params)
signature := fmt.Sprintf("%x", h.Sum(nil))
return strings.Join([]string{"cache", req.Method, signature}, ":")
}
func (e *StaticMethodHandler) GetRPCMethod(ctx context.Context, req *RPCReq) (*RPCRes, error) {
if e.cache == nil {
return nil, nil
}
if e.filterGet != nil && !e.filterGet(req) {
return nil, nil
}
e.m.RLock()
defer e.m.RUnlock()
key := e.key(req)
val, err := e.cache.Get(ctx, key)
if err != nil {
log.Error("error reading from cache", "key", key, "method", req.Method, "err", err)
return nil, err
}
if val == "" {
return nil, nil
}
var result interface{}
if err := json.Unmarshal([]byte(val), &result); err != nil {
log.Error("error unmarshalling value from cache", "key", key, "method", req.Method, "err", err)
return nil, err
}
return &RPCRes{
JSONRPC: req.JSONRPC,
Result: result,
ID: req.ID,
}, nil
}
func (e *StaticMethodHandler) PutRPCMethod(ctx context.Context, req *RPCReq, res *RPCRes) error {
if e.cache == nil {
return nil
}
// if there is a filter on get, we don't want to cache it because its irretrievable
if e.filterGet != nil && !e.filterGet(req) {
return nil
}
// response filter
if e.filterPut != nil && !e.filterPut(req, res) {
return nil
}
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 {
2023-05-16 06:20:42 +03:00
log.Error("error putting into cache", "key", key, "method", req.Method, "err", err)
return err
}
return nil
}