status-go/vendor/gopkg.in/olebedev/go-duktape.v3/dbgsockettransport.go

168 lines
3.0 KiB
Go

package duktape
import (
"bufio"
"errors"
"fmt"
"io"
"net"
"sync"
"unsafe"
)
type SocketTransport struct {
ctx *Context
uData interface{}
requestFunc DebugRequestFunc
detachedFunc DebugDetachedFunc
listener net.Listener
closed bool
conn *connection
m sync.Mutex
}
type connection struct {
conn net.Conn
reader *bufio.Reader
writer *bufio.Writer
errorListener func(err error)
}
func NewSocketTransport(ctx *Context,
network, addr string,
requestFunc DebugRequestFunc,
detachedFunc DebugDetachedFunc,
uData interface{}) (*SocketTransport, error) {
listener, err := net.Listen(network, addr)
if err != nil {
return nil, err
}
return &SocketTransport{
ctx: ctx,
uData: uData,
requestFunc: requestFunc,
detachedFunc: detachedFunc,
listener: listener,
m: sync.Mutex{},
}, nil
}
func (s *SocketTransport) attach() error {
debugger := DukDebugger()
return debugger.Attach(
s.ctx,
s.conn.read,
s.conn.write,
s.conn.peek,
nil,
s.conn.writeFlush,
s.requestFunc,
s.detachedFunc,
s.uData,
)
}
func (s *SocketTransport) Close() error {
s.m.Lock()
defer s.m.Unlock()
s.closed = true
if s.conn != nil {
if err := s.conn.conn.Close(); err != nil {
return err
}
}
return s.listener.Close()
}
func (s *SocketTransport) Listen(errorListener func(err error)) {
acceptConnection := func(conn net.Conn) error {
s.m.Lock()
defer s.m.Unlock()
if s.closed {
return nil
}
if s.conn != nil {
return errors.New("only one debugger can be connected at a time")
}
c := &connection{
conn: conn,
reader: bufio.NewReader(conn),
writer: bufio.NewWriter(conn),
errorListener: errorListener,
}
s.conn = c
if err := s.attach(); err != nil {
return err
}
return nil
}
go func() {
for {
if s.closed {
return
}
accepted, err := s.listener.Accept()
if err != nil {
if errorListener != nil {
errorListener(err)
}
continue
}
if err := acceptConnection(accepted); err != nil {
if errorListener != nil {
errorListener(err)
}
}
}
}()
}
func (c *connection) read(uData unsafe.Pointer, buffer []byte) uint {
r, err := io.ReadAtLeast(c.reader, buffer, 1)
if err != nil {
if err != io.EOF {
if c.errorListener != nil {
c.errorListener(errors.New(fmt.Sprintf("could not read from socket: %v", err)))
}
}
return 0
}
return uint(r)
}
func (c *connection) write(uData unsafe.Pointer, buffer []byte) uint {
w, err := c.writer.Write(buffer)
if err != nil {
if c.errorListener != nil {
c.errorListener(errors.New(fmt.Sprintf("could not write to socket: %v", err)))
}
return 0
}
return uint(w)
}
func (c *connection) peek(uData unsafe.Pointer) uint {
return uint(c.reader.Buffered())
}
func (c *connection) writeFlush(uData unsafe.Pointer) {
if err := c.writer.Flush(); err != nil {
if c.errorListener != nil {
c.errorListener(errors.New(fmt.Sprintf("could not flush socket: %v", err)))
}
}
}