"refactor(common): 重构序列化工具包,将serialize重命名为utils并添加bitset组件"
This commit is contained in:
142
common/utils/go-jsonrpc/httpio/reader.go
Normal file
142
common/utils/go-jsonrpc/httpio/reader.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package httpio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
)
|
||||
|
||||
var log = logging.Logger("rpc")
|
||||
|
||||
func ReaderParamEncoder(addr string) jsonrpc.Option {
|
||||
return jsonrpc.WithParamEncoder(new(io.Reader), func(value reflect.Value) (reflect.Value, error) {
|
||||
r := value.Interface().(io.Reader)
|
||||
|
||||
reqID := uuid.New()
|
||||
u, _ := url.Parse(addr)
|
||||
u.Path = path.Join(u.Path, reqID.String())
|
||||
|
||||
go func() {
|
||||
// TODO: figure out errors here
|
||||
|
||||
resp, err := http.Post(u.String(), "application/octet-stream", r)
|
||||
if err != nil {
|
||||
log.Errorf("sending reader param: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
log.Errorf("sending reader param: non-200 status: ", resp.Status)
|
||||
return
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
return reflect.ValueOf(reqID), nil
|
||||
})
|
||||
}
|
||||
|
||||
type waitReadCloser struct {
|
||||
io.ReadCloser
|
||||
wait chan struct{}
|
||||
}
|
||||
|
||||
func (w *waitReadCloser) Read(p []byte) (int, error) {
|
||||
n, err := w.ReadCloser.Read(p)
|
||||
if err != nil {
|
||||
close(w.wait)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (w *waitReadCloser) Close() error {
|
||||
close(w.wait)
|
||||
return w.ReadCloser.Close()
|
||||
}
|
||||
|
||||
func ReaderParamDecoder() (http.HandlerFunc, jsonrpc.ServerOption) {
|
||||
var readersLk sync.Mutex
|
||||
readers := map[uuid.UUID]chan *waitReadCloser{}
|
||||
|
||||
hnd := func(resp http.ResponseWriter, req *http.Request) {
|
||||
strId := path.Base(req.URL.Path)
|
||||
u, err := uuid.Parse(strId)
|
||||
if err != nil {
|
||||
http.Error(resp, fmt.Sprintf("parsing reader uuid: %s", err), 400)
|
||||
}
|
||||
|
||||
readersLk.Lock()
|
||||
ch, found := readers[u]
|
||||
if !found {
|
||||
ch = make(chan *waitReadCloser)
|
||||
readers[u] = ch
|
||||
}
|
||||
readersLk.Unlock()
|
||||
|
||||
wr := &waitReadCloser{
|
||||
ReadCloser: req.Body,
|
||||
wait: make(chan struct{}),
|
||||
}
|
||||
|
||||
select {
|
||||
case ch <- wr:
|
||||
case <-req.Context().Done():
|
||||
log.Error("context error in reader stream handler (1): %v", req.Context().Err())
|
||||
resp.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-wr.wait:
|
||||
case <-req.Context().Done():
|
||||
log.Error("context error in reader stream handler (2): %v", req.Context().Err())
|
||||
resp.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteHeader(200)
|
||||
}
|
||||
|
||||
dec := jsonrpc.WithParamDecoder(new(io.Reader), func(ctx context.Context, b []byte) (reflect.Value, error) {
|
||||
var strId string
|
||||
if err := json.Unmarshal(b, &strId); err != nil {
|
||||
return reflect.Value{}, xerrors.Errorf("unmarshaling reader id: %w", err)
|
||||
}
|
||||
|
||||
u, err := uuid.Parse(strId)
|
||||
if err != nil {
|
||||
return reflect.Value{}, xerrors.Errorf("parsing reader UUDD: %w", err)
|
||||
}
|
||||
|
||||
readersLk.Lock()
|
||||
ch, found := readers[u]
|
||||
if !found {
|
||||
ch = make(chan *waitReadCloser)
|
||||
readers[u] = ch
|
||||
}
|
||||
readersLk.Unlock()
|
||||
|
||||
select {
|
||||
case wr := <-ch:
|
||||
return reflect.ValueOf(wr), nil
|
||||
case <-ctx.Done():
|
||||
return reflect.Value{}, ctx.Err()
|
||||
}
|
||||
})
|
||||
|
||||
return hnd, dec
|
||||
}
|
||||
Reference in New Issue
Block a user