|
@@ -10,27 +10,33 @@ import (
|
|
"os"
|
|
"os"
|
|
"runtime"
|
|
"runtime"
|
|
"strings"
|
|
"strings"
|
|
|
|
+ "sync"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
"git.nspix.com/golang/micro/helper/net/ip"
|
|
"git.nspix.com/golang/micro/helper/net/ip"
|
|
bytepkg "git.nspix.com/golang/micro/helper/pool/byte"
|
|
bytepkg "git.nspix.com/golang/micro/helper/pool/byte"
|
|
- "git.nspix.com/golang/micro/helper/unsafestr"
|
|
|
|
"github.com/peterh/liner"
|
|
"github.com/peterh/liner"
|
|
)
|
|
)
|
|
|
|
|
|
type Client struct {
|
|
type Client struct {
|
|
|
|
+ seq uint16
|
|
appName string
|
|
appName string
|
|
conn net.Conn
|
|
conn net.Conn
|
|
context context.Context
|
|
context context.Context
|
|
readyChan chan struct{}
|
|
readyChan chan struct{}
|
|
completerChan chan *Frame
|
|
completerChan chan *Frame
|
|
responseChan chan *Frame
|
|
responseChan chan *Frame
|
|
|
|
+ mutex sync.Mutex
|
|
}
|
|
}
|
|
|
|
|
|
func (client *Client) writePack(packet *Frame) (err error) {
|
|
func (client *Client) writePack(packet *Frame) (err error) {
|
|
if packet.Timestamp == 0 {
|
|
if packet.Timestamp == 0 {
|
|
packet.Timestamp = time.Now().Unix()
|
|
packet.Timestamp = time.Now().Unix()
|
|
}
|
|
}
|
|
|
|
+ client.mutex.Lock()
|
|
|
|
+ client.seq++
|
|
|
|
+ packet.Seq = client.seq
|
|
|
|
+ client.mutex.Unlock()
|
|
err = writeFrame(client.conn, packet)
|
|
err = writeFrame(client.conn, packet)
|
|
return
|
|
return
|
|
}
|
|
}
|
|
@@ -74,7 +80,10 @@ func (client *Client) rdyLoop(c chan error) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case PacketTypeData:
|
|
case PacketTypeData:
|
|
- client.responseChan <- packet
|
|
|
|
|
|
+ select {
|
|
|
|
+ case client.responseChan <- packet:
|
|
|
|
+ case <-time.After(time.Second):
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
select {
|
|
select {
|
|
@@ -83,6 +92,35 @@ func (client *Client) rdyLoop(c chan error) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func (client *Client) waitResponse(ctx context.Context, seq uint16) (err error) {
|
|
|
|
+ childCtx, cancelFunc := context.WithTimeout(ctx, time.Second*30)
|
|
|
|
+ defer func() {
|
|
|
|
+ cancelFunc()
|
|
|
|
+ }()
|
|
|
|
+ for {
|
|
|
|
+ select {
|
|
|
|
+ case <-childCtx.Done():
|
|
|
|
+ err = client.context.Err()
|
|
|
|
+ return
|
|
|
|
+ case res, ok := <-client.responseChan:
|
|
|
|
+ if !ok {
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ if res.Seq == seq {
|
|
|
|
+ if res.Error != "" {
|
|
|
|
+ client.stdout(res.Error, EOL)
|
|
|
|
+ } else {
|
|
|
|
+ client.stdout(string(bytes.Trim(res.Data, "\r\n")))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if res.Flag == FlagComplete {
|
|
|
|
+ client.stdout(EOL)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
func (client *Client) interactive(c chan error) {
|
|
func (client *Client) interactive(c chan error) {
|
|
var (
|
|
var (
|
|
err error
|
|
err error
|
|
@@ -116,35 +154,18 @@ func (client *Client) interactive(c chan error) {
|
|
client.stdout("\033[2J")
|
|
client.stdout("\033[2J")
|
|
continue
|
|
continue
|
|
}
|
|
}
|
|
- if err = client.writePack(&Frame{Type: PacketTypeData, Data: []byte(line)}); err != nil {
|
|
|
|
|
|
+ reqFrame := newFrame(PacketTypeData, FlagComplete, []byte(line))
|
|
|
|
+ if err = client.writePack(reqFrame); err != nil {
|
|
break
|
|
break
|
|
}
|
|
}
|
|
state.AppendHistory(line)
|
|
state.AppendHistory(line)
|
|
- select {
|
|
|
|
- case <-client.context.Done():
|
|
|
|
- err = client.context.Err()
|
|
|
|
- return
|
|
|
|
- case <-time.After(time.Second * 30):
|
|
|
|
- client.stdout("io timeout", EOL)
|
|
|
|
- case res, ok := <-client.responseChan:
|
|
|
|
- if !ok {
|
|
|
|
- break
|
|
|
|
- }
|
|
|
|
- if res.Error != "" {
|
|
|
|
- client.stdout(res.Error, EOL)
|
|
|
|
- } else {
|
|
|
|
- client.stdout(string(bytes.Trim(res.Data, "\r\n")), EOL)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ client.waitResponse(client.context, reqFrame.Seq)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func (client *Client) CompleterHandleFunc(str string) (ss []string) {
|
|
func (client *Client) CompleterHandleFunc(str string) (ss []string) {
|
|
var err error
|
|
var err error
|
|
- if err = client.writePack(&Frame{
|
|
|
|
- Type: PacketTypeCompleter,
|
|
|
|
- Data: unsafestr.StringToBytes(str),
|
|
|
|
- }); err != nil {
|
|
|
|
|
|
+ if err = client.writePack(newFrame(PacketTypeCompleter, FlagComplete, []byte(str))); err != nil {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
select {
|
|
select {
|
|
@@ -169,9 +190,7 @@ func (client *Client) Run() (err error) {
|
|
defer func() {
|
|
defer func() {
|
|
_ = client.conn.Close()
|
|
_ = client.conn.Close()
|
|
}()
|
|
}()
|
|
- if err = client.writePack(&Frame{
|
|
|
|
- Type: PacketTypeEcho,
|
|
|
|
- }); err != nil {
|
|
|
|
|
|
+ if err = client.writePack(newFrame(PacketTypeEcho, FlagComplete, nil)); err != nil {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
client.stdout("connecting")
|
|
client.stdout("connecting")
|
|
@@ -201,7 +220,7 @@ func ExecuteContext(ctx context.Context, conn net.Conn, cmd string) (s string, e
|
|
if frame, err = nextFrame(conn); err != nil {
|
|
if frame, err = nextFrame(conn); err != nil {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
- if err = cli.writePack(&Frame{Type: PacketTypeData, Data: []byte(cmd)}); err != nil {
|
|
|
|
|
|
+ if err = cli.writePack(newFrame(PacketTypeData, FlagComplete, []byte(cmd))); err != nil {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
if frame, err = nextFrame(conn); err != nil {
|
|
if frame, err = nextFrame(conn); err != nil {
|