diff --git a/pkg/pcloud/pclouddata.go b/pkg/pcloud/pclouddata.go index da85cccd..f77660d5 100644 --- a/pkg/pcloud/pclouddata.go +++ b/pkg/pcloud/pclouddata.go @@ -49,22 +49,13 @@ func (ur *WebShareUpdateResponseType) GetSimpleKey() int64 { return ur.UpdateId } -type WebShareRemotePtr struct { +type WebShareRemote struct { + RemoteId string `json:"remoteid"` Alias string `json:"alias,omitempty"` CanonicalName string `json:"canonicalname"` Name string `json:"name,omitempty"` -} - -func webRemoteFromRemotePtr(rptr sstore.RemotePtrType) *WebShareRemotePtr { - if rptr.RemoteId == "" { - return nil - } - rcopy := remote.GetRemoteById(rptr.RemoteId).GetRemoteCopy() - return &WebShareRemotePtr{ - Alias: rcopy.RemoteAlias, - CanonicalName: rcopy.RemoteCanonicalName, - Name: rptr.Name, - } + HomeDir string `json:"homedir,omitempty"` + IsRoot bool `json:"isroot,omitempty"` } type WebShareScreenType struct { @@ -73,6 +64,17 @@ type WebShareScreenType struct { ViewKey string `json:"viewkey"` } +func webRemoteFromRemote(rptr sstore.RemotePtrType, r *sstore.RemoteType) *WebShareRemote { + return &WebShareRemote{ + RemoteId: r.RemoteId, + Alias: r.RemoteAlias, + CanonicalName: r.RemoteCanonicalName, + Name: rptr.Name, + HomeDir: r.StateVars["home"], + IsRoot: r.StateVars["remoteuser"] == "root", + } +} + func webScreenFromScreen(s *sstore.ScreenType) (*WebShareScreenType, error) { if s == nil || s.ScreenId == "" { return nil, fmt.Errorf("invalid nil screen") @@ -121,7 +123,7 @@ type WebShareCmdType struct { LineId string `json:"lineid"` CmdStr string `json:"cmdstr"` RawCmdStr string `json:"rawcmdstr"` - Remote *WebShareRemotePtr `json:"remote"` + Remote *WebShareRemote `json:"remote"` FeState sstore.FeStateType `json:"festate"` TermOpts sstore.TermOpts `json:"termopts"` Status string `json:"status"` @@ -132,11 +134,19 @@ type WebShareCmdType struct { } func webCmdFromCmd(lineId string, cmd *sstore.CmdType) (*WebShareCmdType, error) { + if cmd.Remote.RemoteId == "" { + return nil, fmt.Errorf("invalid cmd, remoteptr has no remoteid") + } + remote := remote.GetRemoteCopyById(cmd.Remote.RemoteId) + if remote == nil { + return nil, fmt.Errorf("invalid cmd, cannot retrieve remote:%s", cmd.Remote.RemoteId) + } + webRemote := webRemoteFromRemote(cmd.Remote, remote) rtn := &WebShareCmdType{ LineId: lineId, CmdStr: cmd.CmdStr, RawCmdStr: cmd.RawCmdStr, - Remote: webRemoteFromRemotePtr(cmd.Remote), + Remote: webRemote, FeState: cmd.FeState, TermOpts: cmd.TermOpts, Status: cmd.Status, diff --git a/pkg/remote/remote.go b/pkg/remote/remote.go index d95ad095..1129b949 100644 --- a/pkg/remote/remote.go +++ b/pkg/remote/remote.go @@ -387,6 +387,15 @@ func GetRemoteById(remoteId string) *MShellProc { return GlobalStore.Map[remoteId] } +func GetRemoteCopyById(remoteId string) *sstore.RemoteType { + msh := GetRemoteById(remoteId) + if msh == nil { + return nil + } + rcopy := msh.GetRemoteCopy() + return &rcopy +} + func GetRemoteMap() map[string]*MShellProc { GlobalStore.Lock.Lock() defer GlobalStore.Lock.Unlock() @@ -518,7 +527,10 @@ func (msh *MShellProc) GetRemoteRuntimeState() RemoteRuntimeState { if msh.Status == StatusConnecting { state.WaitingForPassword = msh.isWaitingForPassword_nolock() } - vars := make(map[string]string) + vars := msh.Remote.StateVars + if vars == nil { + vars = make(map[string]string) + } vars["user"] = msh.Remote.RemoteUser vars["bestuser"] = vars["user"] vars["host"] = msh.Remote.RemoteHost @@ -963,6 +975,33 @@ func (msh *MShellProc) RunInstall() { return } +func (msh *MShellProc) updateRemoteStateVars(ctx context.Context, remoteId string, initPk *packet.InitPacketType) { + msh.Lock.Lock() + defer msh.Lock.Unlock() + stateVars := getStateVarsFromInitPk(initPk) + if stateVars == nil { + return + } + msh.Remote.StateVars = stateVars + err := sstore.UpdateRemoteStateVars(ctx, remoteId, stateVars) + if err != nil { + // ignore error, nothing to do + log.Printf("error updating remote statevars: %v\n", err) + } +} + +func getStateVarsFromInitPk(initPk *packet.InitPacketType) map[string]string { + if initPk == nil || initPk.NotFound { + return nil + } + rtn := make(map[string]string) + rtn["home"] = initPk.HomeDir + rtn["remoteuser"] = initPk.User + rtn["remotehost"] = initPk.HostName + rtn["remoteuname"] = initPk.UName + return rtn +} + func (msh *MShellProc) ReInit(ctx context.Context) (*packet.InitPacketType, error) { reinitPk := packet.MakeReInitPacket() reinitPk.ReqId = uuid.New().String() @@ -986,6 +1025,8 @@ func (msh *MShellProc) ReInit(ctx context.Context) (*packet.InitPacketType, erro msh.CurrentState = hval msh.StateMap[hval] = initPk.State }) + msh.updateRemoteStateVars(ctx, msh.RemoteId, initPk) + return initPk, nil } @@ -1139,6 +1180,7 @@ func (msh *MShellProc) Launch(interactive bool) { msh.WriteToPtyBuffer("*error connecting to remote: %v\n", err) return } + msh.updateRemoteStateVars(context.Background(), msh.RemoteId, initPk) msh.WriteToPtyBuffer("connected state:%s\n", stateBaseHash) msh.WithLock(func() { msh.ServerProc = cproc diff --git a/pkg/sstore/dbops.go b/pkg/sstore/dbops.go index f6fd32a5..dc826533 100644 --- a/pkg/sstore/dbops.go +++ b/pkg/sstore/dbops.go @@ -199,14 +199,22 @@ func UpsertRemote(ctx context.Context, r *RemoteType) error { maxRemoteIdx := tx.GetInt(query) r.RemoteIdx = int64(maxRemoteIdx + 1) query = `INSERT INTO remote - ( remoteid, physicalid, remotetype, remotealias, remotecanonicalname, remotesudo, remoteuser, remotehost, connectmode, autoinstall, sshopts, remoteopts, lastconnectts, archived, remoteidx, local) VALUES - (:remoteid,:physicalid,:remotetype,:remotealias,:remotecanonicalname,:remotesudo,:remoteuser,:remotehost,:connectmode,:autoinstall,:sshopts,:remoteopts,:lastconnectts,:archived,:remoteidx,:local)` + ( remoteid, physicalid, remotetype, remotealias, remotecanonicalname, remotesudo, remoteuser, remotehost, connectmode, autoinstall, sshopts, remoteopts, lastconnectts, archived, remoteidx, local, statevars) VALUES + (:remoteid,:physicalid,:remotetype,:remotealias,:remotecanonicalname,:remotesudo,:remoteuser,:remotehost,:connectmode,:autoinstall,:sshopts,:remoteopts,:lastconnectts,:archived,:remoteidx,:local,:statevars)` tx.NamedExec(query, r.ToMap()) return nil }) return txErr } +func UpdateRemoteStateVars(ctx context.Context, remoteId string, stateVars map[string]string) error { + return WithTx(ctx, func(tx *TxWrap) error { + query := `UPDATE remote SET statevars = ? WHERE remoteid = ?` + tx.Exec(query, quickJson(stateVars), remoteId) + return nil + }) +} + func InsertHistoryItem(ctx context.Context, hitem *HistoryItemType) error { if hitem == nil { return fmt.Errorf("cannot insert nil history item") diff --git a/pkg/sstore/migrate.go b/pkg/sstore/migrate.go index b6f46156..fb1bfb7f 100644 --- a/pkg/sstore/migrate.go +++ b/pkg/sstore/migrate.go @@ -17,7 +17,7 @@ import ( "github.com/golang-migrate/migrate/v4" ) -const MaxMigration = 16 +const MaxMigration = 17 const MigratePrimaryScreenVersion = 9 func MakeMigrate() (*migrate.Migrate, error) { diff --git a/pkg/sstore/sstore.go b/pkg/sstore/sstore.go index d5440984..3357ec93 100644 --- a/pkg/sstore/sstore.go +++ b/pkg/sstore/sstore.go @@ -377,8 +377,9 @@ type ScreenLinesType struct { func (ScreenLinesType) UseDBMap() {} type ScreenWebShareOpts struct { - ShareName string `json:"sharename"` - ViewKey string `json:"viewkey"` + ShareName string `json:"sharename"` + ViewKey string `json:"viewkey"` + SharedRemotes []string `json:"sharedremotes"` } type ScreenType struct { @@ -804,22 +805,23 @@ func (opts RemoteOptsType) Value() (driver.Value, error) { } type RemoteType struct { - RemoteId string `json:"remoteid"` - PhysicalId string `json:"physicalid"` - RemoteType string `json:"remotetype"` - RemoteAlias string `json:"remotealias"` - RemoteCanonicalName string `json:"remotecanonicalname"` - RemoteSudo bool `json:"remotesudo"` - RemoteUser string `json:"remoteuser"` - RemoteHost string `json:"remotehost"` - ConnectMode string `json:"connectmode"` - AutoInstall bool `json:"autoinstall"` - SSHOpts *SSHOpts `json:"sshopts"` - RemoteOpts *RemoteOptsType `json:"remoteopts"` - LastConnectTs int64 `json:"lastconnectts"` - Archived bool `json:"archived"` - RemoteIdx int64 `json:"remoteidx"` - Local bool `json:"local"` + RemoteId string `json:"remoteid"` + PhysicalId string `json:"physicalid"` + RemoteType string `json:"remotetype"` + RemoteAlias string `json:"remotealias"` + RemoteCanonicalName string `json:"remotecanonicalname"` + RemoteSudo bool `json:"remotesudo"` + RemoteUser string `json:"remoteuser"` + RemoteHost string `json:"remotehost"` + ConnectMode string `json:"connectmode"` + AutoInstall bool `json:"autoinstall"` + SSHOpts *SSHOpts `json:"sshopts"` + RemoteOpts *RemoteOptsType `json:"remoteopts"` + LastConnectTs int64 `json:"lastconnectts"` + Archived bool `json:"archived"` + RemoteIdx int64 `json:"remoteidx"` + Local bool `json:"local"` + StateVars map[string]string `json:"statevars"` } func (r *RemoteType) GetName() string { @@ -878,6 +880,7 @@ func (r *RemoteType) ToMap() map[string]interface{} { rtn["archived"] = r.Archived rtn["remoteidx"] = r.RemoteIdx rtn["local"] = r.Local + rtn["statevars"] = quickJson(r.StateVars) return rtn } @@ -898,6 +901,7 @@ func (r *RemoteType) FromMap(m map[string]interface{}) bool { quickSetBool(&r.Archived, m, "archived") quickSetInt64(&r.RemoteIdx, m, "remoteidx") quickSetBool(&r.Local, m, "local") + quickSetJson(&r.StateVars, m, "statevars") return true }