rpc

package
v1.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 5, 2024 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package rpc provides a json RPC service. This should not be confused with the standards based JSON-RPC 1.0/2.0/... This is a specific implementation over chunked data in UDS.

This package bears more resemblence to net/http than to the net/rpc/json package, at least for the server. This could be used to build a "reflect" type of net/rpc service or to generate a service package like gRPC does.

A simple client example (based on the server below):

client, err := New(socketAddr, cred.UID.Int(), cred.GID.Int(), []os.FileMode{0770, 0771})
if err != nil {
	// Do something
}

ctx, cancel := context.WitheTimeout(5 * time.Second)
req := server.SumReq{Ints: 1, 2, 3}
resp := server.SumResp

retry:
	if err := client.Call(ctx, "/math/sum", req, &resp); err != nil {
		if chunkRPC.Retryable(err) {
			// Okay, so you probably should do this in a for loop, but I wanted to use
			// a label for the hell of it.
			goto retry
		}
		// Do something here, cause you have a non-retryable error.
	}
	if resp.Err.AsError() != nil {
		// Do something with the internal error.
	}
	fmt.Printf("Sum of %#v = %d\n", req, resp.Sum)

A simple service works like:

type Error struct {
	Msg string
}

func (e Error) AsError() error {
	if e.Msg == "" {
		return nil
	}
	return e
}
func (e Error) Error() string {
	return e.Msg
}

type SumReq struct {
	Ints []int
}

type SumResp struct {
	Sum int
	Err Error
}

type MathServer struct{}

func (m *MathServer) Sum(ctx context.Context, req []byte) ([]byte, error) {
	request := SumReq{}
	if err := json.Unmarshal(req, &request); err != nil {
		return nil, chunkRPC.Errorf(chunkRPC.ETBadData, "request could not be unmarshalled into SumReq: %s", err)
	}

	response := SumResp{}
	for _, i := range request.Ints {
		response.Sum += i
	}
	b, err := json.Marshal(response)
	if err != nil {
		return nil, chunkRPC.Errorf(chunkRPC.ETBadData, "request could not be unmarshalled into SumReq: %s", err)
	}
	return b, nil
}

func main() {
	cred, err := uds.Current()
	if err != nil {
		panic(err)
	}

	serv, err := NewServer("socketAddr", cred.UID.Int(), cred.GID.Int(), 0770)
	if err != nil {
		panic(err)
	}

	ms := MathServer{}

	serv.RegisterMethod("/math/sum", ms.Sum)

	if err := serv.Start(); err != nil {
		log.Fatal(err)
	}
}

Note: The server should only return errors to clients when something goes wrong with the RPC. This makes it predictable on the server side when the error is retryable. When the service has an error, I recommend returning the expected response, which should have a dict containing your custom error code and the error message. This allows your clients to decide if they should retry a request.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CredFromCtx

func CredFromCtx(ctx context.Context) uds.Cred

CredFromCtx will extract the Cred from the Context object.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client provides an RPC client using JSON.

func New

func New(socketAddr string, uid, gid int, fileModes []os.FileMode, options ...Option) (*Client, error)

New is the constructor for Client. rwc must be a *uds.Client.

func (*Client) Call

func (c *Client) Call(ctx context.Context, method string, req, resp interface{}) error

Call calls the RPC service. If Context timeout is not set, will default to 5 minutes.

func (*Client) Close

func (c *Client) Close() error

Close closes the underyling connection.

type Option

type Option func(c *Client)

Option is an optional argument to New.

func MaxSize

func MaxSize(size int64) Option

MaxSize is the maximum size a read message is allowed to be. If a message is larger than this, Next() will fail and the underlying connection will be closed.

func SharedPool

func SharedPool(pool *chunk.Pool) Option

SharedPool allows the use of a shared pool of buffers between Client instead of a pool per client. This is useful when clients are short lived and have similar message sizes. Client will panic if the pool does not return a *[]byte object.

type RequestHandler

type RequestHandler = rpc.RequestHandler

RequestHandler will receive a Context object with a Deadline set and you can retrieve the calling process creds with CredFromCtx. The bytes of the request and resp will be the json.Marshal of the response. An error returned is a ErrServer that can not be retried. Generally, service errors should be in the resp and not a returned error. See the note in the package intro.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server provides an json RPC server.

func NewServer

func NewServer(socketAddr string, uid, gid int, fileMode os.FileMode) (*Server, error)

NewServer is the constructor for a Server.

func (*Server) RegisterMethod

func (s *Server) RegisterMethod(method string, handler RequestHandler)

RegisterMethod registers an RPC method with the server.

func (*Server) Start

func (s *Server) Start() error

Start starts the server. This will block until the server stops.

func (*Server) Stop

func (s *Server) Stop(ctx context.Context) error

Stop stops the server, which will stop listening for new connections. This should slowly kill off existing calls. Stop will return when all calls have completed or the context deadline is reached(or cancelled). A nil error indicates that all jobs were completed. Note: a Server cannot be reused.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL