2022-02-06 07:06:32 +00:00

120 lines
4.0 KiB
Go

// Copyright (C) 2017 Michael J. Fromberger. All Rights Reserved.
// Package channel defines a basic 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.
//
// Channels
//
// A Channel represents the ability to send and received framed records,
// comprising the methods:
//
// Send([]byte) error // send a single complete record
// Recv() ([]byte, error) // receive a single complete record
// Close() error // close the channel
//
// Each record passed to Send is available for Recv. Record contents are not
// interpreted (except as noted below), and it is up to the implementation to
// decide how records are framed for transport. A channel must support use by
// one sender and one receiver concurrently, but is not otherwise required to
// be safe for concurrent use.
//
// Framing
//
// A Framing function adapts a pair of io.Reader and io.WriteCloser to a
// Channel by imposing a particular message-framing discipline. This package
// provides several framing implementations, for example:
//
// ch := channel.LSP(r, wc)
//
// creates a channel that reads from r and writes to wc using the Language
// Server Protocol (LSP) framing defined by
// https://microsoft.github.io/language-server-protocol/specification.
//
package channel
import (
"errors"
"io"
"net"
)
// 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.
//
// 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
// order of records received must be the same as the order sent.
type Channel interface {
// Send transmits a record on the channel. Each call to Send transmits one
// complete record.
Send([]byte) error
// Recv returns the next available record from the channel. If no further
// messages are available, it returns nil, io.EOF. Each call to Recv
// fetches a single complete record.
Recv() ([]byte, error)
// Close shuts down the channel, after which no further records may be
// sent or received.
Close() error
}
// ErrClosed is a sentinel error that can be returned to indicate an operation
// failed because the channel was closed.
var ErrClosed = errors.New("channel is closed")
// IsErrClosing reports whether err is a channel-closed error. This is true
// for the internal error returned by a read from a pipe or socket that is
// closed, or an error that wraps ErrClosed. It is false if err == nil.
func IsErrClosing(err error) bool {
return err != nil && (errors.Is(err, ErrClosed) || errors.Is(err, net.ErrClosed))
}
// A Framing converts a reader and a writer into a Channel with a particular
// message-framing discipline.
type Framing func(io.Reader, io.WriteCloser) Channel
type direct struct {
send chan<- []byte
recv <-chan []byte
}
func (d direct) Send(msg []byte) (err error) {
defer func() {
if p := recover(); p != nil {
err = errors.New("send on closed channel")
}
}()
d.send <- msg
return nil
}
func (d direct) Recv() ([]byte, error) {
msg, ok := <-d.recv
if ok {
return msg, nil
}
return nil, io.EOF
}
func (d direct) Close() error { close(d.send); return nil }
// Direct returns a pair of synchronous connected channels that pass message
// buffers directly in memory without framing or encoding. Sends to client will
// be received by server, and vice versa.
//
// Note that buffers passed to direct channels are not copied. If the caller
// needs to use the buffer after sending it on a direct channel, the caller is
// responsible for making a copy.
func Direct() (client, server Channel) {
c2s := make(chan []byte)
s2c := make(chan []byte)
client = direct{send: c2s, recv: s2c}
server = direct{send: s2c, recv: c2s}
return
}