SYNOPSYS import "clive/ch" const Tnone uint16 = iota ... const MaxMsgSz = 64 * 1024 ... var ErrTooLarge = errors.New("message size is too large") ... var ErrBadPeer = errors.New("both peers are caller/callee") func DefType(x Unpacker) func GroupBytes(in <-chan interface{}, ival time.Duration, size int) <-chan interface{} func Merge(in ...<-chan interface{}) <-chan interface{} func ReadBytes(r io.Reader, c chan<- interface{}) (nbytes int64, nmsgs int, err error) func ReadMsg(r io.Reader) (n int, tag uint32, m interface{}, err error) func ReadMsgs(r io.Reader, c chan<- interface{}) (nbytes int64, nmsgs int, err error) func UnpackString(b []byte) ([]byte, string, error) func WriteBytes(w io.Writer, c <-chan interface{}) (nbytes int64, nmsgs int, err error) func WriteMsg(w io.Writer, tag uint32, m interface{}) (int64, error) func WriteMsgs(w io.Writer, tag uint32, c <-chan interface{}) (nbytes int64, nmsgs int, err error) func WriteStringTo(w io.Writer, s string) (n int64, err error) func NewConn(rw io.ReadWriter, nbuf int, hup chan bool) Conn func NewPipe(nbuf int) Conn func NewPipePair(nbuf int) (Conn, Conn) func NewMux(rw io.ReadWriter, iscaller bool) *Mux func NewMuxPair() (*Mux, *Mux, error) type Byteser interface { ... } type CloseReader interface { ... } type CloseWriter interface { ... } type Conn struct { ... } func NewConn(rw io.ReadWriter, nbuf int, hup chan bool) Conn func NewPipe(nbuf int) Conn func NewPipePair(nbuf int) (Conn, Conn) type Ign struct { ... } type Mux struct { ... } func NewMux(rw io.ReadWriter, iscaller bool) *Mux func NewMuxPair() (*Mux, *Mux, error) type Typer interface { ... } type Unpacker interface { ... } DESCRIPTION Channels that can go through external I/O devices for Clive. The protocol used in the device permits muxing of multiple channels within a single connection. In the connection, messages exchanged use the format: size[4] tag[2] type[2] data[size] Here, a tag identifies a channel and type identifies the type of data exchanged. CONSTANTS const ( Tnone uint16 = iota Tbytes // byte[], used as data Tign // byte[], ignored as data Tstr // string Terr // error string Taddr // file address (name, ln, ch) Tdir // map[string]string, directory entry Tzx // zx protocol msg Tusr // first user defined type value ) Message types. It is ok for the user to define new types. By convention, unknown message types are to be forwarded as-is by processes piping data along with actual data being processed. For any unknown type, Bytes(), WriteTo(), and String() are used if they exist, if they don't, the type is discarded. In this case, the type is Tign unless a TypeId() method exists to return the type id to be sent. const ( // Maximum supported msg sz MaxMsgSz = 64 * 1024 // Maximum supported len(Dir) MaxDirSz = 1024 ) TYPES type Byteser interface { Bytes() []byte } type CloseReader interface { CloseRead() error } See NewConn. type CloseWriter interface { CloseWrite() error } See NewConn. type Conn struct { Tag string // debug In <-chan interface{} Out chan<- interface{} } A Conn is a channel-pair used as a duplex connection. The tag may be used for debugging or to convey the address of the other end of the connection. func NewConn(rw io.ReadWriter, nbuf int, hup chan bool) Conn Create a Conn to perform msg I/O through the given device. If r/w implements CloseReader/CloseWriter, half closes are used. Note that TCP has half closes but TLS does not. Otherwise, if Close() is implemented, the end of the reading or writing processes cause a close on the entire connection. Error messages are propagated like everybody else and do not cause a break. I/O errors (and the like) on the device do cause the connection to break and the error is propagated if possible. If hup is not nil, it is closed when rw is closed. func NewPipe(nbuf int) Conn Creates an io.Pipe with a Conn interface, using channels with nbuf elements of buffering. func NewPipePair(nbuf int) (Conn, Conn) Returns two Conns piped to each other. The chans involved all have nbuf elements of buffering. Useful for debugging or to replace the network. type Ign struct { Typ uint16 Dat []byte } byte[] messages ignored as data. type Mux struct { In <-chan Conn // new connections are sent here Hup <-chan bool // closed upon device hang up dbg.Flag // contains filtered or unexported fields } A Mux is a multiplexed set of channels on a duplex connection. It relies on Conns to perform I/O, but permits multiple Conns to be active on the same underlying device. There is flow control and it is ok for any of the mux clients to cease reading for a while, and to stream a bunch of data, other connections will be able to stream their data at the same time. func NewMux(rw io.ReadWriter, iscaller bool) *Mux Create a Mux on the given underlying device. One end of the device must be the caller and the other the callee. It does not matter which end is each one. When I/O ceases due to errors or the mux being closed, the underlying device is closed if it implements io.Closer. No half-closes are ever used. func NewMuxPair() (*Mux, *Mux, error) Create a pair of (os) piped muxes func (m *Mux) Close() Cease I/O in this mux and release all resources. func (m *Mux) Out() Conn Ask for a channel to send an output stream to the other end. There is no reply for the request stream. func (m *Mux) Rpc() Conn Ask for a channel to send an output stream that expects an input stream as its reply. type Typer interface { TypeId() uint16 } type Unpacker interface { Typer Unpack([]byte) (interface{}, error) } For user defined types, implementors of this interface use their own make function to make values of the message type upon reception. FUNCTIONS func DefType(x Unpacker) Define a user type to be sent through chans Should be used only at init time. func GroupBytes(in <-chan interface{}, ival time.Duration, size int) <-chan interface{} Group bytes from the input channel so data is sent at most every ival or when the given size is reached. Useful to collect command output and display it for the user without issuing a single write for each msg in the input. func Merge(in ...<-chan interface{}) <-chan interface{} Merge input channels: msgs received from in are sent to a single channel func ReadBytes(r io.Reader, c chan<- interface{}) (nbytes int64, nmsgs int, err error) Read bytes from a external reader and send them as messages through c The chan is not closed, the caller may close(c, err) upon return. func ReadMsg(r io.Reader) (n int, tag uint32, m interface{}, err error) Read a message and return the number of bytes, the msg, and its tag. If the message is an error, it is returned in in the interface. Errors while reading from r are returned using the error instead. EOF is reported using io.EOF; but it's not an error. func ReadMsgs(r io.Reader, c chan<- interface{}) (nbytes int64, nmsgs int, err error) Read messages from a external reader and send them through c Error messages are forwarded. The chan is not closed, the caller may close(c, err) upon return. func UnpackString(b []byte) ([]byte, string, error) func WriteBytes(w io.Writer, c <-chan interface{}) (nbytes int64, nmsgs int, err error) Write []byte messages to an external writer, ignoring everything else. Error messages are ignored (the first one is used as the return sts). func WriteMsg(w io.Writer, tag uint32, m interface{}) (int64, error) Write []byte, or Ign, string, error, Stringer, Byteser or discard the write. If the write is discarded, ErrDiscarded is returned. func WriteMsgs(w io.Writer, tag uint32, c <-chan interface{}) (nbytes int64, nmsgs int, err error) Write messages received from c through an external writer with the given tag. The chan is not closed, the caller may close(c, err) upon return. Error messages are also propagated. The cerror of c, if not nil, is also written as an error message. func WriteStringTo(w io.Writer, s string) (n int64, err error) VARIABLES var ( ErrTooLarge = errors.New("message size is too large") ErrTooSmall = errors.New("truncated message") ErrAlready = errors.New("type already defined") ErrDiscarded = errors.New("msg write discarded") ErrIO = errors.New("i/o error") // Msg size for []byte readers MsgSz = 16 * 1024 ) var ( ErrBadPeer = errors.New("both peers are caller/callee") )
Clive, 2nd ed. User's manual. Section 2