mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-22 00:13:52 +01:00
Finish implementation of RPC.
This commit is contained in:
parent
c1aed10e8b
commit
4494afe47f
@ -2,6 +2,7 @@ package model
|
|||||||
|
|
||||||
type Filesystem struct {
|
type Filesystem struct {
|
||||||
Name string
|
Name string
|
||||||
|
Parent *Filesystem
|
||||||
Children []Filesystem
|
Children []Filesystem
|
||||||
Snapshots []Snapshot
|
Snapshots []Snapshot
|
||||||
}
|
}
|
||||||
|
146
rpc/rpc.go
146
rpc/rpc.go
@ -6,16 +6,19 @@ import (
|
|||||||
|
|
||||||
. "github.com/zrepl/zrepl/model"
|
. "github.com/zrepl/zrepl/model"
|
||||||
. "github.com/zrepl/zrepl/util"
|
. "github.com/zrepl/zrepl/util"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RPCRequester interface {
|
type RPCRequester interface {
|
||||||
FilesystemRequest(r FilesystemRequest) (root Filesystem, err error)
|
FilesystemRequest(r FilesystemRequest) (roots []Filesystem, err error)
|
||||||
InitialTransferRequest(r InitialTransferRequest) (io.Reader, error)
|
InitialTransferRequest(r InitialTransferRequest) (io.Reader, error)
|
||||||
IncrementalTransferRequest(r IncrementalTransferRequest) (io.Reader, error)
|
IncrementalTransferRequest(r IncrementalTransferRequest) (io.Reader, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RPCHandler interface {
|
type RPCHandler interface {
|
||||||
HandleFilesystemRequest(r FilesystemRequest) (root Filesystem, err error)
|
HandleFilesystemRequest(r FilesystemRequest) (roots []Filesystem, err error)
|
||||||
HandleInitialTransferRequest(r InitialTransferRequest) (io.Reader, error)
|
HandleInitialTransferRequest(r InitialTransferRequest) (io.Reader, error)
|
||||||
HandleIncrementalTransferRequest(r IncrementalTransferRequest) (io.Reader, error)
|
HandleIncrementalTransferRequest(r IncrementalTransferRequest) (io.Reader, error)
|
||||||
}
|
}
|
||||||
@ -28,7 +31,7 @@ type ByteStreamRPC struct {
|
|||||||
decoder *json.Decoder
|
decoder *json.Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConnectByteStreamRPC(conn io.ReadWriteCloser) (ByteStreamRPC, error) {
|
func ConnectByteStreamRPC(conn io.ReadWriteCloser) (RPCRequester, error) {
|
||||||
// TODO do ssh connection to transport, establish TCP-like communication channel
|
// TODO do ssh connection to transport, establish TCP-like communication channel
|
||||||
rpc := ByteStreamRPC{
|
rpc := ByteStreamRPC{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
@ -37,8 +40,11 @@ func ConnectByteStreamRPC(conn io.ReadWriteCloser) (ByteStreamRPC, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assert protocol versions are equal
|
// Assert protocol versions are equal
|
||||||
req := NewByteStreamRPCProtocolVersionRequest()
|
err := rpc.ProtocolVersionRequest()
|
||||||
rpc.encoder.Encode(&req)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return rpc, nil
|
return rpc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +122,25 @@ func ListenByteStreamRPC(conn io.ReadWriteCloser, handler RPCHandler) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO
|
|
||||||
|
case RTIncrementalTransferRequest:
|
||||||
|
|
||||||
|
var rq IncrementalTransferRequest
|
||||||
|
if err := decoder.Decode(&rq); err != nil {
|
||||||
|
respondWithError(conn, EDecodeRequestBody, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
snapReader, err := handler.HandleIncrementalTransferRequest(rq)
|
||||||
|
if err != nil {
|
||||||
|
respondWithError(conn, EHandler, err)
|
||||||
|
} else {
|
||||||
|
chunker := NewChunker(snapReader)
|
||||||
|
_, err := io.Copy(conn, &chunker)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
respondWithError(conn, EUnknownRequestType, nil)
|
respondWithError(conn, EUnknownRequestType, nil)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
@ -130,28 +154,122 @@ func respondWithError(conn io.Writer, id ErrorId, err error) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func inferRequestType(v interface{}) (RequestType, error) {
|
||||||
|
switch v.(type) {
|
||||||
|
case ByteStreamRPCProtocolVersionRequest:
|
||||||
|
return RTProtocolVersionRequest, nil
|
||||||
|
case FilesystemRequest:
|
||||||
|
return RTFilesystemRequest, nil
|
||||||
|
case InitialTransferRequest:
|
||||||
|
return RTInitialTransferRequest, nil
|
||||||
|
default:
|
||||||
|
return 0, errors.New(fmt.Sprintf("cannot infer request type for type '%v'",
|
||||||
|
reflect.TypeOf(v)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func genUUID() [16]byte {
|
||||||
|
return [16]byte{} // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ByteStreamRPC) sendRequest(v interface{}) (err error) {
|
||||||
|
|
||||||
|
var rt RequestType
|
||||||
|
|
||||||
|
if rt, err = inferRequestType(v); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h := RequestHeader{
|
||||||
|
Type: rt,
|
||||||
|
Id: genUUID(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.encoder.Encode(h); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = c.encoder.Encode(v); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ByteStreamRPC) expectResponseType(rt ResponseType) (err error) {
|
||||||
|
var h ResponseHeader
|
||||||
|
if err = c.decoder.Decode(&h); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.ResponseType != rt {
|
||||||
|
return errors.New("unexpected response type in response header")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ByteStreamRPC) sendRequestReceiveHeader(request interface{}, rt ResponseType) (err error) {
|
||||||
|
|
||||||
|
if err = c.sendRequest(request); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.expectResponseType(rt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ByteStreamRPC) ProtocolVersionRequest() (err error) {
|
||||||
|
b := ByteStreamRPCProtocolVersionRequest{
|
||||||
|
ClientVersion: ByteStreamRPCProtocolVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
// OK response means the remote side can cope with our protocol version
|
||||||
|
return c.sendRequestReceiveHeader(b, ROK)
|
||||||
|
}
|
||||||
|
|
||||||
func (c ByteStreamRPC) FilesystemRequest(r FilesystemRequest) (roots []Filesystem, err error) {
|
func (c ByteStreamRPC) FilesystemRequest(r FilesystemRequest) (roots []Filesystem, err error) {
|
||||||
return nil, nil
|
|
||||||
|
if err = c.sendRequestReceiveHeader(r, RFilesystems); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
roots = make([]Filesystem, 0)
|
||||||
|
|
||||||
|
if err = c.decoder.Decode(roots); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ByteStreamRPC) InitialTransferRequest(r InitialTransferRequest) (io.Reader, error) {
|
func (c ByteStreamRPC) InitialTransferRequest(r InitialTransferRequest) (unchunker io.Reader, err error) {
|
||||||
// send request header using protobuf or similar
|
|
||||||
return nil, nil
|
if err = c.sendRequestReceiveHeader(r, RChunkedStream); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
unchunker = NewUnchunker(c.conn)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ByteStreamRPC) IncrementalTransferRequest(r IncrementalTransferRequest) (io.Reader, error) {
|
func (c ByteStreamRPC) IncrementalTransferRequest(r IncrementalTransferRequest) (unchunker io.Reader, err error) {
|
||||||
return nil, nil
|
if err = c.sendRequestReceiveHeader(r, RChunkedStream); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
unchunker = NewUnchunker(c.conn)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalRPC struct {
|
type LocalRPC struct {
|
||||||
handler RPCHandler
|
handler RPCHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConnectLocalRPC(handler RPCHandler) LocalRPC {
|
func ConnectLocalRPC(handler RPCHandler) RPCRequester {
|
||||||
return LocalRPC{handler}
|
return LocalRPC{handler}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c LocalRPC) FilesystemRequest(r FilesystemRequest) (root Filesystem, err error) {
|
func (c LocalRPC) FilesystemRequest(r FilesystemRequest) (roots []Filesystem, err error) {
|
||||||
return c.handler.HandleFilesystemRequest(r)
|
return c.handler.HandleFilesystemRequest(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ const (
|
|||||||
RTProtocolVersionRequest RequestType = 1
|
RTProtocolVersionRequest RequestType = 1
|
||||||
RTFilesystemRequest = 16
|
RTFilesystemRequest = 16
|
||||||
RTInitialTransferRequest = 17
|
RTInitialTransferRequest = 17
|
||||||
|
RTIncrementalTransferRequest = 18
|
||||||
)
|
)
|
||||||
|
|
||||||
type RequestHeader struct {
|
type RequestHeader struct {
|
||||||
@ -55,7 +56,9 @@ const (
|
|||||||
type ResponseType uint8
|
type ResponseType uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ROK ResponseType = 0
|
ROK ResponseType = 1
|
||||||
|
RFilesystems = 2
|
||||||
|
RChunkedStream = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
type ResponseHeader struct {
|
type ResponseHeader struct {
|
||||||
|
@ -15,8 +15,8 @@ type Unchunker struct {
|
|||||||
remainingChunkBytes uint32
|
remainingChunkBytes uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUnchunker(conn io.Reader) Unchunker {
|
func NewUnchunker(conn io.Reader) *Unchunker {
|
||||||
return Unchunker{
|
return &Unchunker{
|
||||||
in: conn,
|
in: conn,
|
||||||
remainingChunkBytes: 0,
|
remainingChunkBytes: 0,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user