Initial 2024-01-26
This commit is contained in:
5
.editorconfig
Normal file
5
.editorconfig
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
indent_style = tab
|
||||
tab_width = 4
|
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
**/*_
|
||||
**/.#*
|
||||
**/0*
|
||||
**/1*
|
||||
**/2*
|
||||
**/3*
|
||||
**/4*
|
||||
**/5*
|
||||
**/6*
|
||||
**/7*
|
||||
**/8*
|
||||
**/9*
|
||||
|
||||
**/*-test.go
|
||||
|
||||
**/*.so
|
||||
**/*.log*
|
||||
**/*log
|
||||
**/LOG*
|
||||
|
||||
**/main
|
||||
**/main2
|
||||
|
||||
static2/**
|
||||
cache/**
|
||||
data/**
|
||||
old/**
|
||||
outer/**
|
||||
secret/**
|
122
cmpSnipper/cmpSnipper.go
Normal file
122
cmpSnipper/cmpSnipper.go
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"plugin"
|
||||
)
|
||||
|
||||
type cmpPluginStruct struct {
|
||||
Name string
|
||||
Plug *plugin.Plugin
|
||||
}
|
||||
|
||||
|
||||
type App struct {
|
||||
Conf interface{}
|
||||
ErrIsDir error // = errors.New("Is directory")
|
||||
|
||||
CliList []cmpWbsCliStruct
|
||||
|
||||
cmpSnipperHttpServ cmpSnipperHttpServ
|
||||
|
||||
Rand4d int
|
||||
|
||||
PlugList []cmpPluginStruct
|
||||
|
||||
SshList []cmpSshCliStruct
|
||||
}
|
||||
|
||||
func (app *App) PlugInit(name string, file string) {
|
||||
qqq := map[string]interface{}{
|
||||
"Aaa": "Bbb",
|
||||
}
|
||||
|
||||
var plug cmpPluginStruct
|
||||
|
||||
var p *plugin.Plugin
|
||||
|
||||
p, err := plugin.Open(file)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return
|
||||
}
|
||||
|
||||
plug.Name = name
|
||||
plug.Plug = p
|
||||
|
||||
plugInitReq, err := plug.Plug.Lookup("CmpPlug1Init")
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return
|
||||
}
|
||||
|
||||
plugInitFnc := plugInitReq.(func(int, func(any, ...interface{}), map[string]interface{}) interface{})
|
||||
|
||||
plugInitRes := plugInitFnc(33, app.Log, qqq)
|
||||
|
||||
app.Log("%+v", plugInitRes)
|
||||
|
||||
app.PlugList = append(app.PlugList, plug)
|
||||
}
|
||||
|
||||
func (app *App) PlugCall(pnam string, fnam string) {
|
||||
for _, plug := range app.PlugList {
|
||||
if plug.Name != pnam {
|
||||
continue
|
||||
}
|
||||
|
||||
plugFuncReq, err := plug.Plug.Lookup(fnam)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return
|
||||
}
|
||||
|
||||
plugFuncFnc := plugFuncReq.(func() error)
|
||||
|
||||
plugFuncRes := plugFuncFnc()
|
||||
|
||||
app.Log("%+v", plugFuncRes)
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) Prep() (error) {
|
||||
app.ErrIsDir = errors.New("Is directory")
|
||||
|
||||
app.LogSetup()
|
||||
|
||||
var err = app.ConfLoadFile("secret/zest.json");
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *App) Proc() error {
|
||||
var err error // = make(chan error, 1)
|
||||
|
||||
var term = make(chan bool, 1)
|
||||
|
||||
go app.WaitSignal(term)
|
||||
|
||||
err = app.HttpServStart()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
<-term
|
||||
|
||||
app.HttpServStop()
|
||||
|
||||
app.Log("Terminating")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// end
|
103
cmpSnipper/cmpSnipperConf.go
Normal file
103
cmpSnipper/cmpSnipperConf.go
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"strconv"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func (app *App) IfcGet(ifc interface{}, arr ...string) (interface{}, error) {
|
||||
var cnt = len(arr);
|
||||
var idx string
|
||||
|
||||
for j := 0; j < cnt; j++ {
|
||||
idx = arr[j]
|
||||
|
||||
switch v := ifc.(type) {
|
||||
case string:
|
||||
app.Log("Convert string to ifc")
|
||||
ifc = ifc.(interface{})
|
||||
|
||||
case map[string]interface{}:
|
||||
// app.Log("Valid ifc " + idx)
|
||||
ifc = v[idx];
|
||||
|
||||
default:
|
||||
app.Log("Invalid type variable %s %T", idx, ifc)
|
||||
return nil, errors.New("Invalid type variable");
|
||||
}
|
||||
}
|
||||
|
||||
if ifc == nil {
|
||||
return nil, errors.New("Undefine variable " + idx);
|
||||
}
|
||||
|
||||
// app.Log("Found ifc %s %T", idx, ifc)
|
||||
|
||||
return ifc, nil;
|
||||
}
|
||||
|
||||
func (app *App) ConfGetIfc(arr ...string) (interface{}, error) {
|
||||
return app.IfcGet(app.Conf, arr...);
|
||||
}
|
||||
|
||||
func (app *App) ConfGetStr(arr ...string) (string, error) {
|
||||
ifc, err := app.ConfGetIfc(arr...);
|
||||
|
||||
if err != nil {
|
||||
return "", err;
|
||||
}
|
||||
|
||||
switch ifc.(type) {
|
||||
case string:
|
||||
return ifc.(string), nil;
|
||||
case float64:
|
||||
f := ifc.(float64)
|
||||
u := uint64(f)
|
||||
return strconv.FormatUint(u, 10), nil;
|
||||
default:
|
||||
return "", errors.New("Invalid type value !s");
|
||||
}
|
||||
|
||||
return "", errors.New("Invalid type value");
|
||||
}
|
||||
|
||||
func (app *App) ConfGetArr(arr ...string) ([]interface{}, error) {
|
||||
ifc, err := app.ConfGetIfc(arr...);
|
||||
|
||||
if err != nil {
|
||||
return nil, err;
|
||||
}
|
||||
|
||||
switch v := ifc.(type) {
|
||||
case []interface{}:
|
||||
return v, nil
|
||||
default:
|
||||
fmt.Printf("Invalid type value %+q\n", ifc)
|
||||
return nil, errors.New("Invalid type value !s");
|
||||
}
|
||||
|
||||
return nil, errors.New("Invalid type value");
|
||||
}
|
||||
|
||||
func (app *App) ConfLoadFile(file string) error {
|
||||
data, err := app.FileReadLimit(file, 1048576);
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// fmt.Println(string(data));
|
||||
|
||||
err = json.Unmarshal(data, &app.Conf)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
84
cmpSnipper/cmpSnipperHttpServ.go
Normal file
84
cmpSnipper/cmpSnipperHttpServ.go
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type tcpKeepAliveListener struct {
|
||||
*net.TCPListener
|
||||
}
|
||||
|
||||
type cmpSnipperHttpServ struct {
|
||||
HttpListener net.Listener
|
||||
}
|
||||
|
||||
func (app *App) HttpServStart() error {
|
||||
var err error;
|
||||
|
||||
// var subjHttpPortString string = "7070";
|
||||
// var subjHttpPortUint16 uint16 = subjConf.Http.Port;
|
||||
|
||||
host, err := app.ConfGetStr("http", "host")
|
||||
|
||||
// fmt.Printf("Success load : %+v\n", host)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
port, err := app.ConfGetStr("http", "port")
|
||||
|
||||
// fmt.Printf("Success load : %+v\n", port)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// if subjHttpPortUint16 == 0 || subjHttpPortString != strconv.FormatUint(uint64(subjHttpPortUint16), 10) {
|
||||
// fmt.Printf("Invalid http.port %s != %d\n", subjHttpPortString, subjHttpPortUint16)
|
||||
// app.Log(".Fatal");
|
||||
// }
|
||||
|
||||
|
||||
httpFileServer := http.FileServer(http.Dir("static"))
|
||||
http.Handle("/go-prefix/static/", http.StripPrefix("/go-prefix/static/", httpFileServer))
|
||||
|
||||
http.HandleFunc("/" , app.HttpReq);
|
||||
http.HandleFunc("/go-prefix/ws" , app.HttpWebSockHand)
|
||||
|
||||
var addr = host + ":" + port
|
||||
|
||||
server := &http.Server{Addr: addr}
|
||||
|
||||
app.Log("Listenning: '%s'", port);
|
||||
|
||||
app.cmpSnipperHttpServ.HttpListener, err = net.Listen("tcp", addr)
|
||||
|
||||
// defer app.HttpServClose()
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
err = server.Serve(tcpKeepAliveListener{app.cmpSnipperHttpServ.HttpListener.(*net.TCPListener)})
|
||||
|
||||
if err == nil {
|
||||
app.Log(err)
|
||||
return // err
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *App) HttpServStop() {
|
||||
app.cmpSnipperHttpServ.HttpListener.Close()
|
||||
|
||||
app.Log("Server Closed")
|
||||
}
|
245
cmpSnipper/cmpSnipperHttpUtil.go
Normal file
245
cmpSnipper/cmpSnipperHttpUtil.go
Normal file
@@ -0,0 +1,245 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (app *App) HttpRespText(w http.ResponseWriter, data []byte) {
|
||||
w.Write(data)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (app *App) HttpRespJson(w http.ResponseWriter, data any) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
jsonResp, err := json.MarshalIndent(data, "", "\t")
|
||||
|
||||
if err != nil {
|
||||
app.Log("Error happened in JSON marshal. Err: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
app.HttpRespText(w, jsonResp)
|
||||
}
|
||||
|
||||
func HttpRespCodeText(w http.ResponseWriter, req *http.Request, code int, cont string, mesg any) {
|
||||
w.WriteHeader(code)
|
||||
|
||||
w.Header().Set("Content-Type", cont)
|
||||
|
||||
|
||||
}
|
||||
|
||||
func (app *App) HttpRespForbidden(w http.ResponseWriter, req *http.Request, mesg string) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
|
||||
resp := make(map[string]any)
|
||||
resp["code"] = 403
|
||||
resp["status"] = "Forbidden"
|
||||
resp["message"] = mesg
|
||||
|
||||
app.HttpRespJson(w, resp)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (app *App) HttpReqDir1(w http.ResponseWriter, req *http.Request, targ string, path string) {
|
||||
resp := map[string]interface{}{
|
||||
"path" : path,
|
||||
"directory": targ,
|
||||
"content" : nil,
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(targ)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
app.HttpRespForbidden(w, req, "Server error")
|
||||
}
|
||||
|
||||
var slice []interface{};
|
||||
|
||||
for _, e := range entries {
|
||||
slice = append(slice, map[string]interface{}{
|
||||
"name": e.Name(),
|
||||
})
|
||||
|
||||
// fmt.Println(e.Name());
|
||||
}
|
||||
|
||||
resp["content"] = slice
|
||||
|
||||
app.HttpRespJson(w, resp)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (app *App) HttpReqDir(w http.ResponseWriter, req *http.Request, targ string, path string) {
|
||||
finx := path + "/index.html"
|
||||
|
||||
data, err := app.FileReadLimit(finx, 1048576);
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
app.HttpReqDir1(w, req, targ, path)
|
||||
return
|
||||
}
|
||||
|
||||
if err == app.ErrIsDir {
|
||||
app.HttpReqDir1(w, req, targ, path)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
app.Log("Err: %s", err)
|
||||
app.HttpRespForbidden(w, req, "Server error")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
|
||||
app.HttpRespText(w, data)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (app *App) HttpReq(w http.ResponseWriter, req *http.Request) {
|
||||
// https://go.dev/src/net/http/request.go
|
||||
|
||||
// fmt.Printf("Request: %+v\n", req)
|
||||
|
||||
var auri = (strings.Split(req.RequestURI, "/"))
|
||||
auri[0] = "/"
|
||||
|
||||
var aidx = 0
|
||||
|
||||
app.Log("Auri: %+v", auri)
|
||||
|
||||
var locTarg map[string]interface{}
|
||||
var locEnd bool
|
||||
|
||||
locList, err := app.ConfGetArr("http", "location")
|
||||
|
||||
if err != nil {
|
||||
app.HttpRespForbidden(w, req, "Invalid http.location")
|
||||
return
|
||||
}
|
||||
|
||||
for uid, uri := range auri {
|
||||
locEnd = false
|
||||
|
||||
for _, locIfc := range locList {
|
||||
var locMap map[string]interface{};
|
||||
|
||||
switch v := locIfc.(type) {
|
||||
case map[string]interface{}:
|
||||
locMap = v;
|
||||
}
|
||||
|
||||
if locMap == nil {
|
||||
app.Log("Not Found")
|
||||
continue
|
||||
}
|
||||
|
||||
locUri := locMap["uri"]
|
||||
|
||||
if 1 == 0 {
|
||||
// fmt.Printf("Found: %+v\n", locUri)
|
||||
continue
|
||||
}
|
||||
|
||||
if locUri != uri {
|
||||
// fmt.Printf(" %s != %s\n", locUri, uri)
|
||||
continue
|
||||
}
|
||||
|
||||
// fmt.Printf("Found: %s\n", uri)
|
||||
|
||||
locTarg = locMap
|
||||
locEnd = true
|
||||
aidx = uid
|
||||
|
||||
switch v := locMap["list"].(type) {
|
||||
case []interface{}:
|
||||
locList = v;
|
||||
// fmt.Printf("Found list\n");
|
||||
}
|
||||
}
|
||||
|
||||
if !locEnd {
|
||||
break
|
||||
}
|
||||
}
|
||||
/*
|
||||
fmt.Printf("Targ %+v\n", locTarg);
|
||||
fmt.Printf("Targ %+v\n", locEnd );
|
||||
fmt.Printf("Targ %s \n", locTarg["uri"] );
|
||||
fmt.Printf("Targ %+v\n", auri[(aidx+1):]);
|
||||
*/
|
||||
switch locTarg["type"] {
|
||||
case "json":
|
||||
targ := locTarg["targ"].(string)
|
||||
|
||||
app.HttpRespJson(w, locTarg[targ])
|
||||
|
||||
return
|
||||
|
||||
case "func":
|
||||
targ := locTarg["targ"].(string)
|
||||
parm := locTarg["parm"]
|
||||
|
||||
resp, err := app.CallFuncByName(targ, parm)
|
||||
|
||||
if err != nil {
|
||||
app.Log("Err: %s", err)
|
||||
break
|
||||
}
|
||||
|
||||
app.HttpRespJson(w, resp)
|
||||
|
||||
return
|
||||
|
||||
case "directory":
|
||||
targ := locTarg["targ"].(string)
|
||||
|
||||
path := targ + "/" + strings.Join(auri[(aidx+1):], "/")
|
||||
|
||||
app.Log("Location: %s", path)
|
||||
|
||||
data, err := app.FileReadLimit(path, 1048576);
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
break
|
||||
}
|
||||
|
||||
if err == app.ErrIsDir {
|
||||
app.HttpReqDir(w, req, targ, path)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
app.Log("Err: %s", err)
|
||||
app.HttpRespForbidden(w, req, "Server error")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
|
||||
app.HttpRespText(w, data)
|
||||
|
||||
return
|
||||
|
||||
case "redirect":
|
||||
http.Redirect(w, req, locTarg["targ"].(string), int(locTarg["code"].(float64)))
|
||||
|
||||
return
|
||||
|
||||
// case "ws":
|
||||
}
|
||||
|
||||
app.HttpRespForbidden(w, req, "Invalid type")
|
||||
}
|
168
cmpSnipper/cmpSnipperHttpWsHandle.go
Normal file
168
cmpSnipper/cmpSnipperHttpWsHandle.go
Normal file
@@ -0,0 +1,168 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"time"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type cmpWbsCliStruct struct {
|
||||
W http.ResponseWriter
|
||||
Connect *websocket.Conn
|
||||
HostPort string
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
HandshakeTimeout: 60 * time.Second,
|
||||
}
|
||||
|
||||
func (app *App) HttpWebSockHand(w http.ResponseWriter, req *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, req, nil)
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return
|
||||
}
|
||||
|
||||
app.Log("HttpWebSockHand:for")
|
||||
|
||||
HostPort := req.Header.Get("X-Real-Ip")
|
||||
|
||||
if HostPort == "" {
|
||||
HostPort = req.Header.Get("X-Forwarded-For")
|
||||
}
|
||||
|
||||
if HostPort == "" {
|
||||
HostPort = req.RemoteAddr
|
||||
}
|
||||
|
||||
app.Log("New client: %s", HostPort)
|
||||
|
||||
var cmpWbsCli cmpWbsCliStruct = cmpWbsCliStruct{
|
||||
w,
|
||||
conn,
|
||||
HostPort,
|
||||
}
|
||||
|
||||
|
||||
app.CliList = append(app.CliList, cmpWbsCli)
|
||||
|
||||
app.Log(app.CliList)
|
||||
|
||||
for i, cli := range app.CliList {
|
||||
app.Log("Client %s, %s", i, cli.HostPort)
|
||||
}
|
||||
|
||||
for {
|
||||
var inp = map[string]interface{}{}
|
||||
var out = map[string]interface{}{
|
||||
"snip": "",
|
||||
"result": nil,
|
||||
}
|
||||
|
||||
err := conn.ReadJSON(&inp)
|
||||
|
||||
if err != nil {
|
||||
app.Log("Read JSON: %s", err)
|
||||
app.Log(err)
|
||||
|
||||
var list []cmpWbsCliStruct
|
||||
|
||||
for _, ii := range app.CliList {
|
||||
if ii.HostPort == HostPort {
|
||||
continue
|
||||
}
|
||||
|
||||
list = append(list, ii)
|
||||
}
|
||||
|
||||
app.CliList = list
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
app.Log("Received message: %+v", inp)
|
||||
|
||||
out["snip"] = inp["snip"]
|
||||
|
||||
// app.Log("Copy snip OK")
|
||||
|
||||
var snip string;
|
||||
|
||||
snip = inp["snip"].(string)
|
||||
|
||||
// app.Log("Look snip")
|
||||
|
||||
if app.SnipExists(snip) {
|
||||
out["result"], err = app.SnipCall(cmpWbsCli, snip, inp)
|
||||
|
||||
if err != nil {
|
||||
out["error"] = "Server error"
|
||||
}
|
||||
} else {
|
||||
out["error"] = "Unknown snip"
|
||||
app.Log("Unknow snip:", inp["snip"])
|
||||
}
|
||||
|
||||
err = conn.WriteJSON(out)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
}
|
||||
|
||||
// for
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (app *App) HttpWebSockSendTo(cmpWbsCli cmpWbsCliStruct, snip string, result map[string]interface{}) {
|
||||
var err error
|
||||
|
||||
out := map[string]interface{}{
|
||||
"snip": snip,
|
||||
"result": result,
|
||||
}
|
||||
|
||||
err = cmpWbsCli.Connect.WriteJSON(out)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (app *App) HttpWebSockSendAll(snip string, result map[string]interface{}) {
|
||||
var err error
|
||||
|
||||
app.Log("Send to all")
|
||||
|
||||
out := map[string]interface{}{
|
||||
"snip": snip,
|
||||
"result": result,
|
||||
}
|
||||
|
||||
for _, ii := range app.CliList {
|
||||
if ii.HostPort == "" {
|
||||
break
|
||||
}
|
||||
|
||||
err = ii.Connect.WriteJSON(out)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
57
cmpSnipper/cmpSnipperLog.go
Normal file
57
cmpSnipper/cmpSnipperLog.go
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func (app *App) LogMod(arg interface{}) string {
|
||||
var str string
|
||||
|
||||
switch t := arg.(type) {
|
||||
case nil:
|
||||
str = /* "N:" + */ "null"
|
||||
|
||||
case string:
|
||||
str = /* "S:" + */ t
|
||||
|
||||
case error:
|
||||
str = /* "E:" + */ t.Error()
|
||||
|
||||
case byte:
|
||||
str = /* "B:" + */ string(t)
|
||||
|
||||
case []byte:
|
||||
str = /* "A:" + */ string(t)
|
||||
|
||||
case interface{}:
|
||||
obyte, _ := json.MarshalIndent(arg, "", "\t")
|
||||
str = /* "J:" + */ string(obyte)
|
||||
|
||||
default:
|
||||
str = /* "U:" + */ fmt.Sprintf("Unknown type %T", t)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
func (app *App) Log(farg any, iargs ...interface{}) {
|
||||
var str = app.LogMod(farg)
|
||||
|
||||
log.SetPrefix(time.Now().UTC().Format("2006-01-02 15:04:05") + ": ")
|
||||
|
||||
oargs := make([]interface{}, len(iargs))
|
||||
|
||||
for k, arg := range iargs {
|
||||
oargs[k] = app.LogMod(arg)
|
||||
}
|
||||
|
||||
log.Output(2, fmt.Sprintf(str + "\n", oargs...))
|
||||
}
|
||||
|
||||
func (app *App) LogSetup() {
|
||||
log.SetFlags( log.Lshortfile );
|
||||
}
|
84
cmpSnipper/cmpSnipperSignal.go
Normal file
84
cmpSnipper/cmpSnipperSignal.go
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (app *App) WaitSignal(term chan bool) {
|
||||
var sigreq = make(chan os.Signal, 1)
|
||||
|
||||
for true {
|
||||
signal.Notify(sigreq)
|
||||
sigrcv := <-sigreq
|
||||
|
||||
// app.Log("Got signal: %s", sigrcv)
|
||||
|
||||
if sigrcv == syscall.SIGTERM {
|
||||
term <- true
|
||||
// continue
|
||||
return
|
||||
}
|
||||
|
||||
if sigrcv == syscall.SIGINT {
|
||||
term <- true
|
||||
// continue
|
||||
return
|
||||
}
|
||||
|
||||
if sigrcv == syscall.SIGQUIT {
|
||||
term <- true
|
||||
// continue
|
||||
return
|
||||
}
|
||||
|
||||
if sigrcv == syscall.SIGUSR1 {
|
||||
app.Log("Got signal: %s", sigrcv)
|
||||
continue
|
||||
}
|
||||
|
||||
if sigrcv == syscall.SIGUSR2 {
|
||||
app.Log("Got signal: %s", sigrcv)
|
||||
|
||||
app.Log("Rand 4d: %d", app.Rand4d)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// 1) SIGHUP
|
||||
// 2) SIGINT
|
||||
// 3) SIGQUIT
|
||||
// 4) SIGILL
|
||||
// 5) SIGTRAP
|
||||
// 6) SIGABRT
|
||||
// 7) SIGBUS
|
||||
// 8) SIGFPE
|
||||
// 9) SIGKILL
|
||||
// 10) SIGUSR1
|
||||
// 11) SIGSEGV
|
||||
// 12) SIGUSR2
|
||||
// 13) SIGPIPE
|
||||
// 14) SIGALRM
|
||||
// 15) SIGTERM
|
||||
// 16) SIGSTKFLT
|
||||
// 17) SIGCHLD
|
||||
// 18) SIGCONT
|
||||
// 19) SIGSTOP
|
||||
// 20) SIGTSTP
|
||||
// 21) SIGTTIN
|
||||
// 22) SIGTTOU
|
||||
// 23) SIGURG
|
||||
// 24) SIGXCPU
|
||||
// 25) SIGXFSZ
|
||||
// 26) SIGVTALRM
|
||||
// 27) SIGPROF
|
||||
// 28) SIGWINCH
|
||||
// 29) SIGIO
|
||||
// 30) SIGPWR
|
||||
// 31) SIGSYS
|
||||
|
||||
app.Log("Got signal: %s", sigrcv)
|
||||
}
|
||||
}
|
78
cmpSnipper/cmpSnipperSnip.go
Normal file
78
cmpSnipper/cmpSnipperSnip.go
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func (app *App) SnipExists(funcName string) bool {
|
||||
snipName := app.UpperFirst(funcName) + "Snip"
|
||||
refCls := reflect.ValueOf(app)
|
||||
refMth := refCls.MethodByName(snipName)
|
||||
|
||||
if !refMth.IsValid() {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (app *App) SnipCall(cmpWbsCli cmpWbsCliStruct, fnName string, ifcII interface{}) (interface{}, error) {
|
||||
snName := app.UpperFirst(fnName) + "Snip"
|
||||
refCls := reflect.ValueOf(app)
|
||||
refMth := refCls.MethodByName(snName)
|
||||
|
||||
if !refMth.IsValid() {
|
||||
app.Log("Call method \"%s\" not found", snName)
|
||||
return nil, errors.New("Call method not founnd")
|
||||
}
|
||||
|
||||
app.Log("Call method \"%s\"", snName)
|
||||
|
||||
ifcIM := map[string]interface{}{
|
||||
"InputArgument" : ifcII,
|
||||
"HostPort" : cmpWbsCli.HostPort,
|
||||
}
|
||||
|
||||
refIL := []reflect.Value{
|
||||
reflect.ValueOf(ifcIM),
|
||||
}
|
||||
|
||||
refOL := refMth.Call(refIL)
|
||||
|
||||
infOI := refOL[0].Interface()
|
||||
|
||||
app.Log("Interface output item %+v", infOI)
|
||||
|
||||
return infOI, nil
|
||||
}
|
||||
|
||||
func (app *App) SnipGetCli(parm any) (cmpWbsCliStruct, error) {
|
||||
var err error
|
||||
var cmpWbsCli cmpWbsCliStruct
|
||||
|
||||
HostPortIfc, err := app.IfcGet(parm.(map[string]interface{}), "HostPort")
|
||||
|
||||
if err != nil {
|
||||
app.Log("Invalid iterface")
|
||||
return cmpWbsCli, err
|
||||
}
|
||||
|
||||
HostPort, ok := HostPortIfc.(string)
|
||||
|
||||
if !ok {
|
||||
app.Log("Invalid string")
|
||||
return cmpWbsCli, errors.New("Can't covert to string")
|
||||
}
|
||||
|
||||
for _, ii := range app.CliList {
|
||||
if HostPort != ii.HostPort {
|
||||
continue
|
||||
}
|
||||
|
||||
return ii, nil
|
||||
}
|
||||
|
||||
return cmpWbsCli, errors.New("Client " + HostPort + " not found")
|
||||
}
|
12
cmpSnipper/cmpSnipperSnipCliList.go
Normal file
12
cmpSnipper/cmpSnipperSnipCliList.go
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
func (app *App) CliListSnip(parm any) (any, error) {
|
||||
// app.Log("")
|
||||
|
||||
ret := map[string]interface{}{
|
||||
"list" : app.CliList,
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
32
cmpSnipper/cmpSnipperSnipLeftMenu.go
Normal file
32
cmpSnipper/cmpSnipperSnipLeftMenu.go
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func (app *App) LeftMenuSnip(parm any) (any, error) {
|
||||
// app.Log("Read data")
|
||||
|
||||
mainMenuFile, err := app.ConfGetStr("mainMenuFile")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := app.FileReadLimit(mainMenuFile, 1048576)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res = map[string]interface{}{}
|
||||
|
||||
err = json.Unmarshal(data, &res)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
70
cmpSnipper/cmpSnipperSnipPing.go
Normal file
70
cmpSnipper/cmpSnipperSnipPing.go
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"context"
|
||||
"time"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (app *App) PingSnip(parm any) (any, error) {
|
||||
// log.Println("PingSnip")
|
||||
|
||||
path, err := exec.LookPath("ping")
|
||||
|
||||
app.Log("Prog:", path)
|
||||
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"retval" : 127,
|
||||
"error" : "No prog",
|
||||
}, nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
|
||||
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, "ping", "-c", "4", "8.8.8.8")
|
||||
|
||||
cmd.Stdin = strings.NewReader("")
|
||||
|
||||
var stdout strings.Builder
|
||||
cmd.Stdout = &stdout
|
||||
|
||||
var stderr strings.Builder
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"retval" : exitCode,
|
||||
"error" : err,
|
||||
"stdout" : stdout.String(),
|
||||
"stderr" : stderr.String(),
|
||||
}, nil
|
||||
}
|
16
cmpSnipper/cmpSnipperSnipRand4d.go
Normal file
16
cmpSnipper/cmpSnipperSnipRand4d.go
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func (app *App) Rand4dSnip(parm any) (any, error) {
|
||||
// app.Log("Rand4dSnip")
|
||||
|
||||
app.Rand4d = rand.Intn(10000) + 1000
|
||||
|
||||
return map[string]interface{}{
|
||||
"rand4d" : app.Rand4d,
|
||||
}, nil
|
||||
}
|
87
cmpSnipper/cmpSnipperUtil.go
Normal file
87
cmpSnipper/cmpSnipperUtil.go
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"os"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func (app *App) FileReadLimit(file string, mSize int64) ([]byte, error) {
|
||||
info, err := os.Stat(file)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
return nil, app.ErrIsDir
|
||||
}
|
||||
|
||||
fSize := info.Size()
|
||||
|
||||
if fSize > mSize {
|
||||
return nil, errors.New("File is big")
|
||||
}
|
||||
|
||||
fd, err := os.Open(file)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer fd.Close()
|
||||
|
||||
var rata = make([]byte, fSize);
|
||||
|
||||
rSize, err := fd.Read(rata);
|
||||
|
||||
if fSize != int64(rSize) {
|
||||
return nil, errors.New("Can't read full file size")
|
||||
}
|
||||
|
||||
return rata, nil
|
||||
}
|
||||
|
||||
func (app *App) UpperFirst(si string) string {
|
||||
bi := []byte(si)
|
||||
ss := strings.Title(string(bi[0]))
|
||||
bo := bi
|
||||
bo[0] = ss[0]
|
||||
|
||||
return string(bo)
|
||||
}
|
||||
|
||||
func (app *App) CallFuncByName(funcName string, ifcIL ...interface{}) ([]interface{}, error) {
|
||||
refCls := reflect.ValueOf(app)
|
||||
refMth := refCls.MethodByName(funcName)
|
||||
|
||||
if !refMth.IsValid() {
|
||||
app.Log("Call method \"%s\" not found", funcName)
|
||||
return nil, errors.New("Call method not founnd")
|
||||
}
|
||||
|
||||
app.Log("Call method \"%s\"", funcName)
|
||||
|
||||
refIL := make([]reflect.Value, len(ifcIL))
|
||||
|
||||
for i, ifcII := range ifcIL {
|
||||
refIL[i] = reflect.ValueOf(ifcII)
|
||||
}
|
||||
|
||||
// fmt.Println("reflect input list", refIL);
|
||||
|
||||
refOL := refMth.Call(refIL)
|
||||
|
||||
infOL := make([]interface{}, len(refOL))
|
||||
|
||||
for i, refOI := range refOL {
|
||||
infOL[i] = refOI.Interface()
|
||||
}
|
||||
|
||||
app.Log("Interface output list %+v", infOL)
|
||||
|
||||
return infOL, nil
|
||||
}
|
196
cmpSnipper/cmpSnippetHttpCli.go
Normal file
196
cmpSnipper/cmpSnippetHttpCli.go
Normal file
@@ -0,0 +1,196 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
// "crypto/md5"
|
||||
"net/http"
|
||||
// "os"
|
||||
"io"
|
||||
// "fmt"
|
||||
"bufio"
|
||||
// "io/ioutil"
|
||||
"bytes"
|
||||
"strings"
|
||||
// "golang.org/x/net/html"
|
||||
// "net/url"
|
||||
"encoding/json"
|
||||
"compress/gzip"
|
||||
"compress/flate"
|
||||
"github.com/andybalholm/brotli"
|
||||
)
|
||||
|
||||
func (app *App) HttpGet(url string) (map[string]interface{}) {
|
||||
ret := map[string]interface{}{
|
||||
"Error" : nil ,
|
||||
"RequestUrl" : url ,
|
||||
"StatusCode" : 0 ,
|
||||
"ContentRaw" : nil ,
|
||||
"ContentJson" : nil ,
|
||||
"Header" : nil ,
|
||||
"Content-Encoding" : "" ,
|
||||
"Content-Type" : "" ,
|
||||
"Content-Length" : "" ,
|
||||
}
|
||||
|
||||
app.Log(url)
|
||||
|
||||
cli := &http.Client{}
|
||||
|
||||
ifcRawHead, err := app.ConfGetIfc("httpTest", "head")
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
ret["Error"] = err
|
||||
return ret
|
||||
}
|
||||
|
||||
mapIfcHead := ifcRawHead.(map[string]interface{})
|
||||
|
||||
mapStrHead := make(map[string][]string)
|
||||
|
||||
for key, val := range mapIfcHead {
|
||||
mapStrHead[key] = []string{ val.(string) }
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
|
||||
req.Header = mapStrHead
|
||||
|
||||
res, err := cli.Do(req)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
ret["Error"] = err
|
||||
return ret
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
ret["Error"] = err
|
||||
return ret
|
||||
}
|
||||
|
||||
ret["StatusCode" ] = res.StatusCode
|
||||
ret["Content-Length"] = res.ContentLength
|
||||
ret["Header" ] = res.Header
|
||||
|
||||
// app.Log("Response status: %s", res.Status)
|
||||
// app.Log("Header: %+v", res.Header)
|
||||
|
||||
// app.Log("TransferEncoding: %+v", res.TransferEncoding)
|
||||
// app.Log("ContentLength: %+v", res.ContentLength)
|
||||
|
||||
var tmpl []string
|
||||
|
||||
tmpl = res.Header["Content-Encoding"]
|
||||
if len(tmpl) > 0 {
|
||||
ret["Content-Encoding"] = tmpl[0]
|
||||
}
|
||||
|
||||
tmpl = res.Header["Content-Type"]
|
||||
if len(tmpl) > 0 {
|
||||
tmpl = strings.Split(tmpl[0], ";")
|
||||
|
||||
if len(tmpl) > 0 {
|
||||
ret["Content-Type"] = tmpl[0]
|
||||
}
|
||||
}
|
||||
|
||||
// Content-Disposition: attachment; name="fieldName"; filename="myfile.txt"
|
||||
|
||||
|
||||
out := new(bytes.Buffer)
|
||||
var encReader io.Reader
|
||||
|
||||
switch ret["Content-Encoding"] {
|
||||
case "":
|
||||
encReader = bufio.NewReader(res.Body)
|
||||
case "br":
|
||||
encReader = brotli.NewReader(res.Body)
|
||||
case "gzip":
|
||||
encReader, err = gzip.NewReader(res.Body)
|
||||
case "deflate":
|
||||
encReader = flate.NewReader(res.Body)
|
||||
default:
|
||||
app.Log("Unknown Content-Encoding %s", ret["Content-Encoding"])
|
||||
encReader = bufio.NewReader(res.Body)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
ret["Error"] = err
|
||||
return ret
|
||||
}
|
||||
|
||||
size, err := out.ReadFrom(encReader)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
ret["Error"] = err
|
||||
return ret
|
||||
}
|
||||
|
||||
app.Log("Read %s", size)
|
||||
|
||||
var contRaw []byte = out.Bytes()
|
||||
ret["ContentRaw"] = contRaw
|
||||
|
||||
if ret["Content-Type"] == "application/json" {
|
||||
var contJson interface{}
|
||||
|
||||
err = json.Unmarshal(contRaw, &contJson)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
ret["Error"] = err
|
||||
return ret
|
||||
}
|
||||
|
||||
ret["ContentJson"] = contJson
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (app *App) CmpHttpTestSnip(parm any) (any, error) {
|
||||
var err error
|
||||
|
||||
cli, err := app.SnipGetCli(parm)
|
||||
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"status": "error",
|
||||
"error" : "Not client found",
|
||||
}, err
|
||||
}
|
||||
|
||||
url, err := app.ConfGetStr("httpTest", "url")
|
||||
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"status": "error",
|
||||
"error" : "Not test URL",
|
||||
}, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
var a map[string]interface{}
|
||||
|
||||
a = app.HttpGet(url)
|
||||
|
||||
app.Log(a)
|
||||
|
||||
app.HttpWebSockSendTo(cli, "cmpHttpTest", map[string]interface{}{
|
||||
"status" : "response",
|
||||
"response": a,
|
||||
})
|
||||
}()
|
||||
|
||||
|
||||
return map[string]interface{}{
|
||||
"status" : "request",
|
||||
"request": url,
|
||||
}, nil
|
||||
}
|
288
cmpSnipper/cmpSnippetSshCli.go
Normal file
288
cmpSnipper/cmpSnippetSshCli.go
Normal file
@@ -0,0 +1,288 @@
|
||||
|
||||
package cmpSnipper
|
||||
|
||||
import (
|
||||
"io"
|
||||
"bufio"
|
||||
"strings"
|
||||
"net"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type cmpSshCliStruct struct {
|
||||
Host string
|
||||
Connect *ssh.Client
|
||||
Session *ssh.Session
|
||||
Output *bufio.Reader
|
||||
}
|
||||
|
||||
|
||||
func (app *App) SshAddHostKey(host string, remote net.Addr, pubKey ssh.PublicKey) error {
|
||||
app.Log(pubKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *App) SshConnReal(cmpSshCli *cmpSshCliStruct, host string, keyfile string) error {
|
||||
var err error
|
||||
|
||||
cmpSshCli.Host = host
|
||||
|
||||
key, err := app.FileReadLimit(keyfile, 1048576)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
config := &ssh.ClientConfig{
|
||||
User: "root",
|
||||
Auth: []ssh.AuthMethod{
|
||||
// HostKeyCallback: InsecureIgnoreHostKey(),
|
||||
// ssh.Password("yourpassword"),
|
||||
ssh.PublicKeys(signer),
|
||||
},
|
||||
// HostKeyCallback: ssh.FixedHostKey(hostKey),
|
||||
HostKeyCallback: ssh.HostKeyCallback(func(host string, remote net.Addr, key ssh.PublicKey) error {
|
||||
app.SshAddHostKey(host, remote, key)
|
||||
|
||||
return nil
|
||||
}),
|
||||
}
|
||||
|
||||
cmpSshCli.Connect, err = ssh.Dial("tcp", cmpSshCli.Host, config)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *App) SshSession(cmpSshCli *cmpSshCliStruct) error {
|
||||
var err error
|
||||
|
||||
cmpSshCli.Session, err = cmpSshCli.Connect.NewSession()
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// defer cmpSshCli.Session.Close()
|
||||
|
||||
modes := ssh.TerminalModes{
|
||||
ssh.ECHO: 0,
|
||||
}
|
||||
|
||||
err = cmpSshCli.Session.RequestPty("xterm", 50, 80, modes)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// sshIn, err := session.StdinPipe()
|
||||
// if err != nil {
|
||||
// app.Log(err)
|
||||
// return err
|
||||
// }
|
||||
|
||||
sshOut, err := cmpSshCli.Session.StdoutPipe()
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
sshErr, err := cmpSshCli.Session.StderrPipe()
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
output := io.MultiReader(sshOut, sshErr)
|
||||
|
||||
cmpSshCli.Output = bufio.NewReader(output)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *App) SshConn(host string, keyfile string) (int, error) {
|
||||
var err error
|
||||
|
||||
// app.Log(url)
|
||||
|
||||
var cmpSshCli cmpSshCliStruct
|
||||
|
||||
err = app.SshConnReal(&cmpSshCli, host, keyfile)
|
||||
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
err = app.SshSession(&cmpSshCli)
|
||||
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
app.SshList = append(app.SshList, cmpSshCli)
|
||||
|
||||
app.Log("Append new")
|
||||
|
||||
return len(app.SshList)-1, nil
|
||||
}
|
||||
|
||||
func (app *App) SshExec(cmpWbsCli cmpWbsCliStruct, idx int, cma []string) (error) {
|
||||
var err error
|
||||
|
||||
cmd := strings.Join(cma, " ")
|
||||
|
||||
cmpSshCli := app.SshList[idx]
|
||||
|
||||
// app.Log("idx: '%s', '%s'", idx, cmpSshCli.Host)
|
||||
|
||||
err = cmpSshCli.Session.Start(cmd)
|
||||
|
||||
if err != nil {
|
||||
app.Log(err)
|
||||
return err
|
||||
}
|
||||
|
||||
res := map[string]interface{}{
|
||||
"string": nil,
|
||||
}
|
||||
|
||||
var bli []byte
|
||||
var sli string
|
||||
|
||||
for {
|
||||
bli, _, err = cmpSshCli.Output.ReadLine()
|
||||
|
||||
if err != nil {
|
||||
app.Log("Complete")
|
||||
break
|
||||
}
|
||||
|
||||
sli = string(bli)
|
||||
|
||||
app.Log(sli)
|
||||
|
||||
res["string"] = sli
|
||||
|
||||
app.HttpWebSockSendTo(cmpWbsCli, "cmpSshTest", res)
|
||||
}
|
||||
|
||||
cmpSshCli.Session.Wait()
|
||||
|
||||
app.Log("Free resource SshList[" + string(idx) + "]")
|
||||
|
||||
cmpSshCli.Session.Close()
|
||||
|
||||
cmpSshCli.Connect.Close()
|
||||
|
||||
|
||||
app.Log("Remove SshList[" + string(idx) + "]")
|
||||
|
||||
var list []cmpSshCliStruct
|
||||
|
||||
for i, li := range app.SshList {
|
||||
if i == idx {
|
||||
continue
|
||||
}
|
||||
|
||||
list = append(list, li)
|
||||
}
|
||||
|
||||
app.SshList = list
|
||||
|
||||
app.Log("End")
|
||||
|
||||
// done <- true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *App) CmpSshTestSnip(parm any) (any, error) {
|
||||
var err error
|
||||
|
||||
// var ifcIM map[string]interface{} = parm
|
||||
|
||||
cli, err := app.SnipGetCli(parm)
|
||||
|
||||
// app.Log(cli)
|
||||
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"string": "Not client found",
|
||||
}, err
|
||||
}
|
||||
|
||||
|
||||
host, err := app.ConfGetStr("sshTestHost", "HostPort")
|
||||
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"string": "Not set sshTestHost.HostPort",
|
||||
}, err
|
||||
}
|
||||
|
||||
keyfile, err := app.ConfGetStr("sshTestHost", "PrivateKeyFile")
|
||||
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"string": "Not set sshTestHost.PrivateKeyFile",
|
||||
}, err
|
||||
}
|
||||
|
||||
cmi, err := app.ConfGetIfc("sshTestHost", "Command")
|
||||
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"string": "Not set sshTestHost.Command",
|
||||
}, err
|
||||
}
|
||||
|
||||
cml := cmi.([]interface{})
|
||||
|
||||
cma := make([]string, len(cml))
|
||||
|
||||
for i, v := range cml {
|
||||
cma[i] = v.(string)
|
||||
}
|
||||
|
||||
/*
|
||||
if cma[0] == "none" {
|
||||
return map[string]interface{}{
|
||||
"string": "Can't get command",
|
||||
}, err
|
||||
}
|
||||
*/
|
||||
|
||||
idx, err := app.SshConn(host, keyfile)
|
||||
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"string": "Connection to '" + host + "' failed",
|
||||
}, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
app.SshExec(cli, idx, cma)
|
||||
}()
|
||||
|
||||
app.Log("Wait")
|
||||
|
||||
return map[string]interface{}{
|
||||
"string": "Launch: " + strings.Join(cma, " "),
|
||||
}, nil
|
||||
}
|
12
go.mod
Normal file
12
go.mod
Normal file
@@ -0,0 +1,12 @@
|
||||
module t/z
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.13.0 // indirect
|
10
go.sum
Normal file
10
go.sum
Normal file
@@ -0,0 +1,10 @@
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
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/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
28
main.go
Normal file
28
main.go
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"os"
|
||||
|
||||
"t/z/cmpSnipper"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var app cmpSnipper.App;
|
||||
var err error
|
||||
|
||||
err = app.Prep()
|
||||
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = app.Proc()
|
||||
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
34
plug/CmpPlug1/CmpPlug1.go
Normal file
34
plug/CmpPlug1/CmpPlug1.go
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
// "net/html"
|
||||
)
|
||||
|
||||
type CmpPlug struct {
|
||||
Log func(any, ...interface{})
|
||||
}
|
||||
|
||||
var plg CmpPlug
|
||||
|
||||
func CmpPlug1Init(in int, f func(any, ...interface{}), ifc map[string]interface{} ) interface{} {
|
||||
plg.Log = f
|
||||
|
||||
ifc["Ccc"] = "Ddd"
|
||||
|
||||
fmt.Printf("This is CmpPlug1: %d\n", in)
|
||||
|
||||
return ifc
|
||||
}
|
||||
|
||||
func CmpPlug1Some() error {
|
||||
plg.Log("This is CmpPlug1Some")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Print(23)
|
||||
}
|
558
static/cmpSwoPage.css
Normal file
558
static/cmpSwoPage.css
Normal file
@@ -0,0 +1,558 @@
|
||||
body {
|
||||
color:#ccc;
|
||||
background-color:#222;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
@media (display-mode: fullscreen) {
|
||||
body {
|
||||
color:#ccc;
|
||||
background-color:#444;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
button {
|
||||
background-color:transparent;
|
||||
border:1px solid grey;
|
||||
border-radius:3px;
|
||||
color: white;
|
||||
width:24px;
|
||||
height:24px;
|
||||
font-size:18px;
|
||||
}
|
||||
button:hover {
|
||||
background-color:transparent;
|
||||
border:1px solid white;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
input[type="checkbox"]:checked,
|
||||
input[type="checkbox"]:not(:checked),
|
||||
input[type="radio"]:checked,
|
||||
input[type="radio"]:not(:checked)
|
||||
{
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
input[type="checkbox"]:checked + label,
|
||||
input[type="checkbox"]:not(:checked) + label,
|
||||
input[type="radio"]:checked + label,
|
||||
input[type="radio"]:not(:checked) + label {
|
||||
// display: inline-block;
|
||||
position: relative;
|
||||
padding-left: 28px;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:before,
|
||||
input[type="checkbox"]:not(:checked) + label:before,
|
||||
input[type="radio"]:checked + label:before,
|
||||
input[type="radio"]:not(:checked) + label:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 1px solid green;
|
||||
background-color: #444;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:before,
|
||||
input[type="checkbox"]:not(:checked) + label:before {
|
||||
border-radius: 4px;
|
||||
}
|
||||
input[type="radio"]:checked + label:before,
|
||||
input[type="radio"]:not(:checked) + label:before {
|
||||
border-radius: 100%;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:after,
|
||||
input[type="checkbox"]:not(:checked) + label:after,
|
||||
input[type="radio"]:checked + label:after,
|
||||
input[type="radio"]:not(:checked) + label:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
-webkit-transition: all 0.2s ease;
|
||||
-moz-transition: all 0.2s ease;
|
||||
-o-transition: all 0.2s ease;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:after,
|
||||
input[type="checkbox"]:not(:checked) + label:after {
|
||||
left: 3px;
|
||||
top: 4px;
|
||||
width: 10px;
|
||||
height: 5px;
|
||||
border-radius: 1px;
|
||||
border-left: 4px solid #ccc;
|
||||
border-bottom: 4px solid #ccc;
|
||||
-webkit-transform: rotate(-45deg);
|
||||
-moz-transform: rotate(-45deg);
|
||||
-o-transform: rotate(-45deg);
|
||||
-ms-transform: rotate(-45deg);
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
input[type="radio"]:checked + label:after,
|
||||
input[type="radio"]:not(:checked) + label:after {
|
||||
left: 5px;
|
||||
top: 5px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 100%;
|
||||
background-color: #e145a3;
|
||||
}
|
||||
input[type="checkbox"]:not(:checked) + label:after,
|
||||
input[type="radio"]:not(:checked) + label:after {
|
||||
opacity: 0;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:after,
|
||||
input[type="radio"]:checked + label:after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
table tr.odd:nth-child(2n) {
|
||||
background: #2f2f2f;
|
||||
}
|
||||
|
||||
table tr.odd:hover {
|
||||
background: #282828;
|
||||
}
|
||||
|
||||
table tbody.odd:nth-child(2n) {
|
||||
background: #2f2f2f;
|
||||
}
|
||||
|
||||
table tbody.odd:hover {
|
||||
background: #282828;
|
||||
}
|
||||
|
||||
table tr td {
|
||||
padding:4px;
|
||||
}
|
||||
|
||||
a { color: #37a4a4; text-decoration:none; }
|
||||
a:visited { color: #37a4a4; text-decoration:none; }
|
||||
|
||||
#bodyDiv {
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
border:0px solid black;
|
||||
}
|
||||
|
||||
#topper {
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
right:0;
|
||||
height:32px;
|
||||
border:0px solid grey;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
#topperTab {
|
||||
vertical-align:top;
|
||||
color:#222;
|
||||
background: {SWS_BGCOLOR};
|
||||
}
|
||||
|
||||
#topperTabLeft {
|
||||
width:33%;
|
||||
}
|
||||
|
||||
#topperTabCenter {
|
||||
width:33%;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
#topperTabRight {
|
||||
width:33%;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
#footer {
|
||||
background-color: #222;
|
||||
position:absolute;
|
||||
left:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
height:32px;
|
||||
overflow:hidden;
|
||||
border:0px solid grey;
|
||||
}
|
||||
|
||||
#footerTab {
|
||||
margin:0;
|
||||
padding:0;
|
||||
vertical-align:top;
|
||||
border:0px solid grey;
|
||||
}
|
||||
|
||||
#footerTabLeft {
|
||||
width:33%;
|
||||
}
|
||||
#footerTabCenter {
|
||||
width:33%;
|
||||
text-align:center;
|
||||
}
|
||||
#footerTabRight {
|
||||
width:33%;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
/***********************/
|
||||
|
||||
#leftMenu {
|
||||
position:absolute;
|
||||
top:32px;
|
||||
left:0px;
|
||||
width:142px;
|
||||
bottom:32px;
|
||||
border:0px solid grey;
|
||||
padding:0px;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
#leftMenu input[type=button].leftMenuButton {
|
||||
white-space: normal;
|
||||
padding:4px 14px 4px 14px;
|
||||
border:1px solid grey;
|
||||
border-radius:4px;
|
||||
background: #333;
|
||||
color:#eee;
|
||||
display:block;
|
||||
width:138px;
|
||||
margin:4px;
|
||||
}
|
||||
|
||||
#leftMenu button.leftMenuButton {
|
||||
white-space: normal;
|
||||
padding:4px 14px 4px 14px;
|
||||
border:1px solid grey;
|
||||
border-radius:4px;
|
||||
background: #333;
|
||||
color:#eee;
|
||||
display:block;
|
||||
width:138px;
|
||||
height:100%;
|
||||
margin:4px;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
#leftMenu a.leftMenuLink {
|
||||
white-space: normal;
|
||||
padding:4px 14px 4px 14px;
|
||||
border:0px solid grey;
|
||||
border-radius:4px;
|
||||
display:block;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
|
||||
#leftMenu div {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
#leftMenu .menuNotifyLab {
|
||||
border: 1px solid grey;
|
||||
border-radius: 4px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: red;
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
#leftMenu .menuNotifyLabAnim1 {
|
||||
animation-duration: 0.8s;
|
||||
animation-name: menuNotifyLabAnim1f;
|
||||
animation-timing-function: linear;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
|
||||
@keyframes menuNotifyLabAnim1f {
|
||||
from {
|
||||
bottom: 500px;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
#leftMenu .menuNotifyLabAnim2 {
|
||||
animation-duration: 0.6s;
|
||||
animation-name: menuNotifyLabAnim2f;
|
||||
animation-timing-function: linear;
|
||||
}
|
||||
|
||||
@keyframes menuNotifyLabAnim2f {
|
||||
from {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
50% {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
to {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
#leftMenu .menuNotifyLabHide {
|
||||
opacity:0;
|
||||
animation-duration: 0.6s;
|
||||
animation-name: menuNotifyLabAnim3f;
|
||||
animation-timing-function: linear;
|
||||
}
|
||||
|
||||
@keyframes menuNotifyLabAnim3f {
|
||||
from {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
to {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
|
||||
opacity:0;
|
||||
}
|
||||
}
|
||||
|
||||
.leftMenuBlock {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin-top:4px;
|
||||
margin-bottom:8px;
|
||||
padding-bottom:8px;
|
||||
}
|
||||
|
||||
div.leftMenuBlockName {
|
||||
display: block;
|
||||
}
|
||||
|
||||
button.leftMenuBlockName {
|
||||
display: block;
|
||||
border:0;
|
||||
}
|
||||
|
||||
.leftMenuBlockNameButton {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right:1px;
|
||||
|
||||
border:1px solid green;
|
||||
border-radius:12px;
|
||||
padding:0px;
|
||||
width :24px;
|
||||
height :24px;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
.leftMenuBlockHide > .leftMenuBlockBody {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.leftMenuBlockBody {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
|
||||
#mainRoot {
|
||||
position:absolute;
|
||||
top:32px;
|
||||
left:150px;
|
||||
right:0;
|
||||
bottom:32px;
|
||||
border:1px solid grey;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
|
||||
input[type=text] {
|
||||
background: #333;
|
||||
color:#eee;
|
||||
}
|
||||
|
||||
input[type=button] {
|
||||
padding:4px 14px 4px 14px;
|
||||
border:1px solid grey;
|
||||
border-radius:4px;
|
||||
background: #333;
|
||||
color:#eee;
|
||||
}
|
||||
|
||||
.headWord {
|
||||
display:inline-block;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.footerWord {
|
||||
display:inline-block;
|
||||
overflow:hidden;
|
||||
padding:0 2px 0 2px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********/
|
||||
|
||||
#page {
|
||||
z-index:20;
|
||||
position:fixed;
|
||||
top:32px;
|
||||
left:2px;
|
||||
right:2px;
|
||||
bottom:0;
|
||||
border:1px solid #000;
|
||||
border-radius:4px;
|
||||
background:#222;
|
||||
padding:6px;
|
||||
}
|
||||
|
||||
#pageBody {
|
||||
border:0px solid red;
|
||||
overflow:auto;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
#topRight {
|
||||
z-index:10;
|
||||
position:fixed;
|
||||
background:#000;
|
||||
top:-4px;
|
||||
left:76%;
|
||||
right:80px;
|
||||
bottom:0px;
|
||||
overflow:auto;
|
||||
border:1px solid #000;
|
||||
border-radius:4px;
|
||||
padding:8px;
|
||||
opacity:0.8;
|
||||
}
|
||||
|
||||
#topRight:hover {
|
||||
z-index:50;
|
||||
border:1px solid green;
|
||||
}
|
||||
|
||||
#topCent {
|
||||
z-index:10;
|
||||
position:fixed;
|
||||
background:#222;
|
||||
top:0;
|
||||
left:20%;
|
||||
right:20%;
|
||||
border:1px solid #222;
|
||||
padding:8px;
|
||||
}
|
||||
|
||||
#topCent:hover {
|
||||
z-index:50;
|
||||
}
|
||||
|
||||
#topLeft {
|
||||
z-index:10;
|
||||
position:fixed;
|
||||
background:#000;
|
||||
top:-6px;
|
||||
left:-2px;
|
||||
right:80%;
|
||||
border:1px solid #444;
|
||||
padding:8px;
|
||||
}
|
||||
|
||||
#topLeft:hover {
|
||||
z-index:50;
|
||||
border:1px solid green;
|
||||
}
|
||||
|
||||
#srvDate {
|
||||
animation-duration: 3s;
|
||||
animation-name: an1;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
#srvTime {
|
||||
animation-duration: 3s;
|
||||
animation-name: an1;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
@keyframes an1 {
|
||||
from {
|
||||
letter-spacing: 8px;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
to {
|
||||
letter-spacing: normal;
|
||||
font-size: inhrerit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******/
|
||||
|
||||
.buttonIco {
|
||||
border:1px solid grey;
|
||||
border-radius:4px;
|
||||
padding:2px;
|
||||
margin:0;
|
||||
min-width:54px;
|
||||
background-color:transparent;
|
||||
color:white;
|
||||
font-size:16px;
|
||||
}
|
||||
|
||||
/*******/
|
||||
|
||||
#diag {
|
||||
z-index:50;
|
||||
position:fixed;
|
||||
border:1px solid red;
|
||||
border-radius:8px;
|
||||
background-color:#222;
|
||||
top:20px;
|
||||
left:20px;
|
||||
min-width:640px;
|
||||
min-height:480px;
|
||||
overflow:hidden;
|
||||
}
|
809
static/cmpSwoPage.js
Normal file
809
static/cmpSwoPage.js
Normal file
@@ -0,0 +1,809 @@
|
||||
class cmpSwoPage {
|
||||
constructor() {
|
||||
this.cmpSwoOnConnect = [];
|
||||
this.cmpSwoOnDisconnect = [];
|
||||
|
||||
this.cmpOnLoad();
|
||||
}
|
||||
|
||||
cmpSwoPageInit() {
|
||||
this.snip = {};
|
||||
|
||||
if(!this.sws_sta_prefix)
|
||||
this.sws_sta_prefix = "go-prefix/static/";
|
||||
|
||||
if(!this.sws_dyn_prefix)
|
||||
this.sws_dyn_prefix = "go-prefix/ws";
|
||||
|
||||
this.connect();
|
||||
|
||||
|
||||
this.git = null;
|
||||
|
||||
this.cmpSwoTaskListInit();
|
||||
|
||||
this.srvTime = 0;
|
||||
}
|
||||
|
||||
connect() {
|
||||
var serv = "";
|
||||
|
||||
if(window.location.protocol == "https:")
|
||||
serv = "wss://";
|
||||
else
|
||||
serv = "ws://"
|
||||
|
||||
serv += window.location.host + "/" + this.sws_dyn_prefix ;
|
||||
|
||||
this.wsrv = new WebSocket(serv);
|
||||
|
||||
this.wsrv.onopen = this.onopen.bind (this);
|
||||
this.wsrv.onclose = this.onclose.bind (this);
|
||||
this.wsrv.onmessage = this.onmessage.bind (this);
|
||||
this.wsrv.onerror = this.onerror.bind (this);
|
||||
|
||||
this.WSState(1);
|
||||
}
|
||||
|
||||
onopen(evt) {
|
||||
console.log("Connected to WebSocket server");
|
||||
|
||||
for(var i = 0; i < this.cmpSwoOnConnect.length; i++) {
|
||||
(this.cmpSwoOnConnect[i])();
|
||||
}
|
||||
|
||||
if(this.pprm == "only-connect")
|
||||
return;
|
||||
|
||||
// this.gitInfoReq();
|
||||
|
||||
// this.leftMenuReq();
|
||||
|
||||
// this.contentReq();
|
||||
}
|
||||
|
||||
onclose(evt) {
|
||||
for(var i = 0; i < this.cmpSwoOnDisconnect.length; i++) {
|
||||
(this.cmpSwoOnDisconnect[i])();
|
||||
}
|
||||
|
||||
console.log("Disconnected");
|
||||
|
||||
console.log("Reason: ", evt);
|
||||
|
||||
if(!this.connInterval) {
|
||||
setTimeout(this.connect.bind(this), 100);
|
||||
}
|
||||
}
|
||||
|
||||
onmessage(evt) {
|
||||
// console.log('Retrieved data from server: ' + evt.data);
|
||||
|
||||
var obj = null;
|
||||
|
||||
if(!evt.data) {
|
||||
return console.log("Empty answer");
|
||||
}
|
||||
|
||||
try {
|
||||
obj = JSON.parse(evt.data);
|
||||
} catch(e) {
|
||||
console.log(evt);
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
if(!obj) {
|
||||
console.log("Invalid JSON");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!obj.snip) {
|
||||
console.log("Undefine/empty obj.snip", obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if(obj.task) {
|
||||
console.log("Recv snip: " + obj.snip, "Tasked");
|
||||
|
||||
if(this.cmpSwoTaskListProc(obj) == 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(obj.snip != "swoTick1000") {
|
||||
console.log("Recv snip: " + obj.snip, obj);
|
||||
}
|
||||
|
||||
if(obj.errors) {
|
||||
console.log("Error: ", obj.errors);
|
||||
}
|
||||
|
||||
if(!obj.result) {
|
||||
return console.log("Empty result");
|
||||
}
|
||||
|
||||
if(this.snip[obj.snip]) {
|
||||
console.log("Call this.snip[" + obj.snip + "].rcv");
|
||||
return (this.snip[obj.snip].rcv).bind(this, obj.result);
|
||||
}
|
||||
|
||||
do {
|
||||
var snipFn = obj.snip + "Rcv";
|
||||
|
||||
if(typeof(this[snipFn]) != "function")
|
||||
break;
|
||||
|
||||
console.log("Call this[" + snipFn + "]");
|
||||
// console.log(this[snipFn])
|
||||
|
||||
return this[snipFn](obj.result);
|
||||
} while(0);
|
||||
|
||||
return console.log("Unknown snip '" + obj.snip + "'");
|
||||
}
|
||||
|
||||
onerror(evt, e) {
|
||||
console.log('Error occured: ', evt.data);
|
||||
console.log(evt);
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
// Util
|
||||
|
||||
setFavicon(i) {
|
||||
var link = document.querySelector("link[rel~='icon']");
|
||||
|
||||
if (!link) {
|
||||
link = document.createElement('link');
|
||||
link.rel = 'icon';
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
/*
|
||||
if(i)
|
||||
link.href = '/go-prefix/static/img/umbrella-color.png';
|
||||
else
|
||||
link.href = '/go-prefix/static/img/umbrella-black.png';
|
||||
|
||||
console.log(link.href);
|
||||
*/
|
||||
}
|
||||
|
||||
WSState(z) {
|
||||
if(!this.wsrv) {
|
||||
console.log("WebSocket is NULL");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var m = "";
|
||||
|
||||
switch(this.wsrv.readyState) {
|
||||
case this.wsrv.CONNECTING : m = "WebSocket state is CONNECTING" ; break;
|
||||
case this.wsrv.OPEN : m = "WebSocket state is OPEN" ; break;
|
||||
case this.wsrv.CLOSING : m = "WebSocket state is CLOSING" ; break;
|
||||
case this.wsrv.CLOSED : m = "WebSocket state is CLOSED" ; break;
|
||||
default : m = "WebSocket state is UNKNOWN" ; break;
|
||||
}
|
||||
|
||||
if(z)
|
||||
console.log(m);
|
||||
|
||||
if(this.wsrv.readyState == this.wsrv.OPEN) {
|
||||
this.setFavicon(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
this.setFavicon(1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
readySnip() {
|
||||
if(!this.wsrv) {
|
||||
console.log("WebSocket is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this.wsrv.readyState == this.wsrv.OPEN)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
reqSnip(snip, obj) {
|
||||
if(this.WSState()) {
|
||||
return this.WSState(1);
|
||||
}
|
||||
|
||||
if(obj) {
|
||||
obj.snip = snip;
|
||||
}
|
||||
else {
|
||||
obj = {
|
||||
snip: snip,
|
||||
};
|
||||
}
|
||||
|
||||
console.log("Send snip: " + obj.snip, obj);
|
||||
|
||||
var str = JSON.stringify(obj);
|
||||
|
||||
return this.wsrv.send(str);
|
||||
}
|
||||
|
||||
|
||||
gitInfoReq() {
|
||||
return this.reqSnip("gitInfo");
|
||||
}
|
||||
|
||||
gitInfoRcv(obj) {
|
||||
var n;
|
||||
|
||||
if(!this.git) {
|
||||
this.git = obj;
|
||||
}
|
||||
|
||||
if(obj.gitStatus) {
|
||||
if((n = document.getElementById("gitStatus"))) {
|
||||
n.innerHTML = obj.gitStatus;
|
||||
}
|
||||
|
||||
if((n = document.getElementById("gitTitl"))) {
|
||||
n.setAttribute("title", obj.gitStatus);
|
||||
n.style.color = (obj.gitStatus == "treeClean") ? "#86de74" : "#ff3b6b";
|
||||
}
|
||||
}
|
||||
|
||||
if(obj.gitTimeStamp) {
|
||||
if((n = document.getElementById("gitDate"))) {
|
||||
n.innerHTML = unixtimeToYYYYMMDD(obj.gitTimeStamp);
|
||||
|
||||
if(obj.gitTimeStamp != this.git.gitTimeStamp)
|
||||
n.style.color = "#ffff64";
|
||||
else
|
||||
n.style.color = "#86de74";
|
||||
}
|
||||
|
||||
if((n = document.getElementById("gitTime"))) {
|
||||
n.innerHTML = unixtimeToHHMMSS(obj.gitTimeStamp);
|
||||
|
||||
if(obj.gitTimeStamp != this.git.gitTimeStamp)
|
||||
n.style.color = "#ffff64";
|
||||
else
|
||||
n.style.color = "#86de74";
|
||||
}
|
||||
}
|
||||
|
||||
if(obj.gitCommit && (n = document.getElementById("gitCHID"))) {
|
||||
n.innerHTML = obj.gitCommit.substr(0, 8);
|
||||
|
||||
if(obj.gitTimeStamp != this.git.gitTimeStamp)
|
||||
n.style.color = "#ffff64";
|
||||
else
|
||||
n.style.color = "#86de74";
|
||||
}
|
||||
|
||||
if(obj.gitComment && (n = document.getElementById("gitComm"))) {
|
||||
n.innerHTML = obj.gitComment;
|
||||
|
||||
if(obj.gitTimeStamp != this.git.gitTimeStamp)
|
||||
n.style.color = "#ffff64";
|
||||
else
|
||||
n.style.color = "#86de74";
|
||||
}
|
||||
}
|
||||
|
||||
swoTick1000Rcv(obj) {
|
||||
var tzOff = checkTZ(0);
|
||||
|
||||
obj.ymd = unixtimeToYYYYMMDD(obj["time"] + tzOff);
|
||||
obj.hms = unixtimeToHHMMSS (obj["time"] + tzOff);
|
||||
|
||||
this.srvTime = obj["time"];
|
||||
|
||||
setNodeText("srvDate", obj, "ymd", 0);
|
||||
setNodeText("srvTime", obj, "hms", 0);
|
||||
}
|
||||
|
||||
timeReStyle(sta) {
|
||||
var n1 = document.getElementById("srvDate");
|
||||
var n2 = document.getElementById("srvTime");
|
||||
|
||||
if(sta == "connect") {
|
||||
if(n1) n1.style.color = "#86de74";
|
||||
if(n2) n2.style.color = "#86de74";
|
||||
}
|
||||
else {
|
||||
if(n1) n1.style.color = "#ff3b6b";
|
||||
if(n2) n2.style.color = "#ff3b6b";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Logic
|
||||
|
||||
swoSystemctlRestartSelfServiceReq() {
|
||||
this.reqSnip("swoSystemctlRestartSelfService");
|
||||
}
|
||||
|
||||
swoSystemctlRestartSelfServiceRcv() {
|
||||
;
|
||||
}
|
||||
|
||||
rand4dReq() {
|
||||
this.reqSnip("rand4d");
|
||||
}
|
||||
|
||||
rand4dRcv(obj) {
|
||||
return setNodeText("srvRand", obj, "rand4d");
|
||||
}
|
||||
|
||||
pingReq() {
|
||||
return this.reqSnip("ping");
|
||||
}
|
||||
|
||||
pingRcv(obj) {
|
||||
console.log("pingRcv", obj);
|
||||
}
|
||||
|
||||
/****************/
|
||||
|
||||
leftMenuNameClick(obj) {
|
||||
if(!obj)
|
||||
return console.log("No obj");
|
||||
|
||||
var nodeButton = null;
|
||||
var nodeBlock = null;
|
||||
var node = null;
|
||||
|
||||
// console.log(button);
|
||||
|
||||
if(obj.parentNode) {
|
||||
node = obj;
|
||||
}
|
||||
else if(obj?.target?.parentNode) {
|
||||
node = obj?.target;
|
||||
}
|
||||
|
||||
var mid = node.getAttribute("mid");
|
||||
|
||||
if(!mid)
|
||||
console.log("Can't get mid");
|
||||
|
||||
if(!this.leftMenu.list[mid])
|
||||
console.log("Invalid mid");
|
||||
|
||||
nodeBlock = this.leftMenu.list[mid].nodeBlock;
|
||||
nodeButton = this.leftMenu.list[mid].nodeButt;
|
||||
|
||||
if(!nodeBlock)
|
||||
return console.log("Invalid nodeBlock");
|
||||
|
||||
if(!nodeBlock.classList)
|
||||
return console.log("Invalid nodeBlock.classList");
|
||||
|
||||
if(!nodeBlock.classList.contains("leftMenuBlock"))
|
||||
return console.log("nodeBlock is not leftMenuBlock");
|
||||
|
||||
if(nodeBlock.classList.contains("leftMenuBlockHide")) {
|
||||
nodeBlock.classList.remove("leftMenuBlockHide");
|
||||
nodeButton.innerHTML = "-";
|
||||
}
|
||||
else {
|
||||
nodeBlock.classList.add("leftMenuBlockHide");
|
||||
nodeButton.innerHTML = "+";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
leftMenuItemLinkRend(obj, parn) {
|
||||
var link = dcrt({
|
||||
tag : "a" ,
|
||||
parn : parn ,
|
||||
id : obj?.id ,
|
||||
class: "leftMenuLink" ,
|
||||
href : obj.href ,
|
||||
html : obj.html
|
||||
});
|
||||
}
|
||||
|
||||
leftMenuItemRend(obj, parn) {
|
||||
if(obj.type == "link")
|
||||
return this.leftMenuItemLinkRend(obj, parn);
|
||||
|
||||
var cli = null;
|
||||
|
||||
if(this[obj.func]) {
|
||||
cli = this[obj.func].bind(this, obj.parm);
|
||||
}
|
||||
else {
|
||||
console.log("Invalid func '" + obj.func + "'");
|
||||
}
|
||||
|
||||
var cont = null;
|
||||
|
||||
if(obj.parn) {
|
||||
cont = dcrt({
|
||||
tag : "div",
|
||||
parn : parn,
|
||||
id : obj.parn
|
||||
});
|
||||
}
|
||||
else {
|
||||
cont = parn;
|
||||
}
|
||||
|
||||
var but = dcrt({
|
||||
tag : "button" ,
|
||||
parn : cont ,
|
||||
id : obj?.id ,
|
||||
class: "leftMenuButton" ,
|
||||
click: cli ,
|
||||
html : obj.html
|
||||
});
|
||||
|
||||
// but.setAttribute("onclick", "window.page." + obj.list[i].func + "();");
|
||||
}
|
||||
|
||||
leftMenuBlockRend(obj) {
|
||||
if(!this.leftMenuNodeRoot) {
|
||||
return console.log("No .leftMenuNodeRoot");
|
||||
}
|
||||
|
||||
var id = this.leftMenu.list.length;
|
||||
|
||||
var nodeBlock = dcrt({
|
||||
tag : "div",
|
||||
parn : this.leftMenuNodeRoot,
|
||||
class: "leftMenuBlock"
|
||||
});
|
||||
|
||||
if(!obj.view)
|
||||
nodeBlock.classList.add("leftMenuBlockHide");
|
||||
|
||||
var nodeButt = dcrt({
|
||||
mid : id ,
|
||||
tag : "button" ,
|
||||
parn : nodeBlock ,
|
||||
class: "leftMenuBlockNameButton",
|
||||
click: this.leftMenuNameClick.bind(this),
|
||||
html : "+"
|
||||
});
|
||||
|
||||
var nodeName = dcrt({
|
||||
mid : id ,
|
||||
tag : "button" ,
|
||||
parn : nodeBlock ,
|
||||
class: "leftMenuBlockName" ,
|
||||
click: this.leftMenuNameClick.bind(this),
|
||||
html : obj.name
|
||||
});
|
||||
|
||||
var nodeBody = dcrt({
|
||||
tag : "div",
|
||||
parn : nodeBlock,
|
||||
class: "leftMenuBlockBody"
|
||||
});
|
||||
|
||||
this.leftMenu.list[id] = {
|
||||
nodeBlock : nodeBlock ,
|
||||
nodeButt : nodeButt ,
|
||||
nodeName : nodeName ,
|
||||
nodeBody : nodeBody
|
||||
}
|
||||
|
||||
for(var i = 0; i < obj.list.length; i++) {
|
||||
this.leftMenuItemRend(obj.list[i], nodeBody);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
leftMenuReq() {
|
||||
this.reqSnip("leftMenu");
|
||||
}
|
||||
|
||||
leftMenuRcv(obj) {
|
||||
this.leftMenuNodeRoot = document.getElementById("leftMenu");
|
||||
|
||||
if(!this.leftMenuNodeRoot) {
|
||||
return console.log("No .leftMenuNodeRoot");
|
||||
}
|
||||
|
||||
this.leftMenuNodeRoot.innerHTML = "";
|
||||
|
||||
this.leftMenu = {
|
||||
list: []
|
||||
}
|
||||
|
||||
if(!obj.list) {
|
||||
return console.log("No obj.list");
|
||||
}
|
||||
|
||||
for(var i = 0; i < obj.list.length; i++) {
|
||||
this.leftMenuBlockRend(obj.list[i]);
|
||||
}
|
||||
|
||||
if(obj.defaultPage) {
|
||||
var parm = {};
|
||||
|
||||
if(obj.defaultPageParm)
|
||||
parm = obj.defaultPageParm;
|
||||
|
||||
this.pageContent = obj.defaultPage;
|
||||
|
||||
this.contentReq(obj.defaultPage, parm);
|
||||
}
|
||||
}
|
||||
|
||||
/****************/
|
||||
|
||||
swoTaskListRcv(obj) {
|
||||
console.log(obj);
|
||||
}
|
||||
|
||||
swoTaskListReq() {
|
||||
this.reqSnip("swoTaskList");
|
||||
}
|
||||
|
||||
swoLockListRcv(obj) {
|
||||
console.log(obj);
|
||||
}
|
||||
|
||||
swoLockListReq() {
|
||||
this.reqSnip("swoLockList");
|
||||
}
|
||||
|
||||
swoSetLogFileNameReq() {
|
||||
this.reqSnip("swoSetLogFileName");
|
||||
}
|
||||
|
||||
swoSetLogFileNameRcv(obj) {
|
||||
console.log(obj);
|
||||
}
|
||||
|
||||
/****************/
|
||||
|
||||
cmpSwoTaskListInit() {
|
||||
this.cmpSwoTaskList = [];
|
||||
|
||||
this.cmpSwoTaskListNode = document.getElementById("cmpSwoTaskList");
|
||||
|
||||
if(!this.cmpSwoTaskListNode) {
|
||||
console.log("No cmpSwoTaskList");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cmpSwoTaskListRendItem(name, obj) {
|
||||
if(!this.cmpSwoTaskListNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cmpSwoTaskList[name].node = dcrt({
|
||||
tag : "span",
|
||||
parn : this.cmpSwoTaskListNode,
|
||||
html : "[" + obj.snip + "]"
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cmpSwoTaskListProc(obj) {
|
||||
// if(!this.cmpSwoTaskListNode) {
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
var name = obj.task.task;
|
||||
|
||||
if(obj.task.stat == "work") {
|
||||
var tbj = {
|
||||
snip: obj.snip,
|
||||
node: null
|
||||
};
|
||||
|
||||
this.cmpSwoTaskList[name] = tbj;
|
||||
|
||||
// console.log("Append cmpSwoTaskList node " + name);
|
||||
this.cmpSwoTaskListRendItem(name, obj);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(obj.task.stat == "complete") {
|
||||
if(this.cmpSwoTaskList[name]?.node) {
|
||||
// console.log("Remove cmpSwoTaskList node " + name + " by complete");
|
||||
this.cmpSwoTaskList[name].node.remove();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(obj.task.stat == "lock") {
|
||||
if(this.cmpSwoTaskList[name]?.node) {
|
||||
// console.log("Remove cmpSwoTaskList node " + name + " by lock");
|
||||
this.cmpSwoTaskList[name].node.remove();
|
||||
}
|
||||
|
||||
// console.log(obj);
|
||||
|
||||
var cause = obj?.lock?.cause;
|
||||
|
||||
if(cause) {
|
||||
alert("Заблокировано: " + cause);
|
||||
}
|
||||
else {
|
||||
alert("Заблокировано");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if(obj.task.stat == "error") {
|
||||
// ;
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
console.log("Unknown obj.task.stat: " + obj.task.stat);
|
||||
console.log(obj);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cmpOnLoad() {
|
||||
console.log("OnLoad")
|
||||
|
||||
this.nodeDataHeadRoot = document.getElementById("tblheadroot");
|
||||
this.nodeDataBodyRoot = document.getElementById("tblbodyroot");
|
||||
|
||||
dcrt({
|
||||
tag : "h4",
|
||||
html : "Default page title",
|
||||
style: "margin:4px;",
|
||||
parn : this.nodeDataHeadRoot
|
||||
});
|
||||
|
||||
dcrt({
|
||||
tag : "span",
|
||||
html : "Default page data",
|
||||
parn : this.nodeDataBodyRoot
|
||||
});
|
||||
}
|
||||
|
||||
cmpSshTestReq() {
|
||||
this.nodeDataHeadRoot.innerHTML = "";
|
||||
this.nodeDataBodyRoot.innerHTML = "";
|
||||
|
||||
if(!this.nodeSshTestHead) {
|
||||
this.nodeSshTestHead = dcrt({
|
||||
tag : "h4",
|
||||
style: "margin:4px;",
|
||||
html : "Test SSH",
|
||||
parn : this.nodeDataHeadRoot
|
||||
});
|
||||
|
||||
this.nodeSshTestBody = dcrt({
|
||||
tag : "tbody"
|
||||
});
|
||||
|
||||
this.nodeSshTestRoot = dcrt({
|
||||
tag : "table",
|
||||
parn : this.nodeDataBodyRoot,
|
||||
child: [ this.nodeSshTestBody ]
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.nodeDataHeadRoot.appendChild(this.nodeSshTestHead)
|
||||
this.nodeDataBodyRoot.appendChild(this.nodeSshTestRoot)
|
||||
this.nodeSshTestBody.innerHTML = "";
|
||||
}
|
||||
|
||||
this.reqSnip("cmpSshTest");
|
||||
}
|
||||
|
||||
cmpSshTestRcv(obj) {
|
||||
dcrt({
|
||||
tag : "tr",
|
||||
parn : this.nodeSshTestBody,
|
||||
child: [{
|
||||
tag : "td",
|
||||
html : obj.string
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
cmpHttpTestReq() {
|
||||
this.nodeDataHeadRoot.innerHTML = "";
|
||||
this.nodeDataBodyRoot.innerHTML = "";
|
||||
|
||||
if(!this.nodeHttpTestHead) {
|
||||
this.nodeHttpTestHead = dcrt({
|
||||
tag : "h4",
|
||||
style: "margin:4px;",
|
||||
html : "Test HTTP",
|
||||
parn : this.nodeDataHeadRoot
|
||||
});
|
||||
|
||||
this.nodeHttpTestBody = dcrt({
|
||||
tag : "tbody"
|
||||
});
|
||||
|
||||
this.nodeHttpTestRoot = dcrt({
|
||||
tag : "table",
|
||||
parn : this.nodeDataBodyRoot,
|
||||
child: [ this.nodeHttpTestBody ]
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.nodeDataHeadRoot.appendChild(this.nodeHttpTestHead)
|
||||
this.nodeDataBodyRoot.appendChild(this.nodeHttpTestRoot)
|
||||
this.nodeHttpTestBody.innerHTML = "";
|
||||
}
|
||||
|
||||
this.reqSnip("cmpHttpTest");
|
||||
}
|
||||
|
||||
cmpHttpTestRcv(obj) {
|
||||
if(obj.status == "error") {
|
||||
dcrt({
|
||||
tag : "tr",
|
||||
parn : this.nodeHttpTestBody,
|
||||
child: [{
|
||||
tag : "td",
|
||||
html : obj.error
|
||||
}]
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(obj.status == "request") {
|
||||
dcrt({
|
||||
tag : "tr",
|
||||
parn : this.nodeHttpTestBody,
|
||||
child: [{
|
||||
tag : "td",
|
||||
html : obj.request
|
||||
}]
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(obj.status == "response") {
|
||||
dcrt({
|
||||
tag : "tr",
|
||||
parn : this.nodeHttpTestBody,
|
||||
child: [{
|
||||
tag : "td",
|
||||
child: [{
|
||||
tag : "pre",
|
||||
html : JSON.stringify(obj.response, null, 2)
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dcrt({
|
||||
tag : "tr",
|
||||
parn : this.nodeHttpTestBody,
|
||||
child: [{
|
||||
tag : "td",
|
||||
html : "Unknown status: '" + obj.status + "'"
|
||||
}]
|
||||
});
|
||||
|
||||
console.log(obj.status, obj)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// END class
|
||||
}
|
343
static/cmpSwoUtil.js
Normal file
343
static/cmpSwoUtil.js
Normal file
@@ -0,0 +1,343 @@
|
||||
|
||||
function unixtimeToYYYYMMDD(s) {
|
||||
var n;
|
||||
|
||||
if(s)
|
||||
n = new Date(s * 1000);
|
||||
else
|
||||
n = new Date();
|
||||
|
||||
var m = n.getMonth()+1;
|
||||
var d = n.getDate();
|
||||
|
||||
return (n.getFullYear()) + "-" + (m < 10 ? ("0" + m) : m) + "-" + (d < 10 ? ("0" + d) : d);
|
||||
}
|
||||
|
||||
function unixtimeToHHMMSS(s) {
|
||||
var n;
|
||||
|
||||
if(s)
|
||||
n = new Date(s * 1000);
|
||||
else
|
||||
n = new Date();
|
||||
|
||||
var h = n.getHours();
|
||||
var m = n.getMinutes();
|
||||
var s = n.getSeconds();
|
||||
|
||||
return (h < 10 ? ("0" + h) : h) + ":" + (m < 10 ? ("0" + m) : m) + ":" + (s < 10 ? ("0" + s) : s);
|
||||
}
|
||||
|
||||
function checkTZ(z) {
|
||||
if((new Date()).getTimezoneOffset())
|
||||
return 0;
|
||||
|
||||
if(z)
|
||||
console.log("Auto correct TimeZone");
|
||||
|
||||
return 12 * 60 * 60;
|
||||
}
|
||||
|
||||
function setNodeText(nn, obj, idx, q) {
|
||||
var n = null;
|
||||
|
||||
if(typeof q == "undefined")
|
||||
q = 1;
|
||||
|
||||
switch(typeof nn) {
|
||||
case "string":
|
||||
n = document.getElementById(nn);
|
||||
break;
|
||||
|
||||
case "object":
|
||||
if(nn.nodeType != 1)
|
||||
return console.log("Invalid node object");
|
||||
|
||||
n = nn;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return console.log("Invalid node type");
|
||||
}
|
||||
|
||||
if(!n) {
|
||||
if(q == 1)
|
||||
return console.log("No node '" + nn + "'");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!obj[idx])
|
||||
return;
|
||||
|
||||
n.innerHTML = obj[idx];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
function dpst(no, p) {
|
||||
var n = null;
|
||||
|
||||
do {
|
||||
if(p.before) {
|
||||
n = p.before;
|
||||
break;
|
||||
}
|
||||
|
||||
if(p.after) {
|
||||
n = p.after;
|
||||
break;
|
||||
}
|
||||
|
||||
if(p.parn) {
|
||||
n = p.parn;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
} while(0);
|
||||
|
||||
if(typeof(n) == "string") {
|
||||
n = document.getElementById(n);
|
||||
|
||||
if(!n)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(n.nodeType !== 1) {
|
||||
console.log("Invalid node type");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(p.before) {
|
||||
n.parentNode.insertBefore(no, n);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(p.after) {
|
||||
if(p.after.nextSibling)
|
||||
n.parentNode.insertBefore(no, n.nextSibling);
|
||||
else
|
||||
n.parentNode.appendChild(no);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(p.parn) {
|
||||
n.appendChild(no);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function dcrt(p) {
|
||||
var at = "";
|
||||
var no = null;
|
||||
var spc = {
|
||||
"tag" : 1,
|
||||
"html" : 1,
|
||||
"parn" : 1,
|
||||
"child" : 1,
|
||||
"class" : 1,
|
||||
|
||||
"after" : 1,
|
||||
"before" : 1,
|
||||
|
||||
"click" : 1,
|
||||
"keyup" : 1,
|
||||
"keypress" : 1,
|
||||
"change" : 1,
|
||||
"load" : 1,
|
||||
|
||||
"src" : 1
|
||||
}
|
||||
|
||||
if(!p.tag) {
|
||||
console.log("Empty .tag");
|
||||
return null;
|
||||
}
|
||||
|
||||
no = document.createElement(p.tag);
|
||||
|
||||
for(at in p) {
|
||||
if(spc[at])
|
||||
continue;
|
||||
|
||||
no.setAttribute(at, p[at]);
|
||||
}
|
||||
|
||||
if(p.class)
|
||||
no.className = p.class;
|
||||
|
||||
dpst(no, p);
|
||||
|
||||
if(p.html) {
|
||||
no.innerHTML = p.html;
|
||||
}
|
||||
|
||||
if(p.click) {
|
||||
no.addEventListener("click", p.click, false);
|
||||
}
|
||||
|
||||
if(p.keyup) {
|
||||
no.addEventListener("keyup", p.keyup, false);
|
||||
}
|
||||
|
||||
if(p.keypress) {
|
||||
no.addEventListener("keypress", p.keypress, false);
|
||||
}
|
||||
|
||||
if(p.change) {
|
||||
no.addEventListener("change", p.change, false);
|
||||
}
|
||||
|
||||
if(p.load) {
|
||||
no.addEventListener("load", p.load, false);
|
||||
// no.onload = p.load;
|
||||
}
|
||||
|
||||
if(p.src) {
|
||||
no.setAttribute("src", p.src);
|
||||
// no.src = p.src;
|
||||
}
|
||||
|
||||
if(!p.child)
|
||||
return no;
|
||||
|
||||
var ch = null;
|
||||
|
||||
for(at = 0; at < p.child.length; at++) {
|
||||
if(!p.child[at])
|
||||
continue;
|
||||
|
||||
if(!p.child[at].nodeType)
|
||||
ch = dcrt(p.child[at]);
|
||||
else
|
||||
ch = p.child[at]
|
||||
|
||||
if(!ch)
|
||||
continue;
|
||||
|
||||
no.appendChild(ch);
|
||||
}
|
||||
|
||||
return no;
|
||||
}
|
||||
|
||||
class diag {
|
||||
constructor(parm) {
|
||||
this.buildBody(parm);
|
||||
}
|
||||
|
||||
buildBody(parm) {
|
||||
var top = 0.8 * (window.innerHeight- 480)/2;
|
||||
var left = 1.0 * (window.innerWidth - 640)/2;
|
||||
|
||||
this.diagRoot = dcrt({
|
||||
tag : "div",
|
||||
parn : "body",
|
||||
id : "diag",
|
||||
style: "display:none; top:"+top+"px; left:"+left+"px;"
|
||||
});
|
||||
|
||||
this.diagHead = dcrt({
|
||||
tag : "div",
|
||||
style: "position:absolute; top:0px; left:-2px; right:-2px; height:20px; background:#000; padding:10px; font-weight:bold;",
|
||||
html : "DIALOG",
|
||||
parn : this.diagRoot
|
||||
});
|
||||
|
||||
this.diagBody = dcrt({
|
||||
tag : "div",
|
||||
style: "position:absolute; left:0; right:0; top:40px; bottom:40px; padding:6px; border:0px solid white;",
|
||||
parn : this.diagRoot,
|
||||
// child: parm.child
|
||||
});
|
||||
|
||||
this.diagFloor= dcrt({
|
||||
tag : "div",
|
||||
style: "position:absolute; left:-2px; right:-2px; bottom:0px; height:20px; background:#000; padding:10px;",
|
||||
parn : this.diagRoot
|
||||
});
|
||||
|
||||
do {
|
||||
if(!parm.head)
|
||||
break;
|
||||
|
||||
if(!parm.head.html)
|
||||
break;
|
||||
|
||||
this.diagHead.innerHTML = parm.head.html;
|
||||
} while(0);
|
||||
|
||||
do {
|
||||
if(!parm.body)
|
||||
break;
|
||||
|
||||
if(!parm.body.node)
|
||||
break;
|
||||
|
||||
parm.body.node.parn = this.diagBody;
|
||||
|
||||
dcrt(parm.body.node);
|
||||
} while(0);
|
||||
|
||||
do {
|
||||
if(!parm.floor)
|
||||
break;
|
||||
|
||||
if(!parm.floor.node)
|
||||
break;
|
||||
|
||||
parm.floor.node.parn = this.diagFloor;
|
||||
|
||||
dcrt(parm.floor.node);
|
||||
} while(0);
|
||||
|
||||
this.diagHead.addEventListener('mousedown', this.diagDraggable.bind(this), false);
|
||||
}
|
||||
|
||||
diagDraggable(e) {
|
||||
var e = e || window.event;
|
||||
|
||||
if(window.diag)
|
||||
window.diag.diagRoot.style.zIndex = 49;
|
||||
|
||||
window.diag = this;
|
||||
|
||||
this.diagInnerX = e.clientX + window.pageXOffset - this.diagRoot.offsetLeft;
|
||||
this.diagInnerY = e.clientY + window.pageYOffset - this.diagRoot.offsetTop;
|
||||
|
||||
this.diagHandMove = this.diagMove .bind(this);
|
||||
this.diagHandMouseUp = this.diagMouseUp.bind(this);
|
||||
|
||||
window.addEventListener('mousemove', this.diagHandMove , false);
|
||||
window.addEventListener('mouseup' , this.diagHandMouseUp, true);
|
||||
}
|
||||
|
||||
diagMouseUp(e) {
|
||||
window.removeEventListener('mousemove', this.diagHandMove);
|
||||
window.removeEventListener('mouseup' , this.diagHandMouseUp);
|
||||
}
|
||||
|
||||
diagMove(e) {
|
||||
this.diagRoot.style.zIndex = 50;
|
||||
this.diagRoot.style.position = 'fixed';
|
||||
this.diagRoot.style.left = e.clientX + window.pageXOffset - this.diagInnerX + 'px';
|
||||
this.diagRoot.style.top = e.clientY + window.pageYOffset - this.diagInnerY + 'px';
|
||||
}
|
||||
|
||||
show() {
|
||||
this.diagRoot.style.display = "block";
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.diagRoot.style.display = "none";
|
||||
}
|
||||
|
||||
// CLASS
|
||||
};
|
||||
|
333
static/default.css
Normal file
333
static/default.css
Normal file
@@ -0,0 +1,333 @@
|
||||
|
||||
body {
|
||||
color:#ccc;
|
||||
background-color:#222;
|
||||
font-size: 20px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
@media (display-mode: fullscreen) {
|
||||
body {
|
||||
color:#ccc;
|
||||
background-color:#444;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
input[type="checkbox"]:checked,
|
||||
input[type="checkbox"]:not(:checked),
|
||||
input[type="radio"]:checked,
|
||||
input[type="radio"]:not(:checked)
|
||||
{
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
input[type="checkbox"]:checked + label,
|
||||
input[type="checkbox"]:not(:checked) + label,
|
||||
input[type="radio"]:checked + label,
|
||||
input[type="radio"]:not(:checked) + label {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding-left: 28px;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:before,
|
||||
input[type="checkbox"]:not(:checked) + label:before,
|
||||
input[type="radio"]:checked + label:before,
|
||||
input[type="radio"]:not(:checked) + label:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 1px solid green;
|
||||
background-color: #444;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:before,
|
||||
input[type="checkbox"]:not(:checked) + label:before {
|
||||
border-radius: 4px;
|
||||
}
|
||||
input[type="radio"]:checked + label:before,
|
||||
input[type="radio"]:not(:checked) + label:before {
|
||||
border-radius: 100%;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:after,
|
||||
input[type="checkbox"]:not(:checked) + label:after,
|
||||
input[type="radio"]:checked + label:after,
|
||||
input[type="radio"]:not(:checked) + label:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
-webkit-transition: all 0.2s ease;
|
||||
-moz-transition: all 0.2s ease;
|
||||
-o-transition: all 0.2s ease;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:after,
|
||||
input[type="checkbox"]:not(:checked) + label:after {
|
||||
left: 3px;
|
||||
top: 4px;
|
||||
width: 10px;
|
||||
height: 5px;
|
||||
border-radius: 1px;
|
||||
border-left: 4px solid #ccc;
|
||||
border-bottom: 4px solid #ccc;
|
||||
-webkit-transform: rotate(-45deg);
|
||||
-moz-transform: rotate(-45deg);
|
||||
-o-transform: rotate(-45deg);
|
||||
-ms-transform: rotate(-45deg);
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
input[type="radio"]:checked + label:after,
|
||||
input[type="radio"]:not(:checked) + label:after {
|
||||
left: 5px;
|
||||
top: 5px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 100%;
|
||||
background-color: #e145a3;
|
||||
}
|
||||
input[type="checkbox"]:not(:checked) + label:after,
|
||||
input[type="radio"]:not(:checked) + label:after {
|
||||
opacity: 0;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:after,
|
||||
input[type="radio"]:checked + label:after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
table tr.odd:nth-child(2n) {
|
||||
background: #2f2f2f;
|
||||
}
|
||||
|
||||
table tr.odd:hover {
|
||||
background: #282828;
|
||||
}
|
||||
|
||||
table tr td {
|
||||
padding:4px;
|
||||
}
|
||||
|
||||
a { color: #37a4a4; text-decoration:none; }
|
||||
a:visited { color: #37a4a4; text-decoration:none; }
|
||||
|
||||
input[type=text] {
|
||||
background: #333;
|
||||
color:#eee;
|
||||
}
|
||||
|
||||
input[type=button] {
|
||||
padding:4px 14px 4px 14px;
|
||||
border:1px solid grey;
|
||||
border-radius:4px;
|
||||
background: #333;
|
||||
color:#eee;
|
||||
}
|
||||
|
||||
.headWord {
|
||||
display:inline-block;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.lftButn {
|
||||
padding:4px 14px 4px 14px;
|
||||
border:1px solid grey;
|
||||
border-radius:4px;
|
||||
background: #333;
|
||||
color:#eee;
|
||||
display:block;
|
||||
width:100%;
|
||||
margin:4px;
|
||||
}
|
||||
|
||||
/*********/
|
||||
|
||||
#page {
|
||||
z-index:20;
|
||||
position:fixed;
|
||||
top:32px;
|
||||
left:2px;
|
||||
right:2px;
|
||||
bottom:0;
|
||||
border:1px solid #000;
|
||||
border-radius:4px;
|
||||
background:#222;
|
||||
padding:6px;
|
||||
}
|
||||
|
||||
#pageBody {
|
||||
border:0px solid red;
|
||||
overflow:auto;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
#topRight {
|
||||
z-index:10;
|
||||
position:fixed;
|
||||
background:#000;
|
||||
top:-4px;
|
||||
left:76%;
|
||||
right:80px;
|
||||
bottom:0px;
|
||||
overflow:auto;
|
||||
border:1px solid #000;
|
||||
border-radius:4px;
|
||||
padding:8px;
|
||||
opacity:0.8;
|
||||
}
|
||||
|
||||
#topRight:hover {
|
||||
z-index:50;
|
||||
border:1px solid green;
|
||||
}
|
||||
|
||||
#topCent {
|
||||
z-index:10;
|
||||
position:fixed;
|
||||
background:#222;
|
||||
top:0;
|
||||
left:20%;
|
||||
right:20%;
|
||||
border:1px solid #222;
|
||||
padding:8px;
|
||||
}
|
||||
|
||||
#topCent:hover {
|
||||
z-index:50;
|
||||
}
|
||||
|
||||
#topLeft {
|
||||
z-index:10;
|
||||
position:fixed;
|
||||
background:#000;
|
||||
top:-6px;
|
||||
left:-2px;
|
||||
right:80%;
|
||||
border:1px solid #444;
|
||||
padding:8px;
|
||||
}
|
||||
|
||||
#topLeft:hover {
|
||||
z-index:50;
|
||||
border:1px solid green;
|
||||
}
|
||||
|
||||
/*******/
|
||||
|
||||
#diag {
|
||||
z-index:50;
|
||||
position:fixed;
|
||||
border:1px solid red;
|
||||
border-radius:8px;
|
||||
background-color:#222;
|
||||
top:20px;
|
||||
left:20px;
|
||||
min-width:640px;
|
||||
min-height:480px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
/*******/
|
||||
|
||||
#cmpKernelVanilaNodeRoot {
|
||||
border:1px solid grey;
|
||||
position:absolute;
|
||||
top:16px;
|
||||
right:4px;
|
||||
width:300px;
|
||||
height:90px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
#cmpKernelVanilaTitle {
|
||||
padding-left:32px;
|
||||
background-image: url(/go-prefix/static/img/tux-favicon.png);
|
||||
background-repeat:no-repeat;
|
||||
background-size:16px;
|
||||
background-position: 8px 2px;
|
||||
}
|
||||
|
||||
#cmpKernelVanilaHead {
|
||||
font-size:16px;
|
||||
border-bottom:1px solid grey;
|
||||
}
|
||||
|
||||
#cmpKernelVanilaHeadButton {
|
||||
border:0px solid grey;
|
||||
position:absolute;
|
||||
top:0;
|
||||
right:-24px;
|
||||
|
||||
padding:0px;
|
||||
padding-right:0px;
|
||||
margin:0;
|
||||
background-color:transparent;
|
||||
color:white;
|
||||
font-size:16px;
|
||||
}
|
||||
#cmpKernelVanilaNodeRoot:hover #cmpKernelVanilaHeadButton {
|
||||
right:8px;
|
||||
transform: rotate(-180deg);
|
||||
transition: right 1s, transform 1s;
|
||||
}
|
||||
|
||||
#cmpTinkoffCurrencyNodeRoot {
|
||||
border:1px solid grey;
|
||||
position:absolute;
|
||||
top:110px;
|
||||
right:4px;
|
||||
width:300px;
|
||||
height:90px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
#cmpTinkoffCurrencyTitle {
|
||||
padding-left:32px;
|
||||
background-image: url(/go-prefix/static/img/tkf-favicon-32x32.png);
|
||||
background-repeat:no-repeat;
|
||||
background-size:16px;
|
||||
background-position: 8px 2px;
|
||||
}
|
||||
|
||||
#cmpTinkoffCurrencyHead {
|
||||
font-size:16px;
|
||||
border-bottom:1px solid grey;
|
||||
}
|
||||
|
||||
#cmpTinkoffCurrencyHeadButton {
|
||||
border:0px solid grey;
|
||||
position:absolute;
|
||||
top:0;
|
||||
right:-24px;
|
||||
|
||||
padding:0px;
|
||||
padding-right:0px;
|
||||
margin:0;
|
||||
background-color:transparent;
|
||||
color:white;
|
||||
font-size:16px;
|
||||
}
|
||||
#cmpTinkoffCurrencyNodeRoot:hover #cmpTinkoffCurrencyHeadButton {
|
||||
right:8px;
|
||||
transform: rotate(-270deg);
|
||||
transition: right 1s, transform 1s;
|
||||
}
|
||||
|
||||
#cmpTinkoffCurrencyButton {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url(/go-prefix/static/img/tkf-logo-tinkoff.ru.png);
|
||||
background-repeat:no-repeat;
|
||||
background-size:32px;
|
||||
background-position: 8px 2px;
|
||||
}
|
299
static/default.js
Normal file
299
static/default.js
Normal file
@@ -0,0 +1,299 @@
|
||||
|
||||
// import { modTrm } from "/go-prefix/static/modTrm.js";
|
||||
// import { modYdl } from "/go-prefix/static/modYdl.js";
|
||||
// import { modNeverc } from "/go-prefix/static/modNeverc.js";
|
||||
|
||||
class cmpPage extends cmpSwoPage {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// Object.assign(this, modTrm);
|
||||
// Object.assign(this, modYdl);
|
||||
// Object.assign(this, modNeverc);
|
||||
|
||||
{
|
||||
this.tblheadroot = document.getElementById("tblheadroot");
|
||||
this.tblbodyroot = document.getElementById("tblbodyroot");
|
||||
|
||||
this.tblbody = document.getElementById("tblbody");
|
||||
}
|
||||
|
||||
// this.trmInitOnce();
|
||||
// this.ydlInitOnce();
|
||||
|
||||
this.cmpSwoOnConnect.push( this.timeReStyle.bind(this, "connect") );
|
||||
this.cmpSwoOnConnect.push( this.leftMenuReq.bind(this) );
|
||||
// this.cmpSwoOnConnect.push( this.trmConnect.bind(this) );
|
||||
// this.cmpSwoOnConnect.push( this.ydlConnect.bind(this) );
|
||||
this.cmpSwoOnDisconnect.push( this.timeReStyle.bind(this, "disconnect") );
|
||||
|
||||
this.cmpSwoPageInit();
|
||||
|
||||
this.offLineInit();
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
setHeadHeight(ii) {
|
||||
this.tblheadroot.style.bottom = ii + "px";
|
||||
this.tblbodyroot.style.top = (ii+1) + "px";
|
||||
}
|
||||
|
||||
setHead(node) {
|
||||
if(this.tblheadview)
|
||||
this.tblheadview.style.display = "none";
|
||||
|
||||
this.tblheadview = node;
|
||||
this.tblheadroot.appendChild(node);
|
||||
this.tblheadview.style.display = "";
|
||||
}
|
||||
|
||||
setBody(node) {
|
||||
if(this.tblbodyview)
|
||||
this.tblbodyview.style.display = "none";
|
||||
|
||||
this.tblbodyview = node;
|
||||
this.tblbodyroot.appendChild(node);
|
||||
this.tblbodyview.style.display = "";
|
||||
}
|
||||
|
||||
// Util
|
||||
|
||||
setNode(nn, obj, idx) {
|
||||
var n = document.getElementById(nn);
|
||||
|
||||
if(!n)
|
||||
return console.log("No node '" + nn + "'");
|
||||
|
||||
n.innerHTML = obj[idx];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Logic
|
||||
|
||||
contentReq(page, parm) {
|
||||
console.log("contentReq", page);
|
||||
|
||||
if(page == "trmShow") {
|
||||
this.trmShow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
rndTabHead(parn, hdr) {
|
||||
var hdrTb = document.getElementById("tblhtr");
|
||||
|
||||
if(!hdrTb)
|
||||
return;
|
||||
|
||||
hdrTb.innerHTML = "";
|
||||
|
||||
for(var n = parn?.firstChild?.firstChild, i = 0; n; n = n.nextSibling, i++) {
|
||||
var sta = "border-right:1px solid grey; border-bottom:1px solid grey; ";
|
||||
|
||||
if(hdr[i].child) {
|
||||
sta = "";
|
||||
}
|
||||
|
||||
var th = dcrt({
|
||||
tag : "th",
|
||||
parn : hdrTb,
|
||||
style: sta + "width:" + (n.offsetWidth) + "px;",
|
||||
child: hdr[i].child ? hdr[i].child : null
|
||||
});
|
||||
|
||||
if(hdr[i].html) {
|
||||
th.innerHTML = hdr[i].html;
|
||||
}
|
||||
}
|
||||
|
||||
var n = document.getElementById("tblbodyroot");
|
||||
|
||||
if(n) {
|
||||
n.style.top = (hdrTb.offsetHeight + 6) + "px";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
|
||||
getSpeeddialElemReq() {
|
||||
return this.reqSnip("getSpeeddialElem", null);
|
||||
}
|
||||
|
||||
getSpeeddialElemRcv(obj) {
|
||||
var i = 0;
|
||||
|
||||
for(i = 0; i < obj.length; i++) {
|
||||
this.rndSpeeddialElem(obj[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
offLineInit() {
|
||||
if(1)
|
||||
return;
|
||||
|
||||
this.spdNodeLeftMenu = dcrt({
|
||||
tag : "div",
|
||||
parn : "mainRoot",
|
||||
style: "width:320px; position:relative; height:calc(100% - 10px); top:5px; left:5px; border:1px solid grey;"
|
||||
});
|
||||
|
||||
this.spdNodeLeftMenuScrTop = dcrt({
|
||||
tag : "div",
|
||||
parn : this.spdNodeLeftMenu,
|
||||
style: "width:100%; margin:0px; height:40px; border-bottom:1px solid grey;"
|
||||
});
|
||||
|
||||
this.spdNodeLeftMenuBody = dcrt({
|
||||
tag : "div",
|
||||
parn : this.spdNodeLeftMenu,
|
||||
style: "width:100%; margin:0px; height:calc(100% - 80px); overflow-x:hidden; scroll-x:auto;"
|
||||
})
|
||||
|
||||
this.spdNodeLeftMenuScrBottom = dcrt({
|
||||
tag : "div",
|
||||
parn : this.spdNodeLeftMenu,
|
||||
style: "width:100%; margin:0px; height:40px; border-top:1px solid grey;"
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rndSpeeddialElem(obj) {
|
||||
if(obj.type != "local")
|
||||
return;
|
||||
|
||||
var lab = dcrt({
|
||||
tag : "div",
|
||||
style: "padding:16px;",
|
||||
html : obj.label ? obj.label : obj.ip4v
|
||||
});
|
||||
|
||||
var com = dcrt({
|
||||
tag : "div",
|
||||
style: "color:#888; padding-left:32px; margin-right:32px;",
|
||||
html : (obj.label ? obj.ip4v : "") + (obj.xport ? (" / " + obj.xport) : "")
|
||||
});
|
||||
|
||||
var zzz = null;
|
||||
|
||||
if(obj.xport == "A0") {
|
||||
zzz = this.rndECtl();
|
||||
}
|
||||
|
||||
dcrt({
|
||||
tag : "div",
|
||||
parn : this.spdNodeLeftMenuBody,
|
||||
style: "position:relative; width:calc(100%-10px); margin:5px; height:100px; border:1px solid grey;",
|
||||
child: [
|
||||
lab,
|
||||
com,
|
||||
zzz
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
rndECtl() {
|
||||
if(!this.listECtl)
|
||||
this.listECtl = [];
|
||||
|
||||
var id = this.listECtl.legth;
|
||||
|
||||
this.listECtl[id] = {};
|
||||
|
||||
this.listECtl[id].nodePoint = dcrt({
|
||||
tag : "div",
|
||||
style: "position:absolute; top:2px; width:0px; height:0px; border-radius:17px; border:16px solid;"
|
||||
});
|
||||
|
||||
this.listECtl[id].nodePoint.style.left = "2px";
|
||||
this.listECtl[id].nodePoint.style.borderColor = "#a33";
|
||||
|
||||
this.listECtl[id].nodeLabel = dcrt({
|
||||
tag : "div"
|
||||
});
|
||||
|
||||
this.listECtl[id].nodeRoot = dcrt({
|
||||
tag : "div",
|
||||
style: "position:absolute; top:32px; right:32px; width:84px; height:36px; border:1px solid grey; border-radius:18px;",
|
||||
click: this.clickECtl.bind(this, id),
|
||||
child: [
|
||||
this.listECtl[id].nodePoint,
|
||||
this.listECtl[id].nodeLabel
|
||||
]
|
||||
});
|
||||
|
||||
return this.listECtl[id].nodeRoot;
|
||||
}
|
||||
|
||||
clickECtl(id) {
|
||||
var style = this.listECtl[id].nodePoint.style;
|
||||
|
||||
if(style.left) {
|
||||
style.left = "";
|
||||
style.right = "2px";
|
||||
style.borderColor = "#3a3";
|
||||
}
|
||||
else {
|
||||
style.left = "2px";
|
||||
style.right = "";
|
||||
style.borderColor = "#a33";
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//==========================
|
||||
|
||||
urlMod(parm) {
|
||||
if(!parm?.urlMod.url)
|
||||
return console.log("No .url");
|
||||
|
||||
if(!parm?.urlMod.title)
|
||||
return console.log("No .title");
|
||||
|
||||
// const nextState = parm?.urlMod.nextState; // { additionalInformation: 'Updated the URL with JS' };
|
||||
|
||||
// This will create a new entry in the browser's history, without reloading
|
||||
window.history.pushState(parm?.urlMod.nextState, parm?.urlMod.title, parm.urlMod.url);
|
||||
|
||||
// This will replace the current entry in the browser's history, without reloading
|
||||
window.history.replaceState(parm?.urlMod.nextState, parm?.urlMod.title, parm.urlMod.url);
|
||||
|
||||
// console.log(window.location)
|
||||
}
|
||||
|
||||
// END class
|
||||
}
|
||||
|
||||
|
||||
window.diag = null;
|
||||
function diagMove(e) {
|
||||
window.diag.diagMove(e);
|
||||
}
|
||||
function diagMouseUp(e) {
|
||||
window.diag.diagRoot.style.zIndex = 50;
|
||||
window.removeEventListener('mousemove', diagMove, false);
|
||||
}
|
||||
|
||||
var page = null;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
page = new cmpPage();
|
||||
window.page = page;
|
||||
});
|
||||
|
||||
// END
|
BIN
static/img/favicon.png
Normal file
BIN
static/img/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
BIN
static/img/tkf-favicon-32x32.png
Normal file
BIN
static/img/tkf-favicon-32x32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 B |
BIN
static/img/tux-favicon.png
Normal file
BIN
static/img/tux-favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
BIN
static/img/umbrella-black.png
Normal file
BIN
static/img/umbrella-black.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
BIN
static/img/umbrella-color.png
Normal file
BIN
static/img/umbrella-color.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
61
static/index.html
Normal file
61
static/index.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="cache-control" content="no-cache"/>
|
||||
<meta http-equiv="Pragma" content="no-cache"/>
|
||||
|
||||
<link href="data:image/svg+xml,%3Csvg%0Axmlns:dc='http://purl.org/dc/elements/1.1/'%0Axmlns:cc='http://creativecommons.org/ns%23'%0Axmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23'%0Axmlns:svg='http://www.w3.org/2000/svg'%0Axmlns='http://www.w3.org/2000/svg'%0Axmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'%0Axmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'%0Aversion='1.1'%0Aid='Layer_3'%0Ax='0px'%0Ay='0px'%0AviewBox='0 0 800 800'%0Axml:space='preserve'%0Asodipodi:docname='Cult Mechanicus %5BImperium, Adeptus Mechanicus%5D.svg'%0Awidth='800'%0Aheight='800'%0Ainkscape:version='0.92.3 (2405546, 2018-03-11)'%3E%3Cmetadata%0Aid='metadata13'%3E%3Crdf:RDF%3E%3Ccc:Work%0Ardf:about=''%3E%3Cdc:format%3Eimage/svg+xml%3C/dc:format%3E%3Cdc:type%0Ardf:resource='http://purl.org/dc/dcmitype/StillImage' /%3E%3Cdc:title%3E%3C/dc:title%3E%3C/cc:Work%3E%3C/rdf:RDF%3E%3C/metadata%3E%3Cdefs%0Aid='defs11' /%3E%3Csodipodi:namedview%0Apagecolor='%23ffffff'%0Abordercolor='%23666666'%0Aborderopacity='1'%0Aobjecttolerance='10'%0Agridtolerance='10'%0Aguidetolerance='10'%0Ainkscape:pageopacity='0'%0Ainkscape:pageshadow='2'%0Ainkscape:window-width='1920'%0Ainkscape:window-height='1017'%0Aid='namedview9'%0Ashowgrid='false'%0Afit-margin-top='0'%0Afit-margin-left='0'%0Afit-margin-right='0'%0Afit-margin-bottom='0'%0Ainkscape:pagecheckerboard='true'%0Ainkscape:zoom='0.3337544'%0Ainkscape:cx='69.895884'%0Ainkscape:cy='339.47885'%0Ainkscape:window-x='-8'%0Ainkscape:window-y='-8'%0Ainkscape:window-maximized='1'%0Ainkscape:current-layer='Layer_3' /%3E%3Cg%0Aid='g6'%0Atransform='matrix(0.81670155,0,0,0.81670155,-8.6162014,-11.801337)'%3E%3Cpath%0Ad='m 552.21,318.59 c 0,-2.16 0,-3.32 0,-3.32 0,-5.42 0.76,-17.36 8.74,-28.55 16.26,-22.78 46.62,-20.57 48.37,-20.39 0,-6.82 0,-13.58 0,-20.39 H 391.33 c 0,6.82 0,13.58 0,20.39 1.75,-0.17 32.11,-2.39 48.37,20.39 7.98,11.19 8.74,23.13 8.74,28.55 0,0 0,1.11 0,3.18 -104.69,18.52 -182.92,92.33 -182.92,180.56 0,88.25 78.25,162.06 182.95,180.57 -0.01,2.48 -0.03,4.61 -0.04,6.33 0.23,3.85 0.87,19.75 -10.49,33.21 -10.96,12.99 -28.9,18.76 -46.62,15.15 v 23.31 h 217.99 v -23.31 c -17.71,3.61 -35.66,-2.16 -46.62,-15.15 -11.36,-13.46 -10.72,-29.37 -10.49,-33.21 -0.02,-1.76 -0.03,-3.93 -0.04,-6.47 C 656.46,660.69 734.31,587.03 734.31,499.01734.33,411 656.5,337.34 552.21,318.59 Z M 358.05,503.95 c 0,-67.54 37.51,-125.24 90.43,-148.35 0.08,72.75 0.21,225.02 0.08,296.74 -52.96,-23.09 -90.51,-80.82 -90.51,-148.39 z m 194.04,148.04 c -0.13,-71.75 0,-223.28 0.08,-296.05 52.5,23.34 89.63,80.81 89.63,148 0,67.24 -37.17,124.73 -89.71,148.05 z'%0Aid='path2'%0Ainkscape:connector-curvature='0' /%3E%3Cpath%0Ad='M 990.1,560.87 V 448.76 h -72.53 c -4.3,-36.57 -13.29,-71.71 -26.37,-104.79 l 61.6,-35.57 -56.06,-97.1 -60.35,34.84 c -22,-29.27 -47.74,-55.58 -76.5,-78.21 l 34.38,-59.54 -97.1,-56.06 -33.85,58.64 C 629.86,96.87 594.19,86.99 556.97,81.97 V 14.45 H 444.86 v 67.37 c -37.23,4.91 -72.93,14.7 -106.43,28.7 l -33.93,-58.78 -97.1,56.06 34.29,59.4 c -28.83,22.55 -54.64,48.79 -76.72,78 l -60.48,-34.92 -56.06,97.1 61.46,35.48C 96.72,375.91 87.62,411.02 83.22,447.58 H 10.55 V 559.7 h 74.09 c 5.25,35.85 15.01,70.23 28.72,102.54 l -65.51,37.82 56.06,97.1 66.65,-38.48 c 21.8,27.57 46.97,52.35 74.91,73.69 l -39.08,67.7 97.1,56.06 39.36,-68.17 c 31.86,12.89 65.66,21.99 100.84,26.73 V 994 h 112.12 v -79.17 c 35.2,-4.64 69.02,-13.64 100.92,-26.44 l 39.44,68.32 97.1,-56.06 -39.01,-67.57 c 28,-21.27 53.25,-45.97 75.12,-73.48 l 66.8,38.57 56.06,-97.1 -65.39,-37.75 c 13.79,-32.27 23.67,-66.62 29.01,-102.45 H 990.1 Z M 500.33,818.15 C 326.95,818.15 186.4,677.6 186.4,504.22 186.4,330.84 326.95,190.3 500.33,190.3 c 173.38,0 313.93,140.55 313.93,313.93 0,173.38 -140.56,313.92 -313.93,313.92 z'%0Aid='path4'%0Ainkscape:connector-curvature='0' /%3E%3C/g%3E%3C/svg%3E%0A"
|
||||
rel="icon" type="image/svg+xml"/>
|
||||
|
||||
<script src="/go-prefix/static/cmpSwoPage.js"></script>
|
||||
<script src="/go-prefix/static/cmpSwoUtil.js"></script>
|
||||
<link href="/go-prefix/static/cmpSwoPage.css" rel="stylesheet" type="text/css"/>
|
||||
|
||||
<link href="/go-prefix/static/default.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="/go-prefix/static/default.js" type="module"></script>
|
||||
|
||||
<!-- link href="/go-prefix/static/img/tux-favicon.png" rel="preload" as="image"/ -->
|
||||
<!-- link href="/go-prefix/static/img/tkf-favicon-32x32.png" rel="preload" as="image"/ -->
|
||||
</head>
|
||||
<body id="body"><div style="position:absolute; top:0; left:0; right:0; bottom:0; border:0px solid black;">
|
||||
<div id="topper" style="position:absolute; top:0; left:0; right:0; height:32px; border:0px solid grey; overflow:hidden;">
|
||||
<table id="topperTab" cellpadding="0" cellspacing="0"><tr>
|
||||
<td id="topperTabLeft">
|
||||
|
||||
</td><td id="topperTabCenter">
|
||||
<span> </span>
|
||||
<span id="cmpSwoTaskList"></span>
|
||||
</td><td id="topperTabRight">
|
||||
<div id="user" class="headWord">USER</div>
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<div id="leftMenu">
|
||||
</div>
|
||||
<div id="mainRoot">
|
||||
<!-- div id="mid" style="position:absolute; top:32px; left:150px; right:0; bottom:32px; border:1px solid grey;" -->
|
||||
<div id="tblheadroot" style="position:absolute; top:0px; bottom:31px; left:0; right:12px;"></div>
|
||||
<div id="tblbodyroot" style="position:absolute; top:32px; left:0; right:0; bottom:0; overflow:auto;"></div>
|
||||
</div>
|
||||
<div id="footer" style="position:absolute; left:0; right:0; bottom:0; height:32px; border:0px solid grey;">
|
||||
<table cellpadding="0" cellspacing="0" style="vertical-align:top;"><tr>
|
||||
<td style="width:33%; vertical-align:top;">
|
||||
<div id="gitTitl" class="headWord">GIT</div>
|
||||
<div id="gitDate" class="headWord">2022-99-99</div>
|
||||
<div id="gitTime" class="headWord">99:99:99</div>
|
||||
<div id="gitCHID" class="headWord">00000000</div>
|
||||
<div id="gitComm" class="headWord">Just string</div>
|
||||
</td><td style="width:33%; vertical-align:top; text-align:center;">
|
||||
<div id="srvDate" class="headWord">2022-00-00</div>
|
||||
<div id="srvTime" class="headWord">00:00:00</div>
|
||||
<div id="srvRand" class="headWord"></div>
|
||||
</td><td style="width:33%; vertical-align:top; text-align:right;">
|
||||
<div id="oraLabs" class="headWord">Qwerty</div>
|
||||
<div id="oraRole" class="headWord">NONE</div>
|
||||
<div id="oraAddr" class="headWord">xxx.xxx.xx.xx</div>
|
||||
<div id="oraUser" class="headWord">USER</div>
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
</div></body>
|
61
static/index2.html
Normal file
61
static/index2.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="cache-control" content="no-cache"/>
|
||||
<meta http-equiv="Pragma" content="no-cache"/>
|
||||
|
||||
<link href="data:image/svg+xml,%3Csvg%0Axmlns:dc='http://purl.org/dc/elements/1.1/'%0Axmlns:cc='http://creativecommons.org/ns%23'%0Axmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23'%0Axmlns:svg='http://www.w3.org/2000/svg'%0Axmlns='http://www.w3.org/2000/svg'%0Axmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'%0Axmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'%0Aversion='1.1'%0Aid='Layer_3'%0Ax='0px'%0Ay='0px'%0AviewBox='0 0 800 800'%0Axml:space='preserve'%0Asodipodi:docname='Cult Mechanicus %5BImperium, Adeptus Mechanicus%5D.svg'%0Awidth='800'%0Aheight='800'%0Ainkscape:version='0.92.3 (2405546, 2018-03-11)'%3E%3Cmetadata%0Aid='metadata13'%3E%3Crdf:RDF%3E%3Ccc:Work%0Ardf:about=''%3E%3Cdc:format%3Eimage/svg+xml%3C/dc:format%3E%3Cdc:type%0Ardf:resource='http://purl.org/dc/dcmitype/StillImage' /%3E%3Cdc:title%3E%3C/dc:title%3E%3C/cc:Work%3E%3C/rdf:RDF%3E%3C/metadata%3E%3Cdefs%0Aid='defs11' /%3E%3Csodipodi:namedview%0Apagecolor='%23ffffff'%0Abordercolor='%23666666'%0Aborderopacity='1'%0Aobjecttolerance='10'%0Agridtolerance='10'%0Aguidetolerance='10'%0Ainkscape:pageopacity='0'%0Ainkscape:pageshadow='2'%0Ainkscape:window-width='1920'%0Ainkscape:window-height='1017'%0Aid='namedview9'%0Ashowgrid='false'%0Afit-margin-top='0'%0Afit-margin-left='0'%0Afit-margin-right='0'%0Afit-margin-bottom='0'%0Ainkscape:pagecheckerboard='true'%0Ainkscape:zoom='0.3337544'%0Ainkscape:cx='69.895884'%0Ainkscape:cy='339.47885'%0Ainkscape:window-x='-8'%0Ainkscape:window-y='-8'%0Ainkscape:window-maximized='1'%0Ainkscape:current-layer='Layer_3' /%3E%3Cg%0Aid='g6'%0Atransform='matrix(0.81670155,0,0,0.81670155,-8.6162014,-11.801337)'%3E%3Cpath%0Ad='m 552.21,318.59 c 0,-2.16 0,-3.32 0,-3.32 0,-5.42 0.76,-17.36 8.74,-28.55 16.26,-22.78 46.62,-20.57 48.37,-20.39 0,-6.82 0,-13.58 0,-20.39 H 391.33 c 0,6.82 0,13.58 0,20.39 1.75,-0.17 32.11,-2.39 48.37,20.39 7.98,11.19 8.74,23.13 8.74,28.55 0,0 0,1.11 0,3.18 -104.69,18.52 -182.92,92.33 -182.92,180.56 0,88.25 78.25,162.06 182.95,180.57 -0.01,2.48 -0.03,4.61 -0.04,6.33 0.23,3.85 0.87,19.75 -10.49,33.21 -10.96,12.99 -28.9,18.76 -46.62,15.15 v 23.31 h 217.99 v -23.31 c -17.71,3.61 -35.66,-2.16 -46.62,-15.15 -11.36,-13.46 -10.72,-29.37 -10.49,-33.21 -0.02,-1.76 -0.03,-3.93 -0.04,-6.47 C 656.46,660.69 734.31,587.03 734.31,499.01734.33,411 656.5,337.34 552.21,318.59 Z M 358.05,503.95 c 0,-67.54 37.51,-125.24 90.43,-148.35 0.08,72.75 0.21,225.02 0.08,296.74 -52.96,-23.09 -90.51,-80.82 -90.51,-148.39 z m 194.04,148.04 c -0.13,-71.75 0,-223.28 0.08,-296.05 52.5,23.34 89.63,80.81 89.63,148 0,67.24 -37.17,124.73 -89.71,148.05 z'%0Aid='path2'%0Ainkscape:connector-curvature='0' /%3E%3Cpath%0Ad='M 990.1,560.87 V 448.76 h -72.53 c -4.3,-36.57 -13.29,-71.71 -26.37,-104.79 l 61.6,-35.57 -56.06,-97.1 -60.35,34.84 c -22,-29.27 -47.74,-55.58 -76.5,-78.21 l 34.38,-59.54 -97.1,-56.06 -33.85,58.64 C 629.86,96.87 594.19,86.99 556.97,81.97 V 14.45 H 444.86 v 67.37 c -37.23,4.91 -72.93,14.7 -106.43,28.7 l -33.93,-58.78 -97.1,56.06 34.29,59.4 c -28.83,22.55 -54.64,48.79 -76.72,78 l -60.48,-34.92 -56.06,97.1 61.46,35.48C 96.72,375.91 87.62,411.02 83.22,447.58 H 10.55 V 559.7 h 74.09 c 5.25,35.85 15.01,70.23 28.72,102.54 l -65.51,37.82 56.06,97.1 66.65,-38.48 c 21.8,27.57 46.97,52.35 74.91,73.69 l -39.08,67.7 97.1,56.06 39.36,-68.17 c 31.86,12.89 65.66,21.99 100.84,26.73 V 994 h 112.12 v -79.17 c 35.2,-4.64 69.02,-13.64 100.92,-26.44 l 39.44,68.32 97.1,-56.06 -39.01,-67.57 c 28,-21.27 53.25,-45.97 75.12,-73.48 l 66.8,38.57 56.06,-97.1 -65.39,-37.75 c 13.79,-32.27 23.67,-66.62 29.01,-102.45 H 990.1 Z M 500.33,818.15 C 326.95,818.15 186.4,677.6 186.4,504.22 186.4,330.84 326.95,190.3 500.33,190.3 c 173.38,0 313.93,140.55 313.93,313.93 0,173.38 -140.56,313.92 -313.93,313.92 z'%0Aid='path4'%0Ainkscape:connector-curvature='0' /%3E%3C/g%3E%3C/svg%3E%0A"
|
||||
rel="icon" type="image/svg+xml"/>
|
||||
|
||||
<script src="/go-prefix/static/cmpSwoPage.js"></script>
|
||||
<script src="/go-prefix/static/cmpSwoUtil.js"></script>
|
||||
<link href="/go-prefix/static/cmpSwoPage.css" rel="stylesheet" type="text/css"/>
|
||||
|
||||
<link href="/go-prefix/static/default.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="/go-prefix/static/default.js" type="module"></script>
|
||||
|
||||
<!-- link href="/go-prefix/static/img/tux-favicon.png" rel="preload" as="image"/ -->
|
||||
<!-- link href="/go-prefix/static/img/tkf-favicon-32x32.png" rel="preload" as="image"/ -->
|
||||
</head>
|
||||
<body id="body"><div style="position:absolute; top:0; left:0; right:0; bottom:0; border:0px solid black;">
|
||||
<div id="topper" style="position:absolute; top:0; left:0; right:0; height:32px; border:0px solid grey; overflow:hidden;">
|
||||
<table id="topperTab" cellpadding="0" cellspacing="0"><tr>
|
||||
<td id="topperTabLeft">
|
||||
|
||||
</td><td id="topperTabCenter">
|
||||
<span> </span>
|
||||
<span id="cmpSwoTaskList"></span>
|
||||
</td><td id="topperTabRight">
|
||||
<div id="user" class="headWord">USER</div>
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<div id="leftMenu">
|
||||
</div>
|
||||
<div id="mainRoot">
|
||||
<!-- div id="mid" style="position:absolute; top:32px; left:150px; right:0; bottom:32px; border:1px solid grey;" -->
|
||||
<div id="tblheadroot" style="position:absolute; top:0px; bottom:31px; left:0; right:12px;"></div>
|
||||
<div id="tblbodyroot" style="position:absolute; top:32px; left:0; right:0; bottom:0; overflow:auto;"></div>
|
||||
</div>
|
||||
<div id="footer" style="position:absolute; left:0; right:0; bottom:0; height:32px; border:0px solid grey;">
|
||||
<table cellpadding="0" cellspacing="0" style="vertical-align:top;"><tr>
|
||||
<td style="width:33%; vertical-align:top;">
|
||||
<div id="gitTitl" class="headWord">GIT</div>
|
||||
<div id="gitDate" class="headWord">2022-99-99</div>
|
||||
<div id="gitTime" class="headWord">99:99:99</div>
|
||||
<div id="gitCHID" class="headWord">00000000</div>
|
||||
<div id="gitComm" class="headWord">Just string</div>
|
||||
</td><td style="width:33%; vertical-align:top; text-align:center;">
|
||||
<div id="srvDate" class="headWord">2022-00-00</div>
|
||||
<div id="srvTime" class="headWord">00:00:00</div>
|
||||
<div id="srvRand" class="headWord"></div>
|
||||
</td><td style="width:33%; vertical-align:top; text-align:right;">
|
||||
<div id="oraLabs" class="headWord">Qwerty</div>
|
||||
<div id="oraRole" class="headWord">NONE</div>
|
||||
<div id="oraAddr" class="headWord">xxx.xxx.xx.xx</div>
|
||||
<div id="oraUser" class="headWord">USER</div>
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
</div></body>
|
Reference in New Issue
Block a user