package main import ( "bufio" "fmt" "io" "net" ) type NetConn struct { netReader *bufio.Reader conn net.Conn netReadChan chan rune hangup chan struct{} paused bool connected bool } func NewNetConn(addr string) (*NetConn, error) { c := &NetConn{} var err error c.conn, err = net.Dial("tcp", addr) if err != nil { return nil, err } c.connected = true c.netReader = bufio.NewReader(c.conn) c.netReadChan = make(chan rune) c.hangup = make(chan struct{}) c.paused = false go func() { for { r, l, err := c.netReader.ReadRune() if err != nil && err != io.EOF { c.cleanup() return } if c.paused || l == 0 { select { case <-c.hangup: c.cleanup() return default: // discard } } else { select { case c.netReadChan <- r: case <-c.hangup: c.cleanup() return } } } }() return c, nil } func (c *NetConn) Write(r rune) error { if c == nil { return fmt.Errorf("NetConn not initialized") } _, err := c.conn.Write([]byte(string(r))) if err != nil { close(c.hangup) } return err } func (c *NetConn) Hangup() { if c == nil { return } c.conn.Close() close(c.hangup) } func (c *NetConn) cleanup() { close(c.netReadChan) c.connected = false } func (c *NetConn) Pause() { if c == nil { return } c.paused = true } func (c *NetConn) Resume() { if c == nil { return } c.paused = false } func (c *NetConn) OutputChannel() chan rune { if c == nil { return nil } return c.netReadChan } func (c *NetConn) Connected() bool { if c == nil { return false } return c.connected }