Documentation
¶
Overview ¶
Package grpc is a pure-Go (CGO-free), MRI-faithful reimplementation of the surface of Ruby's grpc gem — the object model a Ruby program sees as the GRPC namespace — without any Ruby runtime and without the gem's C extension (upstream grpc ships as a heavy C extension around the gRPC-core C library).
It does not reimplement HTTP/2 or the gRPC wire protocol: it is a Ruby-faithful API layer built on top of google.golang.org/grpc and google.golang.org/protobuf, the official pure-Go gRPC and protobuf runtimes. Every byte on the wire is therefore produced by the canonical Go gRPC stack, so a server built here interoperates with any conformant gRPC peer and a stub built here can call any conformant gRPC server, by construction.
The network seam ¶
The library never hardwires a socket into its core logic. Both the server's listener and the client's dialer are obtained from an injected Transport. NetTransport is the production transport (real TCP sockets); MemTransport is an in-process, bufconn-backed transport that carries a real HTTP/2 gRPC session over an in-memory pipe, so the whole stack is exercised end-to-end in tests without binding a port. This mirrors how the OIDC/OAuth2 bindings treat the HTTP round-trip as a host seam.
Mapping to the gem ¶
Ruby (grpc) Go (this package) ----------- ----------------- GRPC::RpcServer.new NewRpcServer(...) #add_http2_port(addr, creds) (*RpcServer).AddHTTP2Port #handle(service) (*RpcServer).Handle #run / #run_till_terminated (*RpcServer).Run / RunTillTerminated #stop (*RpcServer).Stop GRPC::ClientStub.new(host, creds) NewClientStub(...) #request_response (*ClientStub).RequestResponse #client_streamer (*ClientStub).ClientStreamer #server_streamer (*ClientStub).ServerStreamer #bidi_streamer (*ClientStub).BidiStreamer GRPC::ActiveCall *ActiveCall GRPC::Core::StatusCodes the StatusCode constants (OK, …) GRPC::BadStatus *BadStatus GRPC::Core::CallError *CallError metadata (a Hash) Metadata (map[string]string) GRPC::GenericService *GenericService rpc :Name, In, Out (*GenericService).RPC service.rpc_stub_class (*GenericService).StubClass → *GenericStub grpc_tools_ruby_protoc GenerateRubyServices
Generated services ¶
The generated-service layer mirrors what grpc_tools_ruby_protoc emits: a GenericService is the GRPC::GenericService a generated *_services_pb.rb Service base class includes — it names the service and collects the rpc declarations, then derives the server-side Service to register (GenericService.BuildService) and the client-side stub (GenericService.StubClass, the gem's rpc_stub_class). GenerateRubyServices is the code generator itself: given a .proto's service block it emits the exact *_services_pb.rb source, byte-faithful to grpc_tools_ruby_protoc (asserted against the real binary as the oracle).
Messages ¶
Like the gem, this package is message-agnostic: a call carries a marshal and an unmarshal function, exactly as GRPC::RpcDesc carries the marshal/unmarshal procs a generated *_pb.rb / *_services_pb.rb attaches. Messages produced by github.com/go-ruby-protobuf/protobuf (the pure-Go google-protobuf gem) drop straight in via its Encode/Decode.
Index ¶
- func GenerateRubyServices(f ServiceFile) (string, error)
- type ActiveCall
- type BadStatus
- type CallError
- type CallOptions
- type ClientStub
- func (s *ClientStub) BidiStreamer(method string, requests []any, opts CallOptions) ([]any, error)
- func (s *ClientStub) ClientStreamer(method string, requests []any, opts CallOptions) (any, error)
- func (s *ClientStub) Close() error
- func (s *ClientStub) RequestResponse(method string, req any, opts CallOptions) (any, error)
- func (s *ClientStub) ServerStreamer(method string, req any, opts CallOptions) ([]any, error)
- type GenericService
- func (g *GenericService) BuildService(h Handlers) (Service, error)
- func (g *GenericService) LookupRPC(name string) (RpcDesc, bool)
- func (g *GenericService) RPC(d RpcDesc) *GenericService
- func (g *GenericService) RpcDescs() []RpcDesc
- func (g *GenericService) ServiceName() string
- func (g *GenericService) StubClass(stub *ClientStub) *GenericStub
- type GenericStub
- func (s *GenericStub) BidiStreamer(rpc string, requests []any, opts CallOptions) ([]any, error)
- func (s *GenericStub) ClientStreamer(rpc string, requests []any, opts CallOptions) (any, error)
- func (s *GenericStub) RequestResponse(rpc string, req any, opts CallOptions) (any, error)
- func (s *GenericStub) ServerStreamer(rpc string, req any, opts CallOptions) ([]any, error)
- type Handlers
- type Marshaler
- type MemTransport
- type Metadata
- type Method
- type MethodGen
- type MethodType
- type NetTransport
- type RpcDesc
- type RpcServer
- type ServerOption
- type Service
- type ServiceFile
- type ServiceGen
- type StatusCode
- type StubOption
- type Transport
- type Unmarshaler
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GenerateRubyServices ¶
func GenerateRubyServices(f ServiceFile) (string, error)
GenerateRubyServices emits the *_services_pb.rb Ruby source for f, byte-for-byte as grpc_tools_ruby_protoc would. A service with no methods is skipped (as the gem's generator skips it), while the package modules are still emitted. It errors if the file has no ProtoFile, or a non-empty service or one of its methods has an empty name.
Types ¶
type ActiveCall ¶
type ActiveCall struct {
// contains filtered or unexported fields
}
ActiveCall mirrors GRPC::ActiveCall: the object a handler or a streaming stub uses to move messages and metadata over a single call. It applies the call's marshal/unmarshal functions so Send/Read speak in messages, not bytes.
The marshal/unmarshal directions are set by whichever side constructs it: on the server Send marshals responses and Read unmarshals requests; on the client it is the reverse.
func (*ActiveCall) Context ¶
func (c *ActiveCall) Context() context.Context
Context exposes the underlying call context for advanced callers.
func (*ActiveCall) Deadline ¶
func (c *ActiveCall) Deadline() (time.Time, bool)
Deadline returns the call deadline and whether one was set, mirroring ActiveCall#deadline.
func (*ActiveCall) EachRemoteRead ¶
func (c *ActiveCall) EachRemoteRead(fn func(msg any) error) error
EachRemoteRead calls fn for every message the peer sends until the stream is half-closed, mirroring ActiveCall#each_remote_read. A non-nil error from fn or from the transport stops the iteration and is returned.
func (*ActiveCall) Metadata ¶
func (c *ActiveCall) Metadata() Metadata
Metadata returns the request metadata the peer sent with the call, mirroring ActiveCall#metadata (a Hash).
func (*ActiveCall) Read ¶
func (c *ActiveCall) Read() (any, error)
Read receives the next message and unmarshals it, mirroring ActiveCall#remote_read. It returns io.EOF when the peer half-closes, so a handler can range over the request stream until EOF.
func (*ActiveCall) Send ¶
func (c *ActiveCall) Send(msg any) error
Send marshals msg and writes it to the call. It mirrors ActiveCall#send / the block-yield a streaming handler uses to emit a response.
type BadStatus ¶
type BadStatus struct {
Code StatusCode
Details string
Metadata Metadata
}
BadStatus mirrors GRPC::BadStatus: an operation that finished with a non-OK status. It carries the status code, the detail message and any trailing metadata, and it is the error a client raises when a call fails.
func NewBadStatus ¶
func NewBadStatus(code StatusCode, details string, md Metadata) *BadStatus
NewBadStatus builds a BadStatus, matching GRPC::BadStatus.new(code, details, metadata). A nil metadata becomes an empty Metadata.
type CallError ¶
type CallError struct {
Message string
}
CallError mirrors GRPC::Core::CallError: a low-level error from the call machinery itself (as opposed to a non-OK application status). It is raised for misuse such as writing to a finished call.
func NewCallError ¶
NewCallError builds a CallError with the given message.
type CallOptions ¶
type CallOptions struct {
Marshal Marshaler
Unmarshal Unmarshaler
Metadata Metadata
Deadline time.Time
}
CallOptions carries the per-call knobs the gem's stub methods accept: the message (un)marshalling, request metadata (a Hash) and a deadline.
type ClientStub ¶
type ClientStub struct {
// contains filtered or unexported fields
}
ClientStub mirrors GRPC::ClientStub: a handle to a remote service over which typed RPC helpers (request_response, client_streamer, server_streamer, bidi_streamer) are issued. The connection is dialed through the injected Transport, so the stub is exercisable in-process over MemTransport.
func NewClientStub ¶
func NewClientStub(host, creds string, opts ...StubOption) (*ClientStub, error)
NewClientStub mirrors GRPC::ClientStub.new(host, creds). The creds argument is accepted for surface fidelity (pass ":this_channel_is_insecure" for plaintext, as the gem does); TLS is a follow-up. It dials host through the transport.
func (*ClientStub) BidiStreamer ¶
func (s *ClientStub) BidiStreamer(method string, requests []any, opts CallOptions) ([]any, error)
BidiStreamer mirrors GRPC::ClientStub#bidi_streamer: it streams every request and returns every response. Requests are sent first, then responses drained; over a buffered transport this exercises full-duplex handlers.
func (*ClientStub) ClientStreamer ¶
func (s *ClientStub) ClientStreamer(method string, requests []any, opts CallOptions) (any, error)
ClientStreamer mirrors GRPC::ClientStub#client_streamer: it streams every request to method and returns the single response.
func (*ClientStub) RequestResponse ¶
func (s *ClientStub) RequestResponse(method string, req any, opts CallOptions) (any, error)
RequestResponse mirrors GRPC::ClientStub#request_response: a unary call. It marshals req, invokes method (e.g. "/helloworld.Greeter/SayHello"), and returns the unmarshalled response. A non-OK status is returned as *BadStatus.
func (*ClientStub) ServerStreamer ¶
func (s *ClientStub) ServerStreamer(method string, req any, opts CallOptions) ([]any, error)
ServerStreamer mirrors GRPC::ClientStub#server_streamer: it sends one request and returns every response the server streams back.
type GenericService ¶
type GenericService struct {
// contains filtered or unexported fields
}
GenericService mirrors the GRPC::GenericService mixin a generated *_services_pb.rb Service base class includes: it names the service (the gem's self.service_name) and collects the RPC declarations (the gem's `rpc` class-macro calls). From it, GenericService.BuildService derives the server-side Service to register on an RpcServer, and GenericService.StubClass derives the client-side stub — the gem's rpc_stub_class.
func NewGenericService ¶
func NewGenericService(serviceName string) *GenericService
NewGenericService builds a GenericService for the fully-qualified service name (e.g. "helloworld.Greeter"), mirroring a generated Service base whose self.service_name is set to that name.
func (*GenericService) BuildService ¶
func (g *GenericService) BuildService(h Handlers) (Service, error)
BuildService pairs each declared RpcDesc with its handler from h and returns the runtime Service to register on an RpcServer with Handle. It mirrors implementing a generated Service subclass and passing an instance to GRPC::RpcServer#handle. It errors if the service declares no RPCs, if a declared RPC has no handler, or if a handler's Go type does not match the RPC's cardinality.
func (*GenericService) LookupRPC ¶
func (g *GenericService) LookupRPC(name string) (RpcDesc, bool)
LookupRPC returns the RpcDesc for name and whether it was declared.
func (*GenericService) RPC ¶
func (g *GenericService) RPC(d RpcDesc) *GenericService
RPC declares one RPC on the service, mirroring the gem's `rpc :Name, Input, Output` class macro. It is chainable so a generated service reads as a sequence of RPC declarations. A duplicate name replaces the earlier declaration, as re-declaring an rpc does in the gem.
func (*GenericService) RpcDescs ¶
func (g *GenericService) RpcDescs() []RpcDesc
RpcDescs returns the declared RPCs in declaration order, mirroring the gem's GenericService.rpc_descs.
func (*GenericService) ServiceName ¶
func (g *GenericService) ServiceName() string
ServiceName returns the fully-qualified service name, mirroring the gem's GenericService.service_name.
func (*GenericService) StubClass ¶
func (g *GenericService) StubClass(stub *ClientStub) *GenericStub
StubClass derives the client stub over an existing ClientStub, mirroring `Stub = Service.rpc_stub_class` followed by `Stub.new(host, creds)`.
type GenericStub ¶
type GenericStub struct {
// contains filtered or unexported fields
}
GenericStub mirrors the Stub class GenericService.rpc_stub_class generates: it wraps a ClientStub and, for each declared RPC, issues the call with the right cardinality and the descriptor's own marshal/unmarshal already applied, so the caller supplies only the request(s) and optional metadata/deadline — exactly the ergonomics of a generated Stub#say_hello(req).
func (*GenericStub) BidiStreamer ¶
func (s *GenericStub) BidiStreamer(rpc string, requests []any, opts CallOptions) ([]any, error)
BidiStreamer issues the bidirectional-streaming RPC named rpc, mirroring a generated bidi stub method. It errors if rpc is unknown or is not a BidiStream RPC.
func (*GenericStub) ClientStreamer ¶
func (s *GenericStub) ClientStreamer(rpc string, requests []any, opts CallOptions) (any, error)
ClientStreamer issues the client-streaming RPC named rpc, mirroring a generated client-streaming stub method. It errors if rpc is unknown or is not a ClientStream RPC.
func (*GenericStub) RequestResponse ¶
func (s *GenericStub) RequestResponse(rpc string, req any, opts CallOptions) (any, error)
RequestResponse issues the unary RPC named rpc, mirroring a generated unary stub method. It errors if rpc is unknown or is not a Unary RPC.
func (*GenericStub) ServerStreamer ¶
func (s *GenericStub) ServerStreamer(rpc string, req any, opts CallOptions) ([]any, error)
ServerStreamer issues the server-streaming RPC named rpc, mirroring a generated server-streaming stub method. It errors if rpc is unknown or is not a ServerStream RPC.
type Handlers ¶
Handlers binds each declared RPC name to its handler implementation. Each value must be the handler func matching the RPC's cardinality — the same four shapes Method accepts:
Unary func(req any, call *ActiveCall) (any, error) ClientStream func(call *ActiveCall) (any, error) ServerStream func(req any, call *ActiveCall) error BidiStream func(call *ActiveCall) error
This mirrors defining the instance methods of a generated Service subclass.
type Marshaler ¶
Marshaler serializes a message to bytes. It plays the role of the marshal proc a generated *_services_pb.rb attaches to each GRPC::RpcDesc.
type MemTransport ¶
type MemTransport struct {
// contains filtered or unexported fields
}
MemTransport is an in-process transport backed by bufconn. A server's Listen registers an in-memory listener under its address; a client's Dial to that same address is wired straight to it. No OS socket or port is used, yet a real gRPC HTTP/2 session runs over the pipe, so servers and stubs are exercised end-to-end. Share one MemTransport between the server and the stubs that call it.
func NewMemTransport ¶
func NewMemTransport() *MemTransport
NewMemTransport creates an empty in-memory transport.
type Metadata ¶
Metadata mirrors the gem's representation of call metadata: a plain Hash of string keys to string values. In the gem a handler reads request metadata from ActiveCall#metadata and sends response metadata with a Hash; this type is that Hash.
gRPC keys are case-insensitive on the wire and the runtime lower-cases them; this type follows suit so a key set as "Foo" reads back as "foo", matching the gem's observed behaviour.
type Method ¶
type Method struct {
// Name is the RPC method name as it appears on the wire, e.g. "SayHello".
Name string
// Type selects the cardinality and which handler field is invoked.
Type MethodType
// RequestUnmarshal decodes an incoming request message.
RequestUnmarshal Unmarshaler
// ResponseMarshal encodes an outgoing response message.
ResponseMarshal Marshaler
// UnaryHandler serves a Unary method: one request in, one response out.
UnaryHandler func(req any, call *ActiveCall) (any, error)
// ClientStreamHandler serves a ClientStream method: it reads requests from
// call (via Read / EachRemoteRead) and returns the single response.
ClientStreamHandler func(call *ActiveCall) (any, error)
// ServerStreamHandler serves a ServerStream method: it receives the single
// request and emits responses with call.Send.
ServerStreamHandler func(req any, call *ActiveCall) error
// BidiStreamHandler serves a BidiStream method: it reads requests and emits
// responses over the same call.
BidiStreamHandler func(call *ActiveCall) error
}
Method describes one RPC of a service, mirroring a single GRPC::RpcDesc: its name, cardinality, the request/response (un)marshalling, and the handler. Exactly one handler field is used, selected by Type.
type MethodGen ¶
type MethodGen struct {
// Name is the RPC name as declared, e.g. "SayHello".
Name string
// InputType is the fully-qualified proto name of the request message, e.g.
// "helloworld.HelloRequest" (a leading dot is tolerated).
InputType string
// OutputType is the fully-qualified proto name of the response message.
OutputType string
// ClientStreaming marks a streaming request (the input is wrapped in
// stream(...)).
ClientStreaming bool
// ServerStreaming marks a streaming response (the output is wrapped in
// stream(...)).
ServerStreaming bool
}
MethodGen describes one RPC in a service block.
type MethodType ¶
type MethodType int
MethodType is the cardinality of an RPC, mirroring the four shapes a GRPC::RpcDesc can take.
const ( // Unary is a single request, single response (request_response). Unary MethodType = iota // ClientStream is a stream of requests, single response (client_streamer). ClientStream // ServerStream is a single request, stream of responses (server_streamer). ServerStream // BidiStream is a stream of requests and a stream of responses // (bidi_streamer). BidiStream )
type NetTransport ¶
type NetTransport struct{}
NetTransport is the production transport: it listens and dials real TCP sockets via the standard library. It is the default when a server or stub is created without an explicit transport.
type RpcDesc ¶
type RpcDesc struct {
// Name is the RPC method name as declared and as it appears on the wire,
// e.g. "SayHello".
Name string
// Type is the cardinality of the RPC.
Type MethodType
// RequestMarshal encodes a request message (used by the client stub).
RequestMarshal Marshaler
// RequestUnmarshal decodes a request message (used by the server).
RequestUnmarshal Unmarshaler
// ResponseMarshal encodes a response message (used by the server).
ResponseMarshal Marshaler
// ResponseUnmarshal decodes a response message (used by the client stub).
ResponseUnmarshal Unmarshaler
}
RpcDesc mirrors GRPC::RpcDesc: one declared RPC of a service — its wire name, cardinality, and the marshal/unmarshal functions for the request and response messages. In the gem a RpcDesc carries the marshal/unmarshal *procs* a message class' marshal_class_method / unmarshal_class_method yield; here, staying message-agnostic like the gem, it carries the equivalent Marshaler / Unmarshaler functions. Messages from github.com/go-ruby-protobuf/protobuf drop straight in via its Encode / Decode.
type RpcServer ¶
type RpcServer struct {
// contains filtered or unexported fields
}
RpcServer mirrors GRPC::RpcServer: it binds one or more HTTP/2 ports, has services registered on it, and runs until stopped. The actual listener comes from the injected Transport, so the server logic itself never touches a socket and is fully exercisable in-process over MemTransport.
func NewRpcServer ¶
func NewRpcServer(opts ...ServerOption) *RpcServer
NewRpcServer builds an RpcServer, mirroring GRPC::RpcServer.new. Register services with Handle, bind ports with AddHTTP2Port, then Run.
func (*RpcServer) AddHTTP2Port ¶
AddHTTP2Port mirrors GRPC::RpcServer#add_http2_port(addr, creds). The credentials argument is accepted for surface fidelity — pass ":this_port_is_insecure" for a plaintext port, as the gem does. TLS credentials are a follow-up; the address is remembered and bound when the server runs. It returns the bound address.
func (*RpcServer) Handle ¶
Handle mirrors GRPC::RpcServer#handle(service): it registers a service's RPCs. It must be called before Run.
func (*RpcServer) Run ¶
Run mirrors GRPC::RpcServer#run: it binds every added port and serves, blocking until Stop is called. A bind failure is returned immediately; a clean Stop returns nil. At least one port must have been added, and Run may not be entered twice.
func (*RpcServer) RunTillTerminated ¶
RunTillTerminated mirrors GRPC::RpcServer#run_till_terminated: it runs the server and returns when it is stopped. The gem also installs SIGINT/SIGTERM handlers; wiring signals is a host concern, so here it is an alias for Run that a host can pair with its own signal trap calling Stop.
type ServerOption ¶
type ServerOption func(*RpcServer)
ServerOption configures an RpcServer at construction.
func WithTransport ¶
func WithTransport(t Transport) ServerOption
WithTransport injects the network seam. Without it an RpcServer uses NetTransport (real sockets).
type Service ¶
Service describes a gRPC service to register on an RpcServer, mirroring the service object passed to GRPC::RpcServer#handle. Name is the fully-qualified service name (e.g. "helloworld.Greeter").
type ServiceFile ¶
type ServiceFile struct {
// ProtoFile is the source .proto path as it appears after -I, e.g.
// "helloworld.proto" or "grpc/testing/echo.proto". It sets the header's
// Source line and the require of the companion messages file.
ProtoFile string
// Package is the proto package, e.g. "helloworld" or "grpc.testing" (may be
// empty for a package-less file).
Package string
// Services are the services declared in the file, in declaration order.
Services []ServiceGen
}
ServiceFile describes one .proto file's service block, the input to GenerateRubyServices — the subset of a FileDescriptorProto the Ruby gRPC generator reads.
type ServiceGen ¶
type ServiceGen struct {
// Name is the service name as declared, e.g. "Greeter".
Name string
// Methods are the RPCs of the service, in declaration order.
Methods []MethodGen
}
ServiceGen describes one service block.
type StatusCode ¶
type StatusCode uint32
StatusCode mirrors GRPC::Core::StatusCodes — the canonical gRPC status codes. The integer values are wire-fixed and identical to the gem's constants and to google.golang.org/grpc/codes.
const ( OK StatusCode = 0 Cancelled StatusCode = 1 Unknown StatusCode = 2 InvalidArgument StatusCode = 3 DeadlineExceeded StatusCode = 4 NotFound StatusCode = 5 AlreadyExists StatusCode = 6 PermissionDenied StatusCode = 7 ResourceExhausted StatusCode = 8 FailedPrecondition StatusCode = 9 Aborted StatusCode = 10 OutOfRange StatusCode = 11 Unimplemented StatusCode = 12 Internal StatusCode = 13 DataLoss StatusCode = 15 Unauthenticated StatusCode = 16 )
The gRPC status codes, matching GRPC::Core::StatusCodes::* one-to-one.
func (StatusCode) Name ¶
func (c StatusCode) Name() string
Name returns the gem's constant name for the code, e.g. "INVALID_ARGUMENT". Unknown numeric codes render as "CODE(<n>)".
func (StatusCode) String ¶
func (c StatusCode) String() string
String satisfies fmt.Stringer with the gem's constant name.
type StubOption ¶
type StubOption func(*stubConfig)
StubOption configures a ClientStub at construction.
func WithStubTransport ¶
func WithStubTransport(t Transport) StubOption
WithStubTransport injects the network seam for the stub. Without it the stub dials via NetTransport.
func WithTimeout ¶
func WithTimeout(d time.Duration) StubOption
WithTimeout sets a default per-call deadline, mirroring the gem's ClientStub.new(..., timeout:). CallOptions.Deadline overrides it per call.
type Transport ¶
type Transport interface {
// Listen returns a net.Listener for the given "host:port" address.
Listen(addr string) (net.Listener, error)
// Dial returns a connection to the given address, honouring ctx for
// cancellation and deadlines.
Dial(ctx context.Context, addr string) (net.Conn, error)
}
Transport is the network seam. The core RpcServer and ClientStub never touch sockets directly: a server obtains its listener from Listen and a client obtains its connections from Dial. Production wiring uses NetTransport (real TCP); tests use MemTransport (an in-process bufconn pipe carrying a real HTTP/2 gRPC session). Injecting the transport keeps the whole stack testable in-process without binding a port, mirroring the host seam used by the OIDC / OAuth2 bindings.
type Unmarshaler ¶
Unmarshaler deserializes bytes into a message, mirroring the unmarshal proc a generated *_services_pb.rb attaches to each GRPC::RpcDesc.
