diff --git a/cmpSnipper/cmpSnipper.go b/cmpSnipper/cmpSnipper.go
index 4d46b2f..3b236ad 100644
--- a/cmpSnipper/cmpSnipper.go
+++ b/cmpSnipper/cmpSnipper.go
@@ -18,12 +18,15 @@
HttpCliDebug uint32
HttpCliSslVerify bool
+ CliCur *cmpWbsCliStruct
CliList []cmpWbsCliStruct
cmpSnipperHttpServ cmpSnipperHttpServ
Rand4d int
+ Ping2List []Ping2Struct
+
PlugList []cmpPluginStruct
SshList []cmpSshCliStruct
diff --git a/cmpSnipper/cmpSnipperHttpWsHandle.go b/cmpSnipper/cmpSnipperHttpWsHandle.go
index 73098f5..6fce4fe 100644
--- a/cmpSnipper/cmpSnipperHttpWsHandle.go
+++ b/cmpSnipper/cmpSnipperHttpWsHandle.go
@@ -3,6 +3,7 @@
import (
"time"
+ "sync"
"net/http"
"github.com/gorilla/websocket"
@@ -11,6 +12,7 @@
type cmpWbsCliStruct struct {
W http.ResponseWriter
Connect *websocket.Conn
+ Mutex sync.Mutex
HostPort string
}
@@ -44,9 +46,12 @@
app.Log("New client: %s", HostPort)
+ var Mutex sync.Mutex
+
var cmpWbsCli cmpWbsCliStruct = cmpWbsCliStruct{
w,
conn,
+ Mutex,
HostPort,
}
@@ -107,14 +112,16 @@
}
} else {
out["error"] = "Unknown snip"
- app.Log("Unknow snip:", inp["snip"])
+ app.Log("Unknow snip: %s", inp["snip"])
}
-
- err = conn.WriteJSON(out)
+/*
+ err = conn.Write-JSON(out)
if err != nil {
app.Log(err)
}
+*/
+ app.HttpWebSockSendRawTo(cmpWbsCli, out)
// for
}
@@ -122,21 +129,34 @@
return
}
- func (app *App) HttpWebSockSendTo(cmpWbsCli cmpWbsCliStruct, snip string, result map[string]interface{}) {
+ func (app *App) HttpWebSockSendRawTo(cmpWbsCli cmpWbsCliStruct, raw map[string]interface{}) {
var err error
- out := map[string]interface{}{
- "snip": snip,
- "result": result,
- }
+ app.Log("LOCK")
- err = cmpWbsCli.Connect.WriteJSON(out)
+ cmpWbsCli.Mutex.Lock()
+
+ defer cmpWbsCli.Mutex.Unlock()
+
+ err = cmpWbsCli.Connect.WriteJSON(raw)
if err != nil {
app.Log(err)
return
}
+ return
+
+ }
+
+ func (app *App) HttpWebSockSendTo(cmpWbsCli cmpWbsCliStruct, snip string, result map[string]interface{}) {
+ out := map[string]interface{}{
+ "snip": snip,
+ "result": result,
+ }
+
+ app.HttpWebSockSendRawTo(cmpWbsCli, out)
+
return
}
diff --git a/cmpSnipper/cmpSnipperSnip.go b/cmpSnipper/cmpSnipperSnip.go
index 76ac646..8c2a730 100644
--- a/cmpSnipper/cmpSnipperSnip.go
+++ b/cmpSnipper/cmpSnipperSnip.go
@@ -39,8 +39,12 @@
reflect.ValueOf(ifcIM),
}
+ app.CliCur = &cmpWbsCli
+
refOL := refMth.Call(refIL)
+ // app.CliCur = nil ???
+
infOI := refOL[0].Interface()
app.Log("Interface output item %+v", infOI)
diff --git a/cmpSnipper/cmpSnipperSnipLeftMenu.go b/cmpSnipper/cmpSnipperSnipLeftMenu.go
index e872313..7d08e4c 100644
--- a/cmpSnipper/cmpSnipperSnipLeftMenu.go
+++ b/cmpSnipper/cmpSnipperSnipLeftMenu.go
@@ -11,12 +11,14 @@
mainMenuFile, err := app.ConfGetStr("mainMenuFile")
if err != nil {
+ app.Log("Can't get config.mainMenuFile")
return nil, err
}
data, err := app.FileReadLimit(mainMenuFile, 1048576)
if err != nil {
+ app.Log("Can't read file '%s'", mainMenuFile)
return nil, err
}
diff --git a/cmpSnipper/cmpSnipperSnipPing.go b/cmpSnipper/cmpSnipperSnipPing.go
index 7393a80..a334930 100644
--- a/cmpSnipper/cmpSnipperSnipPing.go
+++ b/cmpSnipper/cmpSnipperSnipPing.go
@@ -2,6 +2,9 @@
package cmpSnipper
import (
+ "io"
+ "sync"
+ "strconv"
"os/exec"
"context"
"time"
@@ -9,6 +12,12 @@
"syscall"
)
+ type Ping2Struct struct {
+ Addr string
+ Win string
+ Pid int
+ }
+
func (app *App) PingSnip(parm any) (any, error) {
// log.Println("PingSnip")
@@ -68,3 +77,357 @@
"stderr" : stderr.String(),
}, nil
}
+
+
+func (app *App) copyAndCapture(r io.Reader, strWin string) ([]byte, error) {
+ var out []byte
+ buf := make([]byte, 1024, 1024)
+ for {
+ n, err := r.Read(buf[:])
+ if n > 0 {
+ d := buf[:n]
+ out = append(out, d...)
+ str := strings.Trim(string(d), "\n\r")
+
+ app.Log("Std: %s", str)
+
+ app.Ping2SendStr(str)
+ }
+ if err != nil {
+ // Read returns io.EOF at the end of file, which is not an error for us
+ if err == io.EOF {
+ err = nil
+ }
+ return out, err
+ }
+ }
+}
+
+ func (app *App) Ping2SendObj(obj map[string]interface{}) (error) {
+ if app.CliCur == nil {
+ app.Log("No cli")
+ return nil
+ }
+
+ app.HttpWebSockSendTo(*app.CliCur, "ping2Data", obj)
+
+ return nil
+ }
+
+ func (app *App) Ping2SendStr(str string) (error) {
+ return app.Ping2SendObj(map[string]interface{}{
+ "data" : "stdout",
+ "string": str,
+ })
+ }
+
+
+
+
+func (app *App) ping2Capture(r io.Reader, strWin string) ([]byte, error) {
+ var out []byte
+ buf := make([]byte, 1024, 1024)
+ for {
+ n, err := r.Read(buf[:])
+ if n > 0 {
+ d := buf[:n]
+ out = append(out, d...)
+ str := strings.Trim(string(d), "\n\r")
+
+ app.Log("Std: %s", str)
+
+ app.Ping2SendStr(str)
+ }
+ if err != nil {
+ // Read returns io.EOF at the end of file, which is not an error for us
+ if err == io.EOF {
+ err = nil
+ }
+ return out, err
+ }
+ }
+}
+
+
+ func (app *App) Ping2ExecStart(strAddr string, strWin string) (any, error) {
+ var Ping2Free *Ping2Struct = nil
+
+ for key, val := range app.Ping2List {
+ if val.Pid == 0 {
+ Ping2Free = &val
+ break
+ }
+
+ if val.Addr == strAddr {
+ app.Ping2List[key].Win = strWin
+
+ return map[string]interface{}{
+ "stutus" : "success",
+ }, nil
+ }
+ }
+
+ if Ping2Free == nil {
+ var NewPing2Struct Ping2Struct
+ Ping2Free = &NewPing2Struct
+ app.Ping2List = append(app.Ping2List, NewPing2Struct)
+ }
+
+ var err error
+
+ ctx, cancel := context.WithTimeout(context.Background(), 100 * time.Second)
+
+ defer cancel()
+
+ cmd := exec.CommandContext(ctx, "ping", "-c", "40", strAddr)
+
+ var stdout, stderr []byte
+ stdoutIn, _ := cmd.StdoutPipe()
+ stderrIn, _ := cmd.StderrPipe()
+
+ var exitCode int;
+
+ err = cmd.Start()
+
+ if err != nil {
+ app.Log(err)
+ return nil, err
+ }
+
+ Ping2Free.Addr = strAddr
+ Ping2Free.Win = strWin
+ Ping2Free.Pid = cmd.Process.Pid
+
+ go app.Ping2SendObj(map[string]interface{}{
+ "data" : "procid",
+ "procid": Ping2Free.Pid,
+ })
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ stdout, err = app.ping2Capture(stdoutIn, strWin)
+ wg.Done()
+ }()
+
+ stderr, err = app.ping2Capture(stderrIn, strWin)
+
+ wg.Wait()
+
+ err = cmd.Wait()
+
+ if err != nil {
+ // try to get the exit code
+ if exitError, ok := err.(*exec.ExitError); ok {
+ ws := exitError.Sys().(syscall.WaitStatus)
+ exitCode = ws.ExitStatus()
+ } else {
+ // This will happen (in OSX) if `name` is not available in $PATH,
+ // in this situation, exit code could not be get, and stderr will be
+ // empty string very likely, so we use the default fail code, and format err
+ // to string and set to stderr
+
+ app.Log("Could not get exit code for failed program")
+ exitCode = 255
+ }
+ } else {
+ // success, exitCode should be 0 if go is ok
+ ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
+ exitCode = ws.ExitStatus()
+ }
+
+ app.Log("Exit code %s", exitCode)
+
+ if false { /* ??? */
+ outStr, errStr := string(stdout), string(stderr)
+ app.Log("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
+ }
+
+ Ping2Free.Pid = 0
+
+ return map[string]interface{}{
+ "stutus" : "error",
+ "error" : "Invalid IPv4 address",
+ }, nil
+ }
+
+ func (app *App) Ping2ExecSign(strAddr string, strWin string, strSign string) (any, error) {
+ for _, val := range app.Ping2List {
+ if val.Pid == 0 {
+ continue
+ }
+
+ if val.Addr != strAddr {
+ continue
+ }
+
+
+ var err error
+
+ ctx, cancel := context.WithTimeout(context.Background(), 100 * time.Second)
+
+ defer cancel()
+
+ pidStr := strconv.Itoa(val.Pid)
+
+ app.Log("kill %s", pidStr)
+
+ cmd := exec.CommandContext(ctx, "kill", strSign, pidStr)
+
+ var exitCode int;
+
+ err = cmd.Run()
+
+ if err != nil {
+ // try to get the exit code
+ if exitError, ok := err.(*exec.ExitError); ok {
+ ws := exitError.Sys().(syscall.WaitStatus)
+ exitCode = ws.ExitStatus()
+ } else {
+ // This will happen (in OSX) if `name` is not available in $PATH,
+ // in this situation, exit code could not be get, and stderr will be
+ // empty string very likely, so we use the default fail code, and format err
+ // to string and set to stderr
+
+ app.Log("Could not get exit code for failed program")
+ exitCode = 255
+ }
+ } else {
+ // success, exitCode should be 0 if go is ok
+ ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
+ exitCode = ws.ExitStatus()
+ }
+
+ app.Log("Exit code %s", exitCode)
+
+ break
+ }
+
+
+ return map[string]interface{}{
+ "stutus" : "success",
+ }, nil
+ }
+
+ func (app *App) Ping2ExecStop(strAddr string, strWin string) (any, error) {
+ return app.Ping2ExecSign(strAddr, strWin, "-SIGINT")
+ }
+
+ func (app *App) Ping2ExecStat(strAddr string, strWin string) (any, error) {
+ return app.Ping2ExecSign(strAddr, strWin, "-SIGQUIT")
+ }
+
+
+ func (app *App) Ping2ExecSnip(parm any) (any, error) {
+ var err error
+ var ok bool
+
+ var ifcAddr interface{}
+ var ifcCmd interface{}
+ var ifcWin interface{}
+
+ ifcAddr, err = app.IfcGet(parm, "InputArgument", "addr")
+
+ if err != nil {
+ return map[string]interface{}{
+ "stutus" : "error",
+ "error" : "Unset IPv4 address",
+ }, nil
+ }
+
+ ifcCmd, err = app.IfcGet(parm, "InputArgument", "cmd")
+
+ if err != nil {
+ return map[string]interface{}{
+ "stutus" : "error",
+ "error" : "Unset command",
+ }, nil
+ }
+
+ ifcWin, err = app.IfcGet(parm, "InputArgument", "win")
+
+ if err != nil {
+ return map[string]interface{}{
+ "stutus" : "error",
+ "error" : "Unset window",
+ }, nil
+ }
+
+ var strAddr string
+ var strCmd string
+ var strWin string
+
+ strAddr, ok = ifcAddr.(string)
+
+ if !ok {
+ return map[string]interface{}{
+ "stutus" : "error",
+ "error" : "Invalid IPv4 address type",
+ }, nil
+ }
+
+ strCmd, ok = ifcCmd.(string)
+
+ if !ok {
+ return map[string]interface{}{
+ "stutus" : "error",
+ "error" : "Invalid command type",
+ }, nil
+ }
+
+ strWin, ok = ifcWin.(string)
+
+ if !ok {
+ intWin, ok := ifcWin.(float64)
+
+ if !ok {
+ return map[string]interface{}{
+ "stutus" : "error",
+ "error" : "Invalid window type",
+ }, nil
+ }
+
+ strWin = strconv.FormatFloat(intWin, 'f', -1, 32)
+ }
+
+
+ switch(strAddr) {
+ case "1.1.1.1":
+ break;
+ case "8.8.8.8":
+ break;
+ case "8.8.4.4":
+ break;
+ case "9.9.9.9":
+ break;
+
+ default:
+ return map[string]interface{}{
+ "stutus" : "error",
+ "error" : "Invalid IPv4 address",
+ }, nil
+ }
+
+ switch(strCmd) {
+ case "start":
+ go app.Ping2ExecStart(strAddr, strWin)
+
+ return map[string]interface{}{
+ "status" : "success",
+ }, nil
+
+ case "stop":
+ return app.Ping2ExecStop(strAddr, strWin)
+
+ case "stat":
+ return app.Ping2ExecStat(strAddr, strWin)
+
+ default:
+ return map[string]interface{}{
+ "stutus" : "error",
+ "error" : "Invalid command",
+ }, nil
+ }
+
+ return nil, nil
+ }
diff --git a/go.mod b/go.mod
index 13c65e0..82b9067 100644
--- a/go.mod
+++ b/go.mod
@@ -5,8 +5,8 @@ go 1.20
require (
github.com/andybalholm/brotli v1.1.0
github.com/gorilla/websocket v1.5.1
- golang.org/x/crypto v0.14.0
- golang.org/x/net v0.17.0
+ golang.org/x/crypto v0.23.0
+ golang.org/x/net v0.25.0
)
-require golang.org/x/sys v0.13.0 // indirect
+require golang.org/x/sys v0.20.0 // indirect
diff --git a/go.sum b/go.sum
index 1a1142e..bb0add0 100644
--- a/go.sum
+++ b/go.sum
@@ -4,7 +4,13 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
diff --git a/static/default.js b/static/default.js
index 6ddc1c3..be6bb44 100644
--- a/static/default.js
+++ b/static/default.js
@@ -76,9 +76,7 @@
contentReq(page, parm) {
console.log("contentReq", page);
- if(page == "trmShow") {
- this.trmShow();
- }
+ (this[page])();
}
@@ -276,6 +274,204 @@
// console.log(window.location)
}
+ //==========================
+
+ ping2AddrSet(w, addr) {
+ this.blobPing2Wind[w].nodeAddr.innerHTML = addr;
+ this.blobPing2Wind[w].nodeAddrList.style.visibility = "hidden";
+ }
+
+ ping2Addr(w) {
+ if(!this.blobPing2Wind[w].nodeAddrList) {
+ this.blobPing2Wind[w].nodeAddrList = dcrt({
+ tag : "div",
+ style: "display:block; visibility:hidden; position:absolute; top:32px; left:110px; background-color:#222; overflow:auto; border:1px solid grey; padding:15px;",
+ parn : this.blobPing2Wind[w].nodeRoot
+ });
+
+ for(var i = 0; i < this.listPing2Addr.length; i++) {
+ dcrt({
+ tag : "div",
+ parn : this.blobPing2Wind[w].nodeAddrList,
+ click: this.ping2AddrSet.bind(this, w, this.listPing2Addr[i]),
+ html : this.listPing2Addr[i]
+ });
+ }
+ }
+
+ if(this.blobPing2Wind[w].nodeAddrList.style.visibility == "hidden") {
+ this.blobPing2Wind[w].nodeAddrList.style.visibility = "visible";
+ }
+ else {
+ this.blobPing2Wind[w].nodeAddrList.style.visibility = "hidden";
+ }
+ }
+
+ ping2Snip(w, cmd) {
+ if(!cmd) {
+ return;
+ }
+
+ var obj = {
+ win : w + "",
+ cmd : cmd,
+ addr : this.blobPing2Wind[w].nodeAddr.innerHTML
+ };
+
+ return this.reqSnip("ping2Exec", obj);
+ }
+
+ ping2Blob(w, sty) {
+ this.blobPing2Wind[w] = {
+ list : []
+ };
+
+ this.blobPing2Wind[w].nodeRoot = dcrt({
+ tag : "div",
+ style: sty,
+ parn : this.nodePing2Body
+ });
+
+ this.blobPing2Wind[w].nodeAddr = dcrt({
+ tag : "div",
+ style: "display:block; position:absolute; top:-2px; left:125px;",
+ click: this.ping2Addr.bind(this, w),
+ html : "8.8.8.8"
+ });
+
+ this.blobPing2Wind[w].nodeHead = dcrt({
+ tag : "div",
+ style: "display:block; position:absolute; top:1px; height:32px; left:1px; right:1px; overflow:auto; border:0px solid red; padding:0;",
+ parn : this.blobPing2Wind[w].nodeRoot,
+ child: [
+ {
+ tag : "div",
+ style: "display:block; position:absolute; top:0px; left:1px;",
+ click: this.ping2Snip.bind(this, w, "start"),
+ html : ''
+ },
+ {
+ tag : "div",
+ style: "display:block; position:absolute; top:0px; left:25px;",
+ click: this.ping2Snip.bind(this, w, "stat"),
+ html : ''
+ },
+ {
+ tag : "div",
+ style: "display:block; position:absolute; top:0px; left:50px;",
+ click: this.ping2Snip.bind(this, w, "stop"),
+ html : ''
+ },
+ {
+ tag : "div",
+ style: "display:block; position:absolute; top:0px; left:100px;",
+ click: this.ping2Addr.bind(this, w),
+ html : ''
+ },
+ this.blobPing2Wind[w].nodeAddr
+ ]
+ });
+
+ this.blobPing2Wind[w].nodeBody = dcrt({
+ tag : "div",
+ style: "display:block; position:absolute; top:26px; bottom:1px; left:1px; right:1px; overflow:auto; border:1px solid grey;",
+ parn : this.blobPing2Wind[w].nodeRoot
+ });
+
+ }
+
+ ping2StartReq() {
+ this.nodeDataHeadRoot.innerHTML = "";
+ this.nodeDataBodyRoot.innerHTML = "";
+
+ if(!this.nodePing2Head) {
+ this.listPing2Addr = [
+ "1.1.1.1",
+ "8.8.8.8",
+ "8.8.4.4",
+ "9.9.9.9"
+ ];
+
+ this.blobPing2Wind = [];
+
+ this.nodePing2Head = dcrt({
+ tag : "h4",
+ parn : this.nodeDataHeadRoot,
+ style: "margin:4px;",
+ html : "Ping2 Start request"
+ });
+
+ this.nodePing2Body = dcrt({
+ tag : "div",
+ style: "display:block; position:relative; width:100%; height:100%; overflow:auto;",
+ parn : this.nodeDataBodyRoot
+ });
+
+ this.ping2Blob(0, "display:block; position:absolute; top:1px; bottom:1px; left:1px; right:calc(50% - 2px); overflow:auto; border:1px solid grey;");
+
+ this.ping2Blob(1, "display:block; position:absolute; top:1px; bottom:calc(50% - 2px); left:calc(50% + 3px); right:0; overflow:auto; border:1px solid grey;");
+
+ this.ping2Blob(2, "display:block; position:absolute; top:calc(50% - 1px); bottom:1px; left:calc(50% + 3px); right:0; overflow:auto; border:1px solid grey;");
+
+ this.nodePing2BodyList = [];
+ }
+
+ this.nodeDataHeadRoot.appendChild(this.nodePing2Head);
+ this.nodeDataBodyRoot.appendChild(this.nodePing2Body);
+
+ this.reqSnip("ping2Exec", {win: 0, cmd: "start", addr: "1.1.1.1"});
+ this.reqSnip("ping2Exec", {win: 1, cmd: "start", addr: "8.8.8.8"});
+ this.reqSnip("ping2Exec", {win: 2, cmd: "start", addr: "9.9.9.9"});
+
+ return;
+ }
+
+ ping2StartRcv(obj) {
+ // console.log(obj);
+ this.nodePing2Head.innerHTML = "Ping2 starting";
+ }
+
+
+ ping2StopReq() {
+ return this.reqSnip("ping2Stop");
+ }
+
+ ping2StopRcv(obj) {
+ // console.log(obj);
+ }
+
+ ping2StatReq() {
+ return this.reqSnip("ping2Stat");
+ }
+
+ ping2StatRcv(obj) {
+ // console.log(obj);
+ }
+
+ ping2DataRcv(obj) {
+ if(obj.data == "procid") {
+ this.nodePing2Head.innerHTML = "Ping2 started " + obj.procid;
+ return;
+ }
+
+ var w = 0;
+
+ this.blobPing2Wind[w].list.push(dcrt({
+ tag : "pre",
+ style: "margin:0;",
+ parn : this.blobPing2Wind[w].nodeBody,
+ html : obj.string
+ }));
+
+ this.blobPing2Wind[w].nodeBody.scrollTop = this.blobPing2Wind[w].nodeBody.scrollTopMax;
+
+ if(this.blobPing2Wind[w].list.length > 100) {
+ var node = this.blobPing2Wind[w].list.shift();
+ if(node)
+ node.remove();
+ }
+ }
+
// END class
}