|
|
|
|
@ -3,18 +3,22 @@ package main |
|
|
|
|
import ( |
|
|
|
|
"bytes" |
|
|
|
|
"encoding/json" |
|
|
|
|
"errors" |
|
|
|
|
"flag" |
|
|
|
|
"fmt" |
|
|
|
|
"io/ioutil" |
|
|
|
|
"log" |
|
|
|
|
"net/http" |
|
|
|
|
"os" |
|
|
|
|
"sort" |
|
|
|
|
"strings" |
|
|
|
|
"sync" |
|
|
|
|
|
|
|
|
|
"github.com/BurntSushi/toml" |
|
|
|
|
"github.com/awesome-gocui/gocui" |
|
|
|
|
"github.com/curusarn/resh/pkg/cfg" |
|
|
|
|
"github.com/curusarn/resh/pkg/msg" |
|
|
|
|
"github.com/curusarn/resh/pkg/records" |
|
|
|
|
|
|
|
|
|
"os/user" |
|
|
|
|
"path/filepath" |
|
|
|
|
@ -31,18 +35,35 @@ func main() { |
|
|
|
|
usr, _ := user.Current() |
|
|
|
|
dir := usr.HomeDir |
|
|
|
|
configPath := filepath.Join(dir, "/.config/resh.toml") |
|
|
|
|
logPath := filepath.Join(dir, ".resh/cli.log") |
|
|
|
|
|
|
|
|
|
f, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Fatal("Error opening file:", err) |
|
|
|
|
} |
|
|
|
|
defer f.Close() |
|
|
|
|
|
|
|
|
|
log.SetOutput(f) |
|
|
|
|
|
|
|
|
|
var config cfg.Config |
|
|
|
|
if _, err := toml.DecodeFile(configPath, &config); err != nil { |
|
|
|
|
log.Fatal("Error reading config:", err) |
|
|
|
|
} |
|
|
|
|
if config.Debug { |
|
|
|
|
// Debug = true
|
|
|
|
|
log.SetFlags(log.LstdFlags | log.Lmicroseconds) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sessionID := flag.String("sessionID", "", "resh generated session id") |
|
|
|
|
pwd := flag.String("pwd", "", "present working directory") |
|
|
|
|
flag.Parse() |
|
|
|
|
|
|
|
|
|
if *sessionID == "" { |
|
|
|
|
fmt.Println("Error: you need to specify sessionId") |
|
|
|
|
} |
|
|
|
|
if *pwd == "" { |
|
|
|
|
fmt.Println("Error: you need to specify PWD") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
g, err := gocui.NewGui(gocui.OutputNormal, false) |
|
|
|
|
if err != nil { |
|
|
|
|
@ -53,18 +74,22 @@ func main() { |
|
|
|
|
g.Cursor = true |
|
|
|
|
g.SelFgColor = gocui.ColorGreen |
|
|
|
|
// g.SelBgColor = gocui.ColorGreen
|
|
|
|
|
g.Highlight = false |
|
|
|
|
g.Highlight = true |
|
|
|
|
|
|
|
|
|
mess := msg.InspectMsg{SessionID: *sessionID, Count: 40} |
|
|
|
|
resp := SendInspectMsg(mess, strconv.Itoa(config.Port)) |
|
|
|
|
mess := msg.DumpMsg{ |
|
|
|
|
SessionID: *sessionID, |
|
|
|
|
PWD: *pwd, |
|
|
|
|
} |
|
|
|
|
resp := SendDumpMsg(mess, strconv.Itoa(config.Port)) |
|
|
|
|
|
|
|
|
|
st := state{ |
|
|
|
|
// lock sync.Mutex
|
|
|
|
|
dataOriginal: resp.CmdLines, |
|
|
|
|
data: resp.CmdLines, |
|
|
|
|
fullRecords: resp.FullRecords, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
layout := manager{ |
|
|
|
|
sessionID: *sessionID, |
|
|
|
|
pwd: *pwd, |
|
|
|
|
config: config, |
|
|
|
|
s: &st, |
|
|
|
|
} |
|
|
|
|
@ -86,6 +111,7 @@ func main() { |
|
|
|
|
log.Panicln(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
layout.UpdateData("") |
|
|
|
|
err = g.MainLoop() |
|
|
|
|
if err != nil && gocui.IsQuit(err) == false { |
|
|
|
|
log.Panicln(err) |
|
|
|
|
@ -93,20 +119,224 @@ func main() { |
|
|
|
|
layout.Output() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// returns the number of hits for query
|
|
|
|
|
func queryHits(cmdline string, queryTerms []string) int { |
|
|
|
|
func leftCutPadString(str string, newLen int) string { |
|
|
|
|
dots := "…" |
|
|
|
|
strLen := len(str) |
|
|
|
|
if newLen > strLen { |
|
|
|
|
return strings.Repeat(" ", newLen-strLen) + str |
|
|
|
|
} else if newLen < strLen { |
|
|
|
|
return dots + str[strLen-newLen+1:] |
|
|
|
|
} |
|
|
|
|
return str |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func rightCutPadString(str string, newLen int) string { |
|
|
|
|
dots := "…" |
|
|
|
|
strLen := len(str) |
|
|
|
|
if newLen > strLen { |
|
|
|
|
return str + strings.Repeat(" ", newLen-strLen) |
|
|
|
|
} else if newLen < strLen { |
|
|
|
|
return str[:newLen-1] + dots |
|
|
|
|
} |
|
|
|
|
return str |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func cleanHighlight(str string) string { |
|
|
|
|
prefix := "\033[" |
|
|
|
|
|
|
|
|
|
invert := "\033[32;7;1m" |
|
|
|
|
end := "\033[0m" |
|
|
|
|
blueBold := "\033[34;1m" |
|
|
|
|
redBold := "\033[31;1m" |
|
|
|
|
repace := []string{invert, end, blueBold, redBold} |
|
|
|
|
if strings.Contains(str, prefix) == false { |
|
|
|
|
return str |
|
|
|
|
} |
|
|
|
|
for _, escSeq := range repace { |
|
|
|
|
str = strings.ReplaceAll(str, escSeq, "") |
|
|
|
|
} |
|
|
|
|
return str |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func highlightSelected(str string) string { |
|
|
|
|
// template "\033[3%d;%dm"
|
|
|
|
|
invert := "\033[32;7;1m" |
|
|
|
|
end := "\033[0m" |
|
|
|
|
return invert + cleanHighlight(str) + end |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func highlightMatchAlternative(str string) string { |
|
|
|
|
// template "\033[3%d;%dm"
|
|
|
|
|
blueBold := "\033[34;1m" |
|
|
|
|
end := "\033[0m" |
|
|
|
|
return blueBold + cleanHighlight(str) + end |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func highlightMatch(str string) string { |
|
|
|
|
// template "\033[3%d;%dm"
|
|
|
|
|
redBold := "\033[31;1m" |
|
|
|
|
end := "\033[0m" |
|
|
|
|
return redBold + cleanHighlight(str) + end |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func toString(record records.EnrichedRecord, lineLength int) string { |
|
|
|
|
dirColWidth := 24 // make this dynamic somehow
|
|
|
|
|
return leftCutPadString(strings.Replace(record.Pwd, record.Home, "~", 1), dirColWidth) + " " + |
|
|
|
|
rightCutPadString(strings.ReplaceAll(record.CmdLine, "\n", "; "), lineLength-dirColWidth-3) + "\n" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type query struct { |
|
|
|
|
terms []string |
|
|
|
|
pwd string |
|
|
|
|
// pwdTilde string
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func isValidTerm(term string) bool { |
|
|
|
|
if len(term) == 0 { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
if strings.Contains(term, " ") { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func filterTerms(terms []string) []string { |
|
|
|
|
var newTerms []string |
|
|
|
|
for _, term := range terms { |
|
|
|
|
if isValidTerm(term) { |
|
|
|
|
newTerms = append(newTerms, term) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return newTerms |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func newQueryFromString(queryInput string, pwd string) query { |
|
|
|
|
log.Println("QUERY input = <" + queryInput + ">") |
|
|
|
|
terms := strings.Fields(queryInput) |
|
|
|
|
var logStr string |
|
|
|
|
for _, term := range terms { |
|
|
|
|
logStr += " <" + term + ">" |
|
|
|
|
} |
|
|
|
|
log.Println("QUERY raw terms =" + logStr) |
|
|
|
|
terms = filterTerms(terms) |
|
|
|
|
logStr = "" |
|
|
|
|
for _, term := range terms { |
|
|
|
|
logStr += " <" + term + ">" |
|
|
|
|
} |
|
|
|
|
log.Println("QUERY filtered terms =" + logStr) |
|
|
|
|
log.Println("QUERY pwd =" + pwd) |
|
|
|
|
return query{terms: terms, pwd: pwd} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type item struct { |
|
|
|
|
// record records.EnrichedRecord
|
|
|
|
|
display string |
|
|
|
|
displayNoColor string |
|
|
|
|
cmdLine string |
|
|
|
|
pwd string |
|
|
|
|
pwdTilde string |
|
|
|
|
hits int |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (i item) less(i2 item) bool { |
|
|
|
|
// reversed order
|
|
|
|
|
return i.hits > i2.hits |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// used for deduplication
|
|
|
|
|
func (i item) key() string { |
|
|
|
|
unlikelySeparator := "|||||" |
|
|
|
|
return i.cmdLine + unlikelySeparator + i.pwd |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// func (i item) equals(i2 item) bool {
|
|
|
|
|
// return i.cmdLine == i2.cmdLine && i.pwd == i2.pwd
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// newItemFromRecordForQuery creates new item from record based on given query
|
|
|
|
|
// returns error if the query doesn't match the record
|
|
|
|
|
func newItemFromRecordForQuery(record records.EnrichedRecord, query query) (item, error) { |
|
|
|
|
// TODO: use color to highlight matches
|
|
|
|
|
hits := 0 |
|
|
|
|
for _, term := range queryTerms { |
|
|
|
|
if strings.Contains(cmdline, term) { |
|
|
|
|
cmd := record.CmdLine |
|
|
|
|
pwdTilde := strings.Replace(record.Pwd, record.Home, "~", 1) |
|
|
|
|
pwdDisp := leftCutPadString(pwdTilde, 25) |
|
|
|
|
pwdRawDisp := leftCutPadString(record.Pwd, 25) |
|
|
|
|
var useRawPwd bool |
|
|
|
|
for _, term := range query.terms { |
|
|
|
|
if strings.Contains(record.CmdLine, term) { |
|
|
|
|
hits++ |
|
|
|
|
cmd = strings.ReplaceAll(cmd, term, highlightMatch(term)) |
|
|
|
|
// NO continue
|
|
|
|
|
} |
|
|
|
|
if strings.Contains(pwdTilde, term) { |
|
|
|
|
hits++ |
|
|
|
|
pwdDisp = strings.ReplaceAll(pwdDisp, term, highlightMatch(term)) |
|
|
|
|
useRawPwd = false |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if strings.Contains(record.Pwd, term) { |
|
|
|
|
hits++ |
|
|
|
|
pwdRawDisp = strings.ReplaceAll(pwdRawDisp, term, highlightMatch(term)) |
|
|
|
|
useRawPwd = true |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
// if strings.Contains(record.GitOriginRemote, term) {
|
|
|
|
|
// hits++
|
|
|
|
|
// }
|
|
|
|
|
} |
|
|
|
|
// actual pwd matches
|
|
|
|
|
if record.Pwd == query.pwd { |
|
|
|
|
hits++ |
|
|
|
|
pwdDisp = highlightMatchAlternative(pwdDisp) |
|
|
|
|
pwdRawDisp = highlightMatchAlternative(pwdRawDisp) |
|
|
|
|
useRawPwd = false |
|
|
|
|
} |
|
|
|
|
return hits |
|
|
|
|
if hits == 0 { |
|
|
|
|
return item{}, errors.New("no match for given record and query") |
|
|
|
|
} |
|
|
|
|
display := " " |
|
|
|
|
// pwd := leftCutPadString("<"+pwdTilde+">", 20)
|
|
|
|
|
if useRawPwd { |
|
|
|
|
display += pwdRawDisp |
|
|
|
|
} else { |
|
|
|
|
display += pwdDisp |
|
|
|
|
} |
|
|
|
|
hitsDisp := " " + rightCutPadString(strconv.Itoa(hits), 2) |
|
|
|
|
display += hitsDisp |
|
|
|
|
// cmd := "<" + strings.ReplaceAll(record.CmdLine, "\n", ";") + ">"
|
|
|
|
|
cmd = strings.ReplaceAll(cmd, "\n", ";") |
|
|
|
|
display += cmd |
|
|
|
|
// itDummy := item{
|
|
|
|
|
// cmdLine: record.CmdLine,
|
|
|
|
|
// pwd: record.Pwd,
|
|
|
|
|
// }
|
|
|
|
|
// + " #K:<" + itDummy.key() + ">"
|
|
|
|
|
|
|
|
|
|
it := item{ |
|
|
|
|
display: display, |
|
|
|
|
displayNoColor: display, |
|
|
|
|
cmdLine: record.CmdLine, |
|
|
|
|
pwd: record.Pwd, |
|
|
|
|
pwdTilde: pwdTilde, |
|
|
|
|
hits: hits, |
|
|
|
|
} |
|
|
|
|
return it, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func doHighlightString(str string, minLength int) string { |
|
|
|
|
str = "> " + string(str[2:]) |
|
|
|
|
if len(str) < minLength { |
|
|
|
|
str = str + strings.Repeat(" ", minLength-len(str)) |
|
|
|
|
} |
|
|
|
|
return highlightSelected(str) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type state struct { |
|
|
|
|
dataOriginal []string |
|
|
|
|
data []string |
|
|
|
|
lock sync.Mutex |
|
|
|
|
fullRecords []records.EnrichedRecord |
|
|
|
|
data []item |
|
|
|
|
highlightedItem int |
|
|
|
|
|
|
|
|
|
outputBuffer string |
|
|
|
|
@ -114,46 +344,80 @@ type state struct { |
|
|
|
|
|
|
|
|
|
type manager struct { |
|
|
|
|
sessionID string |
|
|
|
|
pwd string |
|
|
|
|
config cfg.Config |
|
|
|
|
|
|
|
|
|
s *state |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m manager) Output() { |
|
|
|
|
m.s.lock.Lock() |
|
|
|
|
defer m.s.lock.Unlock() |
|
|
|
|
if len(m.s.outputBuffer) > 0 { |
|
|
|
|
fmt.Print(m.s.outputBuffer) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m manager) SelectExecute(g *gocui.Gui, v *gocui.View) error { |
|
|
|
|
m.s.lock.Lock() |
|
|
|
|
defer m.s.lock.Unlock() |
|
|
|
|
if m.s.highlightedItem < len(m.s.data) { |
|
|
|
|
m.s.outputBuffer = m.s.data[m.s.highlightedItem] |
|
|
|
|
m.s.outputBuffer = m.s.data[m.s.highlightedItem].cmdLine + "\n" |
|
|
|
|
return gocui.ErrQuit |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m manager) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) { |
|
|
|
|
gocui.DefaultEditor.Edit(v, key, ch, mod) |
|
|
|
|
query := v.Buffer() |
|
|
|
|
terms := strings.Split(query, " ") |
|
|
|
|
var dataHits []int |
|
|
|
|
m.s.data = nil |
|
|
|
|
for _, entry := range m.s.dataOriginal { |
|
|
|
|
hits := queryHits(entry, terms) |
|
|
|
|
if hits > 0 { |
|
|
|
|
m.s.data = append(m.s.data, entry) |
|
|
|
|
dataHits = append(dataHits, hits) |
|
|
|
|
func (m manager) UpdateData(input string) { |
|
|
|
|
log.Println("EDIT start") |
|
|
|
|
log.Println("len(fullRecords) =", len(m.s.fullRecords)) |
|
|
|
|
log.Println("len(data) =", len(m.s.data)) |
|
|
|
|
query := newQueryFromString(input, m.pwd) |
|
|
|
|
var data []item |
|
|
|
|
itemSet := make(map[string]bool) |
|
|
|
|
m.s.lock.Lock() |
|
|
|
|
defer m.s.lock.Unlock() |
|
|
|
|
for _, rec := range m.s.fullRecords { |
|
|
|
|
itm, err := newItemFromRecordForQuery(rec, query) |
|
|
|
|
if err != nil { |
|
|
|
|
// records didn't match the query
|
|
|
|
|
// log.Println(" * continue (no match)", rec.Pwd)
|
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if itemSet[itm.key()] { |
|
|
|
|
// log.Println(" * continue (already present)", itm.key(), itm.pwd)
|
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
itemSet[itm.key()] = true |
|
|
|
|
data = append(data, itm) |
|
|
|
|
// log.Println("DATA =", itm.display)
|
|
|
|
|
} |
|
|
|
|
sort.SliceStable(m.s.data, func(p, q int) bool { |
|
|
|
|
return dataHits[p] > dataHits[q] |
|
|
|
|
log.Println("len(tmpdata) =", len(data)) |
|
|
|
|
sort.SliceStable(data, func(p, q int) bool { |
|
|
|
|
return data[p].hits > data[q].hits |
|
|
|
|
}) |
|
|
|
|
m.s.data = nil |
|
|
|
|
for _, itm := range data { |
|
|
|
|
if len(m.s.data) > 420 { |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
m.s.data = append(m.s.data, itm) |
|
|
|
|
} |
|
|
|
|
m.s.highlightedItem = 0 |
|
|
|
|
log.Println("len(fullRecords) =", len(m.s.fullRecords)) |
|
|
|
|
log.Println("len(data) =", len(m.s.data)) |
|
|
|
|
log.Println("EDIT end") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m manager) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) { |
|
|
|
|
gocui.DefaultEditor.Edit(v, key, ch, mod) |
|
|
|
|
m.UpdateData(v.Buffer()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m manager) Next(g *gocui.Gui, v *gocui.View) error { |
|
|
|
|
_, y := g.Size() |
|
|
|
|
m.s.lock.Lock() |
|
|
|
|
defer m.s.lock.Unlock() |
|
|
|
|
if m.s.highlightedItem < y { |
|
|
|
|
m.s.highlightedItem++ |
|
|
|
|
} |
|
|
|
|
@ -161,6 +425,8 @@ func (m manager) Next(g *gocui.Gui, v *gocui.View) error { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m manager) Prev(g *gocui.Gui, v *gocui.View) error { |
|
|
|
|
m.s.lock.Lock() |
|
|
|
|
defer m.s.lock.Unlock() |
|
|
|
|
if m.s.highlightedItem > 0 { |
|
|
|
|
m.s.highlightedItem-- |
|
|
|
|
} |
|
|
|
|
@ -190,15 +456,36 @@ func (m manager) Layout(g *gocui.Gui) error { |
|
|
|
|
log.Panicln(err.Error()) |
|
|
|
|
} |
|
|
|
|
v.Frame = false |
|
|
|
|
v.Autoscroll = true |
|
|
|
|
v.Autoscroll = false |
|
|
|
|
v.Clear() |
|
|
|
|
for _, cmdLine := range m.s.data { |
|
|
|
|
entry := strings.Trim(cmdLine, "\n") + "\n" |
|
|
|
|
v.WriteString(entry) |
|
|
|
|
} |
|
|
|
|
if m.s.highlightedItem < len(m.s.data) { |
|
|
|
|
v.SetHighlight(m.s.highlightedItem, true) |
|
|
|
|
v.Rewind() |
|
|
|
|
|
|
|
|
|
m.s.lock.Lock() |
|
|
|
|
defer m.s.lock.Unlock() |
|
|
|
|
for i, itm := range m.s.data { |
|
|
|
|
if i == maxY { |
|
|
|
|
log.Println(maxY) |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
displayStr := itm.display |
|
|
|
|
if m.s.highlightedItem == i { |
|
|
|
|
// use actual min requried length instead of 420 constant
|
|
|
|
|
displayStr = doHighlightString(displayStr, 420) |
|
|
|
|
log.Println("### HightlightedItem string :", displayStr) |
|
|
|
|
} else { |
|
|
|
|
log.Println(displayStr) |
|
|
|
|
} |
|
|
|
|
if strings.Contains(displayStr, "\n") { |
|
|
|
|
log.Println("display string contained \\n") |
|
|
|
|
displayStr = strings.ReplaceAll(displayStr, "\n", "#") |
|
|
|
|
} |
|
|
|
|
v.WriteString(displayStr + "\n") |
|
|
|
|
// if m.s.highlightedItem == i {
|
|
|
|
|
// v.SetHighlight(m.s.highlightedItem, true)
|
|
|
|
|
// }
|
|
|
|
|
} |
|
|
|
|
log.Println("len(data) =", len(m.s.data)) |
|
|
|
|
log.Println("highlightedItem =", m.s.highlightedItem) |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -206,14 +493,14 @@ func quit(g *gocui.Gui, v *gocui.View) error { |
|
|
|
|
return gocui.ErrQuit |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// SendInspectMsg to daemon
|
|
|
|
|
func SendInspectMsg(m msg.InspectMsg, port string) msg.MultiResponse { |
|
|
|
|
// SendDumpMsg to daemon
|
|
|
|
|
func SendDumpMsg(m msg.DumpMsg, port string) msg.DumpResponse { |
|
|
|
|
recJSON, err := json.Marshal(m) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Fatal("send err 1", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
req, err := http.NewRequest("POST", "http://localhost:"+port+"/inspect", |
|
|
|
|
req, err := http.NewRequest("POST", "http://localhost:"+port+"/dump", |
|
|
|
|
bytes.NewBuffer(recJSON)) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Fatal("send err 2", err) |
|
|
|
|
@ -232,7 +519,7 @@ func SendInspectMsg(m msg.InspectMsg, port string) msg.MultiResponse { |
|
|
|
|
log.Fatal("read response error") |
|
|
|
|
} |
|
|
|
|
// log.Println(string(body))
|
|
|
|
|
response := msg.MultiResponse{} |
|
|
|
|
response := msg.DumpResponse{} |
|
|
|
|
err = json.Unmarshal(body, &response) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Fatal("unmarshal resp error: ", err) |
|
|
|
|
|