From e4bf4b4ef8fb435c70719209797e543010f9d66a Mon Sep 17 00:00:00 2001 From: sawka Date: Thu, 7 Jul 2022 13:26:46 -0700 Subject: [PATCH] checkpoint, pass remote vars to client for prompt str, get commands showing --- db/migrations/000001_init.up.sql | 10 +--- pkg/remote/remote.go | 11 ++++ pkg/sstore/dbops.go | 85 +++++++++++++--------------- pkg/sstore/quick.go | 68 +++++++++++++++++++++++ pkg/sstore/sstore.go | 95 ++++++++++++++++++-------------- pkg/sstore/txwrap.go | 17 ++++++ 6 files changed, 189 insertions(+), 97 deletions(-) create mode 100644 pkg/sstore/quick.go diff --git a/db/migrations/000001_init.up.sql b/db/migrations/000001_init.up.sql index 6d54ab367..8796f3028 100644 --- a/db/migrations/000001_init.up.sql +++ b/db/migrations/000001_init.up.sql @@ -41,14 +41,8 @@ CREATE TABLE remote ( remotetype varchar(10) NOT NULL, remotename varchar(50) NOT NULL, autoconnect boolean NOT NULL, - - -- ssh specific opts - sshhost varchar(300) NOT NULL, - sshopts varchar(300) NOT NULL, - sshidentity varchar(300) NOT NULL, - sshuser varchar(100) NOT NULL, - - -- runtime data + initpk json NOT NULL, + sshopts json NOT NULL, lastconnectts bigint NOT NULL ); diff --git a/pkg/remote/remote.go b/pkg/remote/remote.go index d47fc0e2e..b954b01f9 100644 --- a/pkg/remote/remote.go +++ b/pkg/remote/remote.go @@ -40,6 +40,7 @@ type RemoteState struct { RemoteType string `json:"remotetype"` RemoteId string `json:"remoteid"` RemoteName string `json:"remotename"` + RemoteVars map[string]string `json:"remotevars"` Status string `json:"status"` DefaultState *sstore.RemoteState `json:"defaultstate"` } @@ -102,9 +103,18 @@ func GetAllRemoteState() []RemoteState { RemoteName: proc.Remote.RemoteName, Status: proc.Status, } + vars := make(map[string]string) + vars["user"], vars["host"] = proc.Remote.GetUserHost() if proc.ServerProc != nil && proc.ServerProc.InitPk != nil { state.DefaultState = &sstore.RemoteState{Cwd: proc.ServerProc.InitPk.HomeDir} + vars["home"] = proc.ServerProc.InitPk.HomeDir + vars["remoteuser"] = proc.ServerProc.InitPk.User + vars["remotehost"] = proc.ServerProc.InitPk.HostName + if proc.Remote.SSHOpts == nil || proc.Remote.SSHOpts.SSHHost == "" { + vars["local"] = "1" + } } + state.RemoteVars = vars rtn = append(rtn, state) } return rtn @@ -199,6 +209,7 @@ func RunCommand(ctx context.Context, pk *scpacket.FeCommandPacketType, cmdId str cmd := &sstore.CmdType{ SessionId: pk.SessionId, CmdId: startPk.CK.GetCmdId(), + CmdStr: runPacket.Command, RemoteId: msh.Remote.RemoteId, RemoteState: convertRemoteState(pk.RemoteState), TermOpts: makeTermOpts(), diff --git a/pkg/sstore/dbops.go b/pkg/sstore/dbops.go index d6b07262b..108cf39d1 100644 --- a/pkg/sstore/dbops.go +++ b/pkg/sstore/dbops.go @@ -22,54 +22,48 @@ func NumSessions(ctx context.Context) (int, error) { return count, nil } -const remoteSelectCols = "remoteid, remotetype, remotename, autoconnect, sshhost, sshopts, sshidentity, sshuser, lastconnectts" - func GetAllRemotes(ctx context.Context) ([]*RemoteType, error) { - db, err := GetDB() + var rtn []*RemoteType + err := WithTx(ctx, func(tx *TxWrap) error { + query := `SELECT * FROM remote` + marr := tx.SelectMaps(query) + for _, m := range marr { + rtn = append(rtn, RemoteFromMap(m)) + } + return nil + }) if err != nil { return nil, err } - query := fmt.Sprintf(`SELECT %s FROM remote`, remoteSelectCols) - var remoteArr []*RemoteType - err = db.SelectContext(ctx, &remoteArr, query) - if err != nil { - return nil, err - } - return remoteArr, nil + return rtn, nil } func GetRemoteByName(ctx context.Context, remoteName string) (*RemoteType, error) { - db, err := GetDB() + var remote *RemoteType + err := WithTx(ctx, func(tx *TxWrap) error { + query := `SELECT * FROM remote WHERE remotename = ?` + m := tx.GetMap(query, remoteName) + remote = RemoteFromMap(m) + return nil + }) if err != nil { return nil, err } - query := fmt.Sprintf(`SELECT %s FROM remote WHERE remotename = ?`, remoteSelectCols) - var remote RemoteType - err = db.GetContext(ctx, &remote, query, remoteName) - if err == sql.ErrNoRows { - return nil, nil - } - if err != nil { - return nil, err - } - return &remote, nil + return remote, nil } func GetRemoteById(ctx context.Context, remoteId string) (*RemoteType, error) { - db, err := GetDB() + var remote *RemoteType + err := WithTx(ctx, func(tx *TxWrap) error { + query := `SELECT * FROM remote WHERE remoteid = ?` + m := tx.GetMap(query, remoteId) + remote = RemoteFromMap(m) + return nil + }) if err != nil { return nil, err } - query := fmt.Sprintf(`SELECT %s FROM remote WHERE remoteid = ?`, remoteSelectCols) - var remote RemoteType - err = db.GetContext(ctx, &remote, query, remoteId) - if err == sql.ErrNoRows { - return nil, nil - } - if err != nil { - return nil, err - } - return &remote, nil + return remote, nil } func InsertRemote(ctx context.Context, remote *RemoteType) error { @@ -80,9 +74,9 @@ func InsertRemote(ctx context.Context, remote *RemoteType) error { if err != nil { return err } - query := `INSERT INTO remote ( remoteid, remotetype, remotename, autoconnect, sshhost, sshopts, sshidentity, sshuser, lastconnectts) VALUES - (:remoteid,:remotetype,:remotename,:autoconnect,:sshhost,:sshopts,:sshidentity,:sshuser, 0 )` - _, err = db.NamedExec(query, remote) + query := `INSERT INTO remote ( remoteid, remotetype, remotename, autoconnect, initpk, sshopts, lastconnectts) VALUES + (:remoteid,:remotetype,:remotename,:autoconnect,:initpk,:sshopts,:lastconnectts)` + _, err = db.NamedExec(query, remote.ToMap()) if err != nil { return err } @@ -218,19 +212,16 @@ INSERT INTO cmd ( sessionid, cmdid, remoteid, cmdstr, remotestate, termopts, st }) } -func GetCmd(ctx context.Context, sessionId string, cmdId string) (*CmdType, error) { - db, err := GetDB() +func GetCmdById(ctx context.Context, sessionId string, cmdId string) (*CmdType, error) { + var cmd *CmdType + err := WithTx(ctx, func(tx *TxWrap) error { + query := `SELECT * FROM cmd WHERE sessionid = ? AND cmdid = ?` + m := tx.GetMap(query, sessionId, cmdId) + cmd = CmdFromMap(m) + return nil + }) if err != nil { return nil, err } - var m map[string]interface{} - query := `SELECT * FROM cmd WHERE sessionid = ? AND cmdid = ?` - err = db.GetContext(ctx, &m, query, sessionId, cmdId) - if err != nil { - if err == sql.ErrNoRows { - return nil, nil - } - return nil, err - } - return CmdFromMap(m), nil + return cmd, nil } diff --git a/pkg/sstore/quick.go b/pkg/sstore/quick.go new file mode 100644 index 000000000..a4b8aaef1 --- /dev/null +++ b/pkg/sstore/quick.go @@ -0,0 +1,68 @@ +package sstore + +import "encoding/json" + +func quickSetStr(strVal *string, m map[string]interface{}, name string) { + v, ok := m[name] + if !ok { + return + } + str, ok := v.(string) + if !ok { + return + } + *strVal = str +} + +func quickSetInt64(ival *int64, m map[string]interface{}, name string) { + v, ok := m[name] + if !ok { + return + } + sqlInt, ok := v.(int64) + if !ok { + return + } + *ival = sqlInt +} + +func quickSetBool(bval *bool, m map[string]interface{}, name string) { + v, ok := m[name] + if !ok { + return + } + sqlInt, ok := v.(int64) + if ok { + if sqlInt > 0 { + *bval = true + } + return + } + sqlBool, ok := v.(bool) + if ok { + *bval = sqlBool + } +} + +func quickSetJson(ptr interface{}, m map[string]interface{}, name string) { + v, ok := m[name] + if !ok { + return + } + str, ok := v.(string) + if !ok { + return + } + if str == "" { + return + } + json.Unmarshal([]byte(str), ptr) +} + +func quickJson(v interface{}) string { + if v == nil { + return "" + } + barr, _ := json.Marshal(v) + return string(barr) +} diff --git a/pkg/sstore/sstore.go b/pkg/sstore/sstore.go index 63f632524..bca56f4f5 100644 --- a/pkg/sstore/sstore.go +++ b/pkg/sstore/sstore.go @@ -7,6 +7,7 @@ import ( "fmt" "log" "path" + "strings" "sync" "time" @@ -134,20 +135,35 @@ type LineType struct { CmdId string `json:"cmdid,omitempty"` } -type RemoteType struct { - RemoteId string `json:"remoteid"` - RemoteType string `json:"remotetype"` - RemoteName string `json:"remotename"` - AutoConnect bool `json:"autoconnect"` - - // type=ssh options +type SSHOpts struct { SSHHost string `json:"sshhost"` - SSHOpts string `json:"sshopts"` + SSHOptsStr string `json:"sshopts"` SSHIdentity string `json:"sshidentity"` SSHUser string `json:"sshuser"` +} - // runtime data - LastConnectTs int64 `json:"lastconnectts"` +type RemoteType struct { + RemoteId string `json:"remoteid"` + RemoteType string `json:"remotetype"` + RemoteName string `json:"remotename"` + AutoConnect bool `json:"autoconnect"` + InitPk *packet.InitPacketType `json:"inipk"` + SSHOpts *SSHOpts `json:"sshopts"` + LastConnectTs int64 `json:"lastconnectts"` +} + +func (r *RemoteType) GetUserHost() (string, string) { + if r.SSHOpts == nil { + return "", "" + } + if r.SSHOpts.SSHUser != "" { + return r.SSHOpts.SSHUser, r.SSHOpts.SSHHost + } + atIdx := strings.Index(r.SSHOpts.SSHHost, "@") + if atIdx == -1 { + return "", r.SSHOpts.SSHHost + } + return r.SSHOpts.SSHHost[0:atIdx], r.SSHOpts.SSHHost[atIdx+1:] } type CmdType struct { @@ -163,12 +179,31 @@ type CmdType struct { RunOut []packet.PacketType `json:"runout"` } -func quickJson(v interface{}) string { - if v == nil { - return "" +func (r *RemoteType) ToMap() map[string]interface{} { + rtn := make(map[string]interface{}) + rtn["remoteid"] = r.RemoteId + rtn["remotetype"] = r.RemoteType + rtn["remotename"] = r.RemoteName + rtn["autoconnect"] = r.AutoConnect + rtn["initpk"] = quickJson(r.InitPk) + rtn["sshopts"] = quickJson(r.SSHOpts) + rtn["lastconnectts"] = r.LastConnectTs + return rtn +} + +func RemoteFromMap(m map[string]interface{}) *RemoteType { + if len(m) == 0 { + return nil } - barr, _ := json.Marshal(v) - return string(barr) + var r RemoteType + quickSetStr(&r.RemoteId, m, "remoteid") + quickSetStr(&r.RemoteType, m, "remotetype") + quickSetStr(&r.RemoteName, m, "remotename") + quickSetBool(&r.AutoConnect, m, "autoconnect") + quickSetJson(&r.InitPk, m, "initpk") + quickSetJson(&r.SSHOpts, m, "sshopts") + quickSetInt64(&r.LastConnectTs, m, "lastconnectts") + return &r } func (cmd *CmdType) ToMap() map[string]interface{} { @@ -186,34 +221,10 @@ func (cmd *CmdType) ToMap() map[string]interface{} { return rtn } -func quickSetStr(strVal *string, m map[string]interface{}, name string) { - v, ok := m[name] - if !ok { - return - } - str, ok := v.(string) - if !ok { - return - } - *strVal = str -} - -func quickSetJson(ptr interface{}, m map[string]interface{}, name string) { - v, ok := m[name] - if !ok { - return - } - str, ok := v.(string) - if !ok { - return - } - if str == "" { - return - } - json.Unmarshal([]byte(str), ptr) -} - func CmdFromMap(m map[string]interface{}) *CmdType { + if len(m) == 0 { + return nil + } var cmd CmdType quickSetStr(&cmd.SessionId, m, "sessionid") quickSetStr(&cmd.CmdId, m, "cmdid") diff --git a/pkg/sstore/txwrap.go b/pkg/sstore/txwrap.go index 2bac4030f..43734e639 100644 --- a/pkg/sstore/txwrap.go +++ b/pkg/sstore/txwrap.go @@ -112,3 +112,20 @@ func (tx *TxWrap) SelectMaps(query string, args ...interface{}) []map[string]int } return rtn } + +func (tx *TxWrap) GetMap(query string, args ...interface{}) map[string]interface{} { + if tx.Err != nil { + return nil + } + row := tx.Txx.QueryRowx(query, args...) + m := make(map[string]interface{}) + err := row.MapScan(m) + if err != nil { + if err == sql.ErrNoRows { + return nil + } + tx.Err = err + return nil + } + return m +}