168 lines
3.0 KiB
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)))
|
||
|
}
|
||
|
}
|
||
|
}
|