diff --git a/waveshell/pkg/packet/packet.go b/waveshell/pkg/packet/packet.go index cf6e39bab..ef3d0414f 100644 --- a/waveshell/pkg/packet/packet.go +++ b/waveshell/pkg/packet/packet.go @@ -743,13 +743,14 @@ func MakeCmdFinalPacket(ck base.CommandKey) *CmdFinalPacketType { } type CmdDonePacketType struct { - Type string `json:"type"` - Ts int64 `json:"ts"` - CK base.CommandKey `json:"ck"` - ExitCode int `json:"exitcode"` - DurationMs int64 `json:"durationms"` - FinalState *ShellState `json:"finalstate,omitempty"` - FinalStateDiff *ShellStateDiff `json:"finalstatediff,omitempty"` + Type string `json:"type"` + Ts int64 `json:"ts"` + CK base.CommandKey `json:"ck"` + ExitCode int `json:"exitcode"` + DurationMs int64 `json:"durationms"` + FinalState *ShellState `json:"finalstate,omitempty"` + FinalStateDiff *ShellStateDiff `json:"finalstatediff,omitempty"` + FinalStateBasePtr *ShellStatePtr `json:"finalstatebaseptr,omitempty"` } func (*CmdDonePacketType) GetType() string { @@ -814,10 +815,10 @@ type RunPacketType struct { Type string `json:"type"` ReqId string `json:"reqid"` CK base.CommandKey `json:"ck"` - ShellType string `json:"shelltype"` // new in v0.6.0 (either "bash" or "zsh") (set by remote.go) + ShellType string `json:"shelltype"` // added in Wave v0.6.0 (either "bash" or "zsh") (set by remote.go) Command string `json:"command"` State *ShellState `json:"state,omitempty"` - StateDiff *ShellStateDiff `json:"statediff,omitempty"` + StatePtr *ShellStatePtr `json:"stateptr,omitempty"` // added in Wave v0.7.2 StateComplete bool `json:"statecomplete,omitempty"` // set to true if state is complete (the default env should not be set) UsePty bool `json:"usepty,omitempty"` TermOpts *TermOpts `json:"termopts,omitempty"` diff --git a/waveshell/pkg/packet/shellstate.go b/waveshell/pkg/packet/shellstate.go index af4b04446..a01c6ae99 100644 --- a/waveshell/pkg/packet/shellstate.go +++ b/waveshell/pkg/packet/shellstate.go @@ -40,6 +40,18 @@ type ShellState struct { HashVal string `json:"-"` } +type ShellStatePtr struct { + BaseHash string `json:"basehash"` + DiffHashArr []string `json:"diffhasharr,omitempty"` +} + +func (ssptr *ShellStatePtr) IsEmpty() bool { + if ssptr == nil || ssptr.BaseHash == "" { + return true + } + return false +} + func (state ShellState) ApproximateSize() int64 { return int64(len(state.Version) + len(state.Cwd) + len(state.ShellVars) + len(state.Aliases) + len(state.Funcs) + len(state.Error)) } diff --git a/waveshell/pkg/server/server.go b/waveshell/pkg/server/server.go index edb13b295..89e588a54 100644 --- a/waveshell/pkg/server/server.go +++ b/waveshell/pkg/server/server.go @@ -50,7 +50,6 @@ type MServer struct { Sender *packet.PacketSender ClientMap map[base.CommandKey]*shexec.ClientProc Debug bool - StateMap *ShellStateMap WriteErrorCh chan bool // closed if there is a I/O write error WriteErrorChOnce *sync.Once Done bool @@ -338,11 +337,6 @@ func (m *MServer) reinit(reqId string, shellType string) { m.Sender.SendErrorResponse(reqId, fmt.Errorf("error initializing shell: %w", err)) return } - err = m.StateMap.SetCurrentState(ssPk.State.GetShellType(), ssPk.State) - if err != nil { - m.Sender.SendErrorResponse(reqId, fmt.Errorf("error setting current state: %w", err)) - return - } ssPk.RespId = reqId m.Sender.SendPacket(ssPk) } @@ -710,7 +704,7 @@ func (m *MServer) ProcessRpcPacket(pk packet.RpcPacketType) { m.Sender.SendErrorResponse(reqId, fmt.Errorf("invalid rpc type '%s'", pk.GetType())) } -func (m *MServer) clientPacketCallback(shellType string, pk packet.PacketType) { +func (m *MServer) clientPacketCallback(shellType string, pk packet.PacketType, runPk *packet.RunPacketType) { if pk.GetType() != packet.CmdDonePacketStr { return } @@ -718,25 +712,22 @@ func (m *MServer) clientPacketCallback(shellType string, pk packet.PacketType) { if donePk.FinalState == nil { return } - stateHash, curState := m.StateMap.GetCurrentState(shellType) - if curState == nil { + initialState := runPk.State + if initialState == nil { return } - sapi, err := shellapi.MakeShellApi(curState.GetShellType()) + initialStateHash := initialState.GetHashVal(false) + sapi, err := shellapi.MakeShellApi(initialState.GetShellType()) if err != nil { return } - diff, err := sapi.MakeShellStateDiff(curState, stateHash, donePk.FinalState) + diff, err := sapi.MakeShellStateDiff(initialState, initialStateHash, donePk.FinalState) if err != nil { return } donePk.FinalState = nil donePk.FinalStateDiff = diff -} - -func (m *MServer) isShellInitialized(shellType string) bool { - _, curState := m.StateMap.GetCurrentState(shellType) - return curState != nil + donePk.FinalStateBasePtr = runPk.StatePtr } func (m *MServer) runCommand(runPacket *packet.RunPacketType) { @@ -786,7 +777,7 @@ func (m *MServer) runCommand(runPacket *packet.RunPacketType) { }() shexec.SendRunPacketAndRunData(context.Background(), cproc.Input, runPacket) cproc.ProxySingleOutput(runPacket.CK, m.Sender, func(pk packet.PacketType) { - m.clientPacketCallback(runPacket.ShellType, pk) + m.clientPacketCallback(runPacket.ShellType, pk, runPacket) }) }() } @@ -849,7 +840,6 @@ func RunServer() (int, error) { server := &MServer{ Lock: &sync.Mutex{}, ClientMap: make(map[base.CommandKey]*shexec.ClientProc), - StateMap: MakeShellStateMap(), Debug: debug, WriteErrorCh: make(chan bool), WriteErrorChOnce: &sync.Once{}, diff --git a/waveshell/pkg/shellapi/shellapi.go b/waveshell/pkg/shellapi/shellapi.go index 3742c432f..81c481269 100644 --- a/waveshell/pkg/shellapi/shellapi.go +++ b/waveshell/pkg/shellapi/shellapi.go @@ -63,6 +63,9 @@ type ShellStateOutput struct { Error string } +// some timing info +// MakeShellStateDiff takes ~1ms to run (even on a large diff) + type ShellApi interface { GetShellType() string MakeExitTrap(fdNum int) (string, []byte) diff --git a/waveshell/pkg/statediff/linediff.go b/waveshell/pkg/statediff/linediff.go index 7e92eb9b1..1f6f652cd 100644 --- a/waveshell/pkg/statediff/linediff.go +++ b/waveshell/pkg/statediff/linediff.go @@ -186,6 +186,9 @@ func readEncodedStringArray(buf *bytes.Buffer) ([]string, error) { func (rtn *LineDiffType) Decode(diffBytes []byte) error { rtn.Clear() + if len(diffBytes) == 0 { + return nil + } r := bytes.NewBuffer(diffBytes) version, err := binary.ReadUvarint(r) if err != nil { diff --git a/waveshell/pkg/statediff/mapdiff.go b/waveshell/pkg/statediff/mapdiff.go index 87965b73a..d1ca830c7 100644 --- a/waveshell/pkg/statediff/mapdiff.go +++ b/waveshell/pkg/statediff/mapdiff.go @@ -29,7 +29,7 @@ func (diff *MapDiffType) Clear() { } func (diff MapDiffType) Dump() { - fmt.Printf("VAR-DIFF\n") + fmt.Printf("VAR-DIFF +%d -%d\n", len(diff.ToAdd), len(diff.ToRemove)) for name, val := range diff.ToAdd { fmt.Printf(" add[%s] %s\n", name, val) } @@ -111,6 +111,9 @@ func (diff MapDiffType) Encode() []byte { func (diff *MapDiffType) Decode(diffBytes []byte) error { diff.Clear() + if len(diffBytes) == 0 { + return nil + } r := bytes.NewBuffer(diffBytes) version, err := binpack.UnpackUInt(r) if err != nil { diff --git a/wavesrv/pkg/cmdrunner/cmdrunner.go b/wavesrv/pkg/cmdrunner/cmdrunner.go index 9f5fbede1..370a58750 100644 --- a/wavesrv/pkg/cmdrunner/cmdrunner.go +++ b/wavesrv/pkg/cmdrunner/cmdrunner.go @@ -3862,7 +3862,7 @@ func doAsyncResetCommand(msh *remote.MShellProc, opts connectOptsType, cmd *ssto rtnErr = err return } - newStatePtr := sstore.ShellStatePtr{ + newStatePtr := packet.ShellStatePtr{ BaseHash: ssPk.State.GetHashVal(false), } if opts.Verbose && origStatePtr != nil { diff --git a/wavesrv/pkg/cmdrunner/resolver.go b/wavesrv/pkg/cmdrunner/resolver.go index d87ca0372..da14d17b0 100644 --- a/wavesrv/pkg/cmdrunner/resolver.go +++ b/wavesrv/pkg/cmdrunner/resolver.go @@ -12,6 +12,7 @@ import ( "strings" "github.com/google/uuid" + "github.com/wavetermdev/waveterm/waveshell/pkg/packet" "github.com/wavetermdev/waveterm/wavesrv/pkg/remote" "github.com/wavetermdev/waveterm/wavesrv/pkg/scpacket" "github.com/wavetermdev/waveterm/wavesrv/pkg/sstore" @@ -42,7 +43,7 @@ type ResolvedRemote struct { RState remote.RemoteRuntimeState RemoteCopy *sstore.RemoteType ShellType string // default remote shell preference - StatePtr *sstore.ShellStatePtr + StatePtr *packet.ShellStatePtr FeState map[string]string } @@ -491,7 +492,7 @@ func ResolveRemoteFromPtr(ctx context.Context, rptr *sstore.RemotePtrType, sessi rtn.StatePtr = nil rtn.FeState = nil } else { - rtn.StatePtr = &sstore.ShellStatePtr{BaseHash: ri.StateBaseHash, DiffHashArr: ri.StateDiffHashArr} + rtn.StatePtr = &packet.ShellStatePtr{BaseHash: ri.StateBaseHash, DiffHashArr: ri.StateDiffHashArr} rtn.FeState = ri.FeState rtn.ShellType = ri.ShellType } diff --git a/wavesrv/pkg/remote/remote.go b/wavesrv/pkg/remote/remote.go index 0471222b5..7b3375ada 100644 --- a/wavesrv/pkg/remote/remote.go +++ b/wavesrv/pkg/remote/remote.go @@ -1886,7 +1886,7 @@ type RunCommandOpts struct { // optional, if not provided shellstate will look up state from remote instance // ReturnState cannot be used with StatePtr // this will also cause this command to bypass the pending state cmd logic - StatePtr *sstore.ShellStatePtr + StatePtr *packet.ShellStatePtr // set to true to skip creating the pty file (for restarted commands) NoCreateCmdPtyFile bool @@ -1920,6 +1920,9 @@ func RunCommand(ctx context.Context, rcOpts RunCommandOpts, runPacket *packet.Ru if rcOpts.StatePtr != nil && runPacket.ReturnState { return nil, nil, fmt.Errorf("RunCommand: cannot use ReturnState with StatePtr") } + if runPacket.StatePtr != nil { + return nil, nil, fmt.Errorf("runPacket.StatePtr should not be set, it is set in RunCommand") + } // pending state command logic // if we are currently running a command that can change the state, we need to wait for it to finish @@ -1950,7 +1953,7 @@ func RunCommand(ctx context.Context, rcOpts RunCommandOpts, runPacket *packet.Ru } // get current remote-instance state - var statePtr *sstore.ShellStatePtr + var statePtr *packet.ShellStatePtr if rcOpts.StatePtr != nil { statePtr = rcOpts.StatePtr } else { @@ -1963,6 +1966,8 @@ func RunCommand(ctx context.Context, rcOpts RunCommandOpts, runPacket *packet.Ru return nil, nil, fmt.Errorf("cannot run command: no valid shell state found") } } + // statePtr will not be nil + runPacket.StatePtr = statePtr currentState, err := sstore.GetFullState(ctx, *statePtr) if err != nil || currentState == nil { return nil, nil, fmt.Errorf("cannot load current remote state: %w", err) @@ -2216,31 +2221,95 @@ func (msh *MShellProc) notifyHangups_nolock() { msh.PendingStateCmds = make(map[pendingStateKey]base.CommandKey) } -// either fullstate or statediff will be set (not both) <- this is so the result is compatible with the sstore.UpdateRemoteState function -// note that this function *does* touch the DB, if FinalStateDiff is set, will ensure that StateBase is written to DB -func (msh *MShellProc) makeStatePtrFromFinalState(ctx context.Context, donePk *packet.CmdDonePacketType) (*sstore.ShellStatePtr, map[string]string, *packet.ShellState, *packet.ShellStateDiff, error) { +func (msh *MShellProc) resolveFinalState(ctx context.Context, origState *packet.ShellState, origStatePtr *packet.ShellStatePtr, donePk *packet.CmdDonePacketType) (*packet.ShellState, error) { if donePk.FinalState != nil { + if origStatePtr == nil { + return nil, fmt.Errorf("command must have a stateptr to resolve final state") + } finalState := stripScVarsFromState(donePk.FinalState) - feState := sstore.FeStateFromShellState(finalState) - statePtr := &sstore.ShellStatePtr{BaseHash: finalState.GetHashVal(false)} - return statePtr, feState, finalState, nil, nil + return finalState, nil } if donePk.FinalStateDiff != nil { + if donePk.FinalStateBasePtr == nil { + return nil, fmt.Errorf("invalid rtnstate, has diff but no baseptr") + } stateDiff := stripScVarsFromStateDiff(donePk.FinalStateDiff) - feState, err := msh.getFeStateFromDiff(stateDiff) + if origStatePtr == donePk.FinalStateBasePtr { + // this is the normal case. the stateptr from the run-packet should match the baseptr from the done-packet + // this is also the most efficient, because we don't need to fetch the original state + sapi, err := shellapi.MakeShellApi(origState.GetShellType()) + if err != nil { + return nil, fmt.Errorf("cannot make shellapi from initial state: %w", err) + } + fullState, err := sapi.ApplyShellStateDiff(origState, stateDiff) + if err != nil { + return nil, fmt.Errorf("cannot apply shell state diff: %w", err) + } + return fullState, nil + } + // this is strange (why is backend returning non-original stateptr?) + // but here, we fetch the stateptr, and then apply the diff against that + realOrigState, err := sstore.GetFullState(ctx, *donePk.FinalStateBasePtr) if err != nil { - return nil, nil, nil, nil, err + return nil, fmt.Errorf("cannot get original state for diff: %w", err) } - fullState := msh.StateMap.GetStateByHash(stateDiff.GetShellType(), stateDiff.BaseHash) - if fullState != nil { - sstore.StoreStateBase(ctx, fullState) + if realOrigState == nil { + return nil, fmt.Errorf("cannot get original state for diff: not found") } - diffHashArr := append(([]string)(nil), donePk.FinalStateDiff.DiffHashArr...) - diffHashArr = append(diffHashArr, donePk.FinalStateDiff.GetHashVal(false)) - statePtr := &sstore.ShellStatePtr{BaseHash: donePk.FinalStateDiff.BaseHash, DiffHashArr: diffHashArr} - return statePtr, feState, nil, stateDiff, nil + sapi, err := shellapi.MakeShellApi(realOrigState.GetShellType()) + if err != nil { + return nil, fmt.Errorf("cannot make shellapi from original state: %w", err) + } + fullState, err := sapi.ApplyShellStateDiff(realOrigState, stateDiff) + if err != nil { + return nil, fmt.Errorf("cannot apply shell state diff: %w", err) + } + return fullState, nil } - return nil, nil, nil, nil, nil + return nil, nil +} + +// after this limit we'll switch to persisting the full state +const NewStateDiffSizeThreshold = 30 * 1024 + +// will update the remote instance with the final state +// this is complicated because we want to be as efficient as possible. +// so we pull the current remote-instance state (just the baseptr). then we compute the diff. +// then we check the size of the diff, and only persist the diff it is under some size threshold +// also we check to see if the diff succeeds (it can fail if the shell or version changed). +// in those cases we also update the RI with the full state +func (msh *MShellProc) updateRIWithFinalState(ctx context.Context, rct *RunCmdType, newState *packet.ShellState) (*sstore.RemoteInstance, error) { + curRIState, err := sstore.GetRemoteStatePtr(ctx, rct.SessionId, rct.ScreenId, rct.RemotePtr) + if err != nil { + return nil, fmt.Errorf("error trying to get current screen stateptr: %w", err) + } + feState := sstore.FeStateFromShellState(newState) + if curRIState == nil { + // no current state, so just persist the full state + return sstore.UpdateRemoteState(ctx, rct.SessionId, rct.ScreenId, rct.RemotePtr, feState, newState, nil) + } + // pull the base (not the diff) state from the RI (right now we don't want to make multi-level diffs) + riBaseState, err := sstore.GetStateBase(ctx, curRIState.BaseHash) + if err != nil { + return nil, fmt.Errorf("error trying to get statebase: %w", err) + } + sapi, err := shellapi.MakeShellApi(riBaseState.GetShellType()) + if err != nil { + return nil, fmt.Errorf("error trying to make shellapi: %w", err) + } + newStateDiff, err := sapi.MakeShellStateDiff(riBaseState, curRIState.BaseHash, newState) + if err != nil { + // if we can't make a diff, just persist the full state (this could happen if the shell type changes) + return sstore.UpdateRemoteState(ctx, rct.SessionId, rct.ScreenId, rct.RemotePtr, feState, newState, nil) + } + // we have a diff, let's check the diff size first + _, encodedDiff := newStateDiff.EncodeAndHash() + if len(encodedDiff) > NewStateDiffSizeThreshold { + // diff is too large, persist the full state + return sstore.UpdateRemoteState(ctx, rct.SessionId, rct.ScreenId, rct.RemotePtr, feState, newState, nil) + } + // diff is small enough, persist the diff + return sstore.UpdateRemoteState(ctx, rct.SessionId, rct.ScreenId, rct.RemotePtr, feState, nil, newStateDiff) } func (msh *MShellProc) handleCmdDonePacket(rct *RunCmdType, donePk *packet.CmdDonePacketType) { @@ -2261,12 +2330,12 @@ func (msh *MShellProc) handleCmdDonePacket(rct *RunCmdType, donePk *packet.CmdDo // only update DB for non-ephemeral commands err := sstore.UpdateCmdDoneInfo(ctx, update, donePk.CK, donePk, sstore.CmdStatusDone) if err != nil { - msh.WriteToPtyBuffer("*error updating cmddone: %v\n", err) + log.Printf("error updating cmddone info (in handleCmdDonePacket): %v\n", err) return } screen, err := sstore.UpdateScreenFocusForDoneCmd(ctx, donePk.CK.GetGroupId(), donePk.CK.GetCmdId()) if err != nil { - msh.WriteToPtyBuffer("*error trying to update screen focus type: %v\n", err) + log.Printf("error trying to update screen focus type (in handleCmdDonePacket): %v\n", err) // fall-through (nothing to do) } if screen != nil { @@ -2274,24 +2343,28 @@ func (msh *MShellProc) handleCmdDonePacket(rct *RunCmdType, donePk *packet.CmdDo } } // ephemeral commands *do* update the remote state - if donePk.FinalState != nil || donePk.FinalStateDiff != nil { - statePtr, feState, finalState, finalStateDiff, err := msh.makeStatePtrFromFinalState(ctx, donePk) + // not all commands get a final state (only RtnState commands have this returned) + // so in those cases finalState will be nil + finalState, err := msh.resolveFinalState(ctx, rct.RunPacket.State, rct.RunPacket.StatePtr, donePk) + if err != nil { + log.Printf("error resolving final state for cmd: %v\n", err) + // fallthrough + } + if finalState != nil { + newRI, err := msh.updateRIWithFinalState(ctx, rct, finalState) if err != nil { - msh.WriteToPtyBuffer("*error trying to read final command state: %v\n", err) + log.Printf("error updating RI with final state (in handleCmdDonePacket): %v\n", err) + // fallthrough } - remoteInst, err := sstore.UpdateRemoteState(ctx, rct.SessionId, rct.ScreenId, rct.RemotePtr, feState, finalState, finalStateDiff) - if err != nil { - msh.WriteToPtyBuffer("*error trying to update remotestate: %v\n", err) - // fall-through (nothing to do) - } - if remoteInst != nil { - update.AddUpdate(sstore.MakeSessionUpdateForRemote(rct.SessionId, remoteInst)) + if newRI != nil { + update.AddUpdate(sstore.MakeSessionUpdateForRemote(rct.SessionId, newRI)) } // ephemeral commands *do not* update cmd state (there is no command) - if statePtr != nil && !rct.Ephemeral { - err = sstore.UpdateCmdRtnState(ctx, donePk.CK, *statePtr) + if newRI != nil && !rct.Ephemeral { + newRIStatePtr := packet.ShellStatePtr{BaseHash: newRI.StateBaseHash, DiffHashArr: newRI.StateDiffHashArr} + err = sstore.UpdateCmdRtnState(ctx, donePk.CK, newRIStatePtr) if err != nil { - msh.WriteToPtyBuffer("*error trying to update cmd rtnstate: %v\n", err) + log.Printf("error trying to update cmd rtnstate: %v\n", err) // fall-through (nothing to do) } } @@ -2605,7 +2678,7 @@ func (msh *MShellProc) getFullState(shellType string, stateDiff *packet.ShellSta } return newState, nil } else { - fullState, err := sstore.GetFullState(context.Background(), sstore.ShellStatePtr{BaseHash: stateDiff.BaseHash, DiffHashArr: stateDiff.DiffHashArr}) + fullState, err := sstore.GetFullState(context.Background(), packet.ShellStatePtr{BaseHash: stateDiff.BaseHash, DiffHashArr: stateDiff.DiffHashArr}) if err != nil { return nil, err } @@ -2632,7 +2705,7 @@ func (msh *MShellProc) getFeStateFromDiff(stateDiff *packet.ShellStateDiff) (map } return sstore.FeStateFromShellState(newState), nil } else { - fullState, err := sstore.GetFullState(context.Background(), sstore.ShellStatePtr{BaseHash: stateDiff.BaseHash, DiffHashArr: stateDiff.DiffHashArr}) + fullState, err := sstore.GetFullState(context.Background(), packet.ShellStatePtr{BaseHash: stateDiff.BaseHash, DiffHashArr: stateDiff.DiffHashArr}) if err != nil { return nil, err } diff --git a/wavesrv/pkg/scpacket/scpacket.go b/wavesrv/pkg/scpacket/scpacket.go index e40b68cc8..6e604643e 100644 --- a/wavesrv/pkg/scpacket/scpacket.go +++ b/wavesrv/pkg/scpacket/scpacket.go @@ -35,10 +35,10 @@ func (rptr *RemotePtrType) GetDisplayName(baseDisplayName string) string { return name } if rptr.Name != "" { - name = name + ":" + rptr.Name + name = name + "#" + rptr.Name } if rptr.OwnerId != "" { - name = "@" + rptr.OwnerId + ":" + name + name = "@" + rptr.OwnerId + "#" + name } return name } diff --git a/wavesrv/pkg/sstore/dbops.go b/wavesrv/pkg/sstore/dbops.go index 41669227a..17e4b438a 100644 --- a/wavesrv/pkg/sstore/dbops.go +++ b/wavesrv/pkg/sstore/dbops.go @@ -793,7 +793,7 @@ func UpdateCmdDoneInfo(ctx context.Context, update *scbus.ModelUpdatePacketType, return nil } -func UpdateCmdRtnState(ctx context.Context, ck base.CommandKey, statePtr ShellStatePtr) error { +func UpdateCmdRtnState(ctx context.Context, ck base.CommandKey, statePtr packet.ShellStatePtr) error { if ck.IsEmpty() { return fmt.Errorf("cannot update cmdrtnstate, empty ck") } @@ -1098,7 +1098,7 @@ func DeleteScreen(ctx context.Context, screenId string, sessionDel bool, update return update, nil } -func GetRemoteState(ctx context.Context, sessionId string, screenId string, remotePtr RemotePtrType) (*packet.ShellState, *ShellStatePtr, error) { +func GetRemoteState(ctx context.Context, sessionId string, screenId string, remotePtr RemotePtrType) (*packet.ShellState, *packet.ShellStatePtr, error) { ssptr, err := GetRemoteStatePtr(ctx, sessionId, screenId, remotePtr) if err != nil { return nil, nil, err @@ -1113,8 +1113,8 @@ func GetRemoteState(ctx context.Context, sessionId string, screenId string, remo return state, ssptr, err } -func GetRemoteStatePtr(ctx context.Context, sessionId string, screenId string, remotePtr RemotePtrType) (*ShellStatePtr, error) { - var ssptr *ShellStatePtr +func GetRemoteStatePtr(ctx context.Context, sessionId string, screenId string, remotePtr RemotePtrType) (*packet.ShellStatePtr, error) { + var ssptr *packet.ShellStatePtr txErr := WithTx(ctx, func(tx *TxWrap) error { ri, err := GetRemoteInstance(tx.Context(), sessionId, screenId, remotePtr) if err != nil { @@ -1123,7 +1123,7 @@ func GetRemoteStatePtr(ctx context.Context, sessionId string, screenId string, r if ri == nil { return nil } - ssptr = &ShellStatePtr{ri.StateBaseHash, ri.StateDiffHashArr} + ssptr = &packet.ShellStatePtr{ri.StateBaseHash, ri.StateDiffHashArr} return nil }) if txErr != nil { @@ -1836,7 +1836,7 @@ func GetStateBaseVersion(ctx context.Context, baseHash string) (string, error) { }) } -func GetCurStateDiffFromPtr(ctx context.Context, ssPtr *ShellStatePtr) (*packet.ShellStateDiff, error) { +func GetCurStateDiffFromPtr(ctx context.Context, ssPtr *packet.ShellStatePtr) (*packet.ShellStateDiff, error) { if ssPtr == nil { return nil, fmt.Errorf("cannot resolve state, empty stateptr") } @@ -1894,7 +1894,7 @@ func GetStateDiff(ctx context.Context, diffHash string) (*packet.ShellStateDiff, } // returns error when not found -func GetFullState(ctx context.Context, ssPtr ShellStatePtr) (*packet.ShellState, error) { +func GetFullState(ctx context.Context, ssPtr packet.ShellStatePtr) (*packet.ShellState, error) { var state *packet.ShellState if ssPtr.BaseHash == "" { return nil, fmt.Errorf("invalid empty basehash") diff --git a/wavesrv/pkg/sstore/sstore.go b/wavesrv/pkg/sstore/sstore.go index 00f074485..ab7d8bc37 100644 --- a/wavesrv/pkg/sstore/sstore.go +++ b/wavesrv/pkg/sstore/sstore.go @@ -538,18 +538,6 @@ func (opts TermOpts) Value() (driver.Value, error) { return quickValueJson(opts) } -type ShellStatePtr struct { - BaseHash string - DiffHashArr []string -} - -func (ssptr *ShellStatePtr) IsEmpty() bool { - if ssptr == nil || ssptr.BaseHash == "" { - return true - } - return false -} - type RemoteInstance struct { RIId string `json:"riid"` Name string `json:"name"` @@ -864,27 +852,27 @@ func (r *RemoteType) GetName() string { } type CmdType struct { - ScreenId string `json:"screenid"` - LineId string `json:"lineid"` - Remote RemotePtrType `json:"remote"` - CmdStr string `json:"cmdstr"` - RawCmdStr string `json:"rawcmdstr"` - FeState map[string]string `json:"festate"` - StatePtr ShellStatePtr `json:"state"` - TermOpts TermOpts `json:"termopts"` - OrigTermOpts TermOpts `json:"origtermopts"` - Status string `json:"status"` - CmdPid int `json:"cmdpid"` - RemotePid int `json:"remotepid"` - RestartTs int64 `json:"restartts,omitempty"` - DoneTs int64 `json:"donets"` - ExitCode int `json:"exitcode"` - DurationMs int `json:"durationms"` - RunOut []packet.PacketType `json:"runout,omitempty"` - RtnState bool `json:"rtnstate,omitempty"` - RtnStatePtr ShellStatePtr `json:"rtnstateptr,omitempty"` - Remove bool `json:"remove,omitempty"` // not persisted to DB - Restarted bool `json:"restarted,omitempty"` // not persisted to DB + ScreenId string `json:"screenid"` + LineId string `json:"lineid"` + Remote RemotePtrType `json:"remote"` + CmdStr string `json:"cmdstr"` + RawCmdStr string `json:"rawcmdstr"` + FeState map[string]string `json:"festate"` + StatePtr packet.ShellStatePtr `json:"state"` + TermOpts TermOpts `json:"termopts"` + OrigTermOpts TermOpts `json:"origtermopts"` + Status string `json:"status"` + CmdPid int `json:"cmdpid"` + RemotePid int `json:"remotepid"` + RestartTs int64 `json:"restartts,omitempty"` + DoneTs int64 `json:"donets"` + ExitCode int `json:"exitcode"` + DurationMs int `json:"durationms"` + RunOut []packet.PacketType `json:"runout,omitempty"` + RtnState bool `json:"rtnstate,omitempty"` + RtnStatePtr packet.ShellStatePtr `json:"rtnstateptr,omitempty"` + Remove bool `json:"remove,omitempty"` // not persisted to DB + Restarted bool `json:"restarted,omitempty"` // not persisted to DB } func (CmdType) GetType() string {