+++ /dev/null
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package fakenet
-
-import (
- "io"
- "net"
- "sync"
- "time"
-)
-
-// NewConn returns a net.Conn built on top of the supplied reader and writer.
-// It decouples the read and write on the conn from the underlying stream
-// to enable Close to abort ones that are in progress.
-// It's primary use is to fake a network connection from stdin and stdout.
-func NewConn(name string, in io.ReadCloser, out io.WriteCloser) net.Conn {
- c := &fakeConn{
- name: name,
- reader: newFeeder(in.Read),
- writer: newFeeder(out.Write),
- in: in,
- out: out,
- }
- go c.reader.run()
- go c.writer.run()
- return c
-}
-
-type fakeConn struct {
- name string
- reader *connFeeder
- writer *connFeeder
- in io.ReadCloser
- out io.WriteCloser
-}
-
-type fakeAddr string
-
-// connFeeder serializes calls to the source function (io.Reader.Read or
-// io.Writer.Write) by delegating them to a channel. This also allows calls to
-// be intercepted when the connection is closed, and cancelled early if the
-// connection is closed while the calls are still outstanding.
-type connFeeder struct {
- source func([]byte) (int, error)
- input chan []byte
- result chan feedResult
- mu sync.Mutex
- closed bool
- done chan struct{}
-}
-
-type feedResult struct {
- n int
- err error
-}
-
-func (c *fakeConn) Close() error {
- c.reader.close()
- c.writer.close()
- c.in.Close()
- c.out.Close()
- return nil
-}
-
-func (c *fakeConn) Read(b []byte) (n int, err error) { return c.reader.do(b) }
-func (c *fakeConn) Write(b []byte) (n int, err error) { return c.writer.do(b) }
-func (c *fakeConn) LocalAddr() net.Addr { return fakeAddr(c.name) }
-func (c *fakeConn) RemoteAddr() net.Addr { return fakeAddr(c.name) }
-func (c *fakeConn) SetDeadline(t time.Time) error { return nil }
-func (c *fakeConn) SetReadDeadline(t time.Time) error { return nil }
-func (c *fakeConn) SetWriteDeadline(t time.Time) error { return nil }
-func (a fakeAddr) Network() string { return "fake" }
-func (a fakeAddr) String() string { return string(a) }
-
-func newFeeder(source func([]byte) (int, error)) *connFeeder {
- return &connFeeder{
- source: source,
- input: make(chan []byte),
- result: make(chan feedResult),
- done: make(chan struct{}),
- }
-}
-
-func (f *connFeeder) close() {
- f.mu.Lock()
- if !f.closed {
- f.closed = true
- close(f.done)
- }
- f.mu.Unlock()
-}
-
-func (f *connFeeder) do(b []byte) (n int, err error) {
- // send the request to the worker
- select {
- case f.input <- b:
- case <-f.done:
- return 0, io.EOF
- }
- // get the result from the worker
- select {
- case r := <-f.result:
- return r.n, r.err
- case <-f.done:
- return 0, io.EOF
- }
-}
-
-func (f *connFeeder) run() {
- var b []byte
- for {
- // wait for an input request
- select {
- case b = <-f.input:
- case <-f.done:
- return
- }
- // invoke the underlying method
- n, err := f.source(b)
- // send the result back to the requester
- select {
- case f.result <- feedResult{n: n, err: err}:
- case <-f.done:
- return
- }
- }
-}