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 ¶
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.
type Option ¶
type Option func(c *Client)
Option is an optional argument to New.
func MaxSize ¶
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 ¶
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 (*Server) RegisterMethod ¶
func (s *Server) RegisterMethod(method string, handler RequestHandler)
RegisterMethod registers an RPC method with the server.
func (*Server) Stop ¶
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.