Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update doc comments throughout the module. #98

Merged
merged 1 commit into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions base.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import (
"strings"
)

// An Assigner assigns a Handler to handle the specified method name, or nil if
// no method is available to handle the request.
// An Assigner maps method names to Handler functions.
type Assigner interface {
// Assign returns the handler for the named method, or nil.
// Assign returns the handler for the named method, or returns nil to
// indicate that the method is not known.
//
// The implementation can obtain the complete request from ctx using the
// jrpc2.InboundRequest function.
Assign(ctx context.Context, method string) Handler
Expand All @@ -26,10 +27,11 @@ type Namer interface {
Names() []string
}

// A Handler function implements a method given a request. The response value
// must be JSON-marshalable or nil. In case of error, the handler can return a
// value of type *jrpc2.Error to control the response code sent back to the
// caller; otherwise the server will wrap the resulting value.
// A Handler function implements a method. The request contains the method
// name, request ID, and parameters sent by the client. The result value must
// be JSON-marshalable or nil. In case of error, the handler can return a value
// of type *jrpc2.Error to control the response code sent back to the caller;
// otherwise the server will wrap the resulting value.
//
// The context passed to the handler by a *jrpc2.Server includes two special
// values that the handler may extract.
Expand Down Expand Up @@ -153,7 +155,7 @@ func (r *Response) UnmarshalResult(v any) error {
return json.Unmarshal(r.result, v)
}

// ResultString returns the encoded result message of r as a string.
// ResultString returns the encoded result value of r as a string.
// If r has no result, for example if r is an error response, it returns "".
func (r *Response) ResultString() string { return string(r.result) }

Expand Down
10 changes: 5 additions & 5 deletions channel/channel.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Copyright (C) 2017 Michael J. Fromberger. All Rights Reserved.

// Package channel defines a basic communications channel.
// Package channel defines a communications channel.
//
// A Channel encodes/transmits and decodes/receives data records over an
// unstructured stream, using a configurable framing discipline. This package
// provides some basic framing implementations.
// A Channel encodes/transmits and decodes/receives data records. The types in
// this package support sending and receiving over an unstructured stream using
// a configurable framing discipline.
//
// # Channels
//
Expand Down Expand Up @@ -42,7 +42,7 @@ import (

// A Channel represents the ability to transmit and receive data records. A
// channel does not interpret the contents of a record, but may add and remove
// framing so that records can be embedded in higher-level protocols.
// framing so that records can be embedded in lower-level protocols.
//
// One sender and one receiver may use a Channel concurrently, but the methods
// of a Channel are not otherwise required to be safe for concurrent use. The
Expand Down
2 changes: 1 addition & 1 deletion channel/hdr.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"strings"
)

// StrictHeader defines a framing that transmits and receives messages using a
// StrictHeader defines a Framing that transmits and receives messages using a
// header prefix similar to HTTP, in which mimeType describes the content type.
//
// Specifically, each message is sent in the format:
Expand Down
52 changes: 26 additions & 26 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

// A Client is a JSON-RPC 2.0 client. The client sends requests and receives
// responses on a channel.Channel provided by the caller.
// responses on a channel.Channel provided by the constructor.
type Client struct {
done *sync.WaitGroup // done when the reader is finished at shutdown time

Expand All @@ -23,8 +23,8 @@ type Client struct {
scall func(context.Context, *jmessage) []byte
chook func(*Client, *Response)

cbctx context.Context // terminates when the client is closed
cbcancel func() // cancels cbctx
cbctx context.Context // terminates when the client is closed
cbcancel context.CancelFunc // cancels cbctx

mu sync.Mutex // protects the fields below
ch channel.Channel // channel to the server
Expand Down Expand Up @@ -82,7 +82,7 @@ func (c *Client) accept(ch receiver) error {
c.log("Decoding error: %v", err)
}
c.mu.Lock()
c.stop(err)
c.stopLocked(err)
c.mu.Unlock()
return err
}
Expand All @@ -94,16 +94,16 @@ func (c *Client) accept(ch receiver) error {
c.mu.Lock()
defer c.mu.Unlock()
for _, rsp := range in {
c.deliver(rsp)
c.deliverLocked(rsp)
}
}()
return nil
}

// handleRequest handles a callback or notification from the server. The
// handleRequestLocked handles a callback or notification from the server. The
// caller must hold c.mu. This function does not block for the handler.
// Precondition: msg is a request or notification, not a response or error.
func (c *Client) handleRequest(msg *jmessage) {
func (c *Client) handleRequestLocked(msg *jmessage) {
if msg.isNotification() {
if c.snote == nil {
c.log("Discarding notification: %v", msg)
Expand Down Expand Up @@ -134,14 +134,14 @@ func (c *Client) handleRequest(msg *jmessage) {
}
}

// For each response, find the request pending on its ID and deliver it. The
// caller must hold c.mu. Unknown response IDs are logged and discarded. As
// we are under the lock, we do not wait for the pending receiver to pick up
// the response; we just drop it in their channel. The channel is buffered so
// we don't need to rendezvous.
func (c *Client) deliver(rsp *jmessage) {
// deliverLocked delivers rsp to the request pending on its ID. The caller
// must hold c.mu. Unknown response IDs are logged and discarded. As we are
// under the lock, we do not wait for the pending receiver to pick up the
// response; we just drop it in their channel. The channel is buffered so we
// don't need to rendezvous.
func (c *Client) deliverLocked(rsp *jmessage) {
if rsp.isRequestOrNotification() {
c.handleRequest(rsp)
c.handleRequestLocked(rsp)
return
}

Expand Down Expand Up @@ -285,9 +285,9 @@ func (c *Client) waitComplete(pctx context.Context, id string, p *Response) {
}
}

// Call initiates a single request and blocks until the response returns.
// A successful call reports a nil error and a non-nil response. Errors from
// the server have concrete type *jrpc2.Error.
// Call initiates a single request and blocks until the response returns or ctx
// ends. A successful call reports a nil error and a non-nil response. Errors
// from the server have concrete type *jrpc2.Error.
//
// rsp, err := c.Call(ctx, method, params)
// if e, ok := err.(*jrpc2.Error); ok {
Expand Down Expand Up @@ -324,8 +324,8 @@ func (c *Client) CallResult(ctx context.Context, method string, params, result a
}

// Batch initiates a batch of concurrent requests, and blocks until all the
// responses return. The responses are returned in the same order as the
// original specs, omitting notifications.
// responses return or ctx ends. The responses are returned in the same order
// as the original specs, omitting notifications.
//
// Any error reported by Batch represents an error in encoding or sending the
// batch to the server. Errors reported by the server in response to requests
Expand Down Expand Up @@ -356,15 +356,15 @@ func (c *Client) Batch(ctx context.Context, specs []Spec) ([]*Response, error) {
}

// A Spec combines a method name and parameter value as part of a Batch. If
// the Notify field is true, the request is sent as a notification.
// the Notify flag is true, the request is sent as a notification.
type Spec struct {
Method string
Params any
Notify bool
}

// Notify transmits a notification to the specified method and parameters. It
// blocks until the notification has been sent.
// blocks until the notification has been sent or ctx ends.
func (c *Client) Notify(ctx context.Context, method string, params any) error {
req, err := c.note(ctx, method, params)
if err != nil {
Expand All @@ -377,7 +377,7 @@ func (c *Client) Notify(ctx context.Context, method string, params any) error {
// Close shuts down the client, terminating any pending in-flight requests.
func (c *Client) Close() error {
c.mu.Lock()
c.stop(errClientStopped)
c.stopLocked(errClientStopped)
c.mu.Unlock()
c.done.Wait()

Expand All @@ -392,10 +392,10 @@ func isUninteresting(err error) bool {
return err == io.EOF || channel.IsErrClosing(err) || err == errClientStopped
}

// stop closes down the reader for c and records err as its final state. The
// caller must hold c.mu. If multiple callers invoke stop, only the first will
// successfully record its error status.
func (c *Client) stop(err error) {
// stopLocked closes down the reader for c and records err as its final state.
// The caller must hold c.mu. If multiple callers invoke stop, only the first
// will successfully record its error status.
func (c *Client) stopLocked(err error) {
if c.ch == nil {
return // nothing is running
}
Expand Down
16 changes: 8 additions & 8 deletions code.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright (C) 2017 Michael J. Fromberger. All Rights Reserved.

// Package code defines error code values used by the jrpc2 package.
package jrpc2

import (
Expand All @@ -9,9 +8,9 @@ import (
"fmt"
)

// A Code is an error response.
// A Code is an error code included in the JSON-RPC error object.
//
// Code values from and including -32768 to -32000 are reserved for pre-defined
// Code values from and including -32768 to -32000 are reserved for predefined
// JSON-RPC errors. Any code within this range, but not defined explicitly
// below is reserved for future use. The remainder of the space is available
// for application defined errors.
Expand Down Expand Up @@ -89,11 +88,12 @@ var stdError = map[Code]string{
}

// ErrorCode returns a Code to categorize the specified error.
// If err == nil, it returns jrpc2.NoError.
// If err is (or wraps) an ErrCoder, it returns the reported code value.
// If err is context.Canceled, it returns jrpc2.Cancelled.
// If err is context.DeadlineExceeded, it returns jrpc2.DeadlineExceeded.
// Otherwise it returns jrpc2.SystemError.
//
// - If err == nil, it returns jrpc2.NoError.
// - If err is (or wraps) an ErrCoder, it returns the reported code value.
// - If err is context.Canceled, it returns jrpc2.Cancelled.
// - If err is context.DeadlineExceeded, it returns jrpc2.DeadlineExceeded.
// - Otherwise it returns jrpc2.SystemError.
func ErrorCode(err error) Code {
if err == nil {
return NoError
Expand Down
16 changes: 8 additions & 8 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"context"
)

// InboundRequest returns the inbound request associated with the given
// context, or nil if ctx does not have an inbound request. The context passed
// to the handler by *jrpc2.Server will include this value.
// InboundRequest returns the inbound request associated with the context
// passed to a Handler, or nil if ctx does not have an inbound request.
// A *jrpc2.Server populates this value for handler contexts.
//
// This is mainly useful to wrapped server methods that do not have the request
// as an explicit parameter; for direct implementations of the Handler type the
Expand All @@ -23,9 +23,8 @@ func InboundRequest(ctx context.Context) *Request {

type inboundRequestKey struct{}

// ServerFromContext returns the server associated with the given context.
// This will be populated on the context passed to request handlers.
// This function is for use by handlers, and will panic for a non-handler context.
// ServerFromContext returns the server associated with the context passed to a
// Handler by a *jrpc2.Server. It will panic for a non-handler context.
//
// It is safe to retain the server and invoke its methods beyond the lifetime
// of the context from which it was extracted; however, a handler must not
Expand All @@ -36,9 +35,10 @@ func ServerFromContext(ctx context.Context) *Server { return ctx.Value(serverKey
type serverKey struct{}

// ClientFromContext returns the client associated with the given context.
// This will be populated on the context passed to callback handlers.
// This will be populated on the context passed by a *jrpc2.Client to a
// client-side callback handler.
//
// A callback handler must not close the client, as the close will deadlock
// A callback handler MUST NOT close the client, as the close will deadlock
// waiting for the callback to return.
func ClientFromContext(ctx context.Context) *Client { return ctx.Value(clientKey{}).(*Client) }

Expand Down
3 changes: 2 additions & 1 deletion error.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import (
)

// Error is the concrete type of errors returned from RPC calls.
// It also represents the JSON encoding of the JSON-RPC error object.
type Error struct {
Code Code `json:"code"` // the machine-readable error code
Message string `json:"message,omitempty"` // the human-readable error message
Data json.RawMessage `json:"data,omitempty"` // optional ancillary error data
}

// Error renders e to a human-readable string for the error interface.
// Error returns a human-readable description of e.
func (e Error) Error() string { return fmt.Sprintf("[%d] %s", e.Code, e.Message) }

// ErrCode trivially satisfies the ErrCoder interface for an *Error.
Expand Down
16 changes: 8 additions & 8 deletions internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,12 @@ func TestServer_specialMethods(t *testing.T) {
}, nil)
ctx := context.Background()
for _, name := range []string{rpcServerInfo, "donkeybait"} {
if got := s.assign(ctx, name); got == nil {
t.Errorf("s.assign(%s): no method assigned", name)
if got := s.assignLocked(ctx, name); got == nil {
t.Errorf("s.assignLocked(%s): no method assigned", name)
}
}
if got := s.assign(ctx, "rpc.nonesuch"); got != nil {
t.Errorf("s.assign(rpc.nonesuch): got %p, want nil", got)
if got := s.assignLocked(ctx, "rpc.nonesuch"); got != nil {
t.Errorf("s.assignLocked(rpc.nonesuch): got %p, want nil", got)
}
}

Expand All @@ -250,14 +250,14 @@ func TestServer_disableBuiltinHook(t *testing.T) {

// With builtins disabled, the default rpc.* methods should not get assigned.
for _, name := range []string{rpcServerInfo} {
if got := s.assign(ctx, name); got != nil {
t.Errorf("s.assign(%s): got %p, wanted nil", name, got)
if got := s.assignLocked(ctx, name); got != nil {
t.Errorf("s.assignLocked(%s): got %p, wanted nil", name, got)
}
}

// However, user-assigned methods with this prefix should now work.
if got := s.assign(ctx, "rpc.nonesuch"); got == nil {
t.Error("s.assign(rpc.nonesuch): missing assignment")
if got := s.assignLocked(ctx, "rpc.nonesuch"); got == nil {
t.Error("s.assignLocked(rpc.nonesuch): missing assignment")
}
}

Expand Down
7 changes: 4 additions & 3 deletions json.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (
"encoding/json"
)

// ParseRequests parses a single request or a batch of requests from JSON.
// This function reports an error only if msg is not valid JSON. The caller
// must check the individual results for their validity.
// ParseRequests parses either a single request or a batch of requests from
// JSON. It reports an error only if msg is not valid JSON. The caller must
// check the Error field results to determine whether the individual requests
// are valid.
func ParseRequests(msg []byte) ([]*ParsedRequest, error) {
var reqs jmessages
if err := reqs.parseJSON(msg); err != nil {
Expand Down
4 changes: 2 additions & 2 deletions opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

// ServerOptions control the behaviour of a server created by NewServer.
// A nil *ServerOptions provides sensible defaults.
// A nil *ServerOptions is valid and provides sensible defaults.
// It is safe to share server options among multiple server instances.
type ServerOptions struct {
// If not nil, send debug text logs here.
Expand Down Expand Up @@ -88,7 +88,7 @@ func (s *ServerOptions) rpcLog() RPCLogger {
}

// ClientOptions control the behaviour of a client created by NewClient.
// A nil *ClientOptions provides sensible defaults.
// A nil *ClientOptions is valid and provides sensible defaults.
type ClientOptions struct {
// If not nil, send debug text logs here.
Logger Logger
Expand Down
Loading