mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-10 19:58:00 +01:00
checkpoint, backend changes for consolidating window and screen_window to screen
This commit is contained in:
parent
ee2fd8e98f
commit
e154aacaad
@ -193,25 +193,20 @@ func HandleLogActiveState(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// params: sessionid, windowid
|
||||
func HandleGetWindow(w http.ResponseWriter, r *http.Request) {
|
||||
// params: screenid
|
||||
func HandleGetFullScreen(w http.ResponseWriter, r *http.Request) {
|
||||
qvals := r.URL.Query()
|
||||
sessionId := qvals.Get("sessionid")
|
||||
windowId := qvals.Get("windowid")
|
||||
if _, err := uuid.Parse(sessionId); err != nil {
|
||||
WriteJsonError(w, fmt.Errorf("invalid sessionid: %w", err))
|
||||
screenId := qvals.Get("screenid")
|
||||
if _, err := uuid.Parse(screenId); err != nil {
|
||||
WriteJsonError(w, fmt.Errorf("invalid screenid: %w", err))
|
||||
return
|
||||
}
|
||||
if _, err := uuid.Parse(windowId); err != nil {
|
||||
WriteJsonError(w, fmt.Errorf("invalid windowid: %w", err))
|
||||
return
|
||||
}
|
||||
window, err := sstore.GetWindowById(r.Context(), sessionId, windowId)
|
||||
screen, err := sstore.GetFullScreenById(r.Context(), screenId)
|
||||
if err != nil {
|
||||
WriteJsonError(w, err)
|
||||
return
|
||||
}
|
||||
WriteJsonSuccess(w, window)
|
||||
WriteJsonSuccess(w, screen)
|
||||
return
|
||||
}
|
||||
|
||||
@ -567,7 +562,7 @@ func main() {
|
||||
gr.HandleFunc("/api/ptyout", AuthKeyWrap(HandleGetPtyOut))
|
||||
gr.HandleFunc("/api/remote-pty", AuthKeyWrap(HandleRemotePty))
|
||||
gr.HandleFunc("/api/rtnstate", AuthKeyWrap(HandleRtnState))
|
||||
gr.HandleFunc("/api/get-window", AuthKeyWrap(HandleGetWindow))
|
||||
gr.HandleFunc("/api/get-full-screen", AuthKeyWrap(HandleGetFullScreen))
|
||||
gr.HandleFunc("/api/run-command", AuthKeyWrap(HandleRunCommand)).Methods("POST")
|
||||
gr.HandleFunc("/api/get-client-data", AuthKeyWrap(HandleGetClientData))
|
||||
gr.HandleFunc("/api/set-winsize", AuthKeyWrap(HandleSetWinSize))
|
||||
|
3
db/migrations/000009_screenprimary.down.sql
Normal file
3
db/migrations/000009_screenprimary.down.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- invalid, will throw an error, cannot migrate down past 9
|
||||
SELECT x;
|
||||
|
56
db/migrations/000009_screenprimary.up.sql
Normal file
56
db/migrations/000009_screenprimary.up.sql
Normal file
@ -0,0 +1,56 @@
|
||||
CREATE TABLE new_screen (
|
||||
sessionid varchar(36) NOT NULL,
|
||||
screenid varchar(36) NOT NULL,
|
||||
windowid varchar(36) NOT NULL,
|
||||
name varchar(50) NOT NULL,
|
||||
screenidx int NOT NULL,
|
||||
screenopts json NOT NULL,
|
||||
ownerid varchar(36) NOT NULL,
|
||||
sharemode varchar(12) NOT NULL,
|
||||
curremoteownerid varchar(36) NOT NULL,
|
||||
curremoteid varchar(36) NOT NULL,
|
||||
curremotename varchar(50) NOT NULL,
|
||||
nextlinenum int NOT NULL,
|
||||
selectedline int NOT NULL,
|
||||
anchor json NOT NULL,
|
||||
focustype varchar(12) NOT NULL,
|
||||
archived boolean NOT NULL,
|
||||
archivedts bigint NOT NULL,
|
||||
PRIMARY KEY (sessionid, screenid)
|
||||
);
|
||||
|
||||
INSERT INTO new_screen
|
||||
SELECT
|
||||
s.sessionid,
|
||||
s.screenid,
|
||||
w.windowid,
|
||||
s.name,
|
||||
s.screenidx,
|
||||
json_patch(s.screenopts, w.winopts),
|
||||
s.ownerid,
|
||||
s.sharemode,
|
||||
w.curremoteownerid,
|
||||
w.curremoteid,
|
||||
w.curremotename,
|
||||
w.nextlinenum,
|
||||
sw.selectedline,
|
||||
sw.anchor,
|
||||
sw.focustype,
|
||||
s.archived,
|
||||
s.archivedts
|
||||
FROM
|
||||
screen s,
|
||||
screen_window sw,
|
||||
window w
|
||||
WHERE
|
||||
s.screenid = sw.screenid
|
||||
AND sw.windowid = w.windowid
|
||||
;
|
||||
|
||||
DROP TABLE screen;
|
||||
DROP TABLE screen_window;
|
||||
DROP TABLE window;
|
||||
|
||||
ALTER TABLE new_screen RENAME TO screen;
|
||||
|
||||
|
@ -151,7 +151,6 @@ func init() {
|
||||
registerCmdFn("remote:installcancel", RemoteInstallCancelCommand)
|
||||
registerCmdFn("remote:reset", RemoteResetCommand)
|
||||
|
||||
registerCmdFn("sw:set", SwSetCommand)
|
||||
registerCmdFn("sw:resize", SwResizeCommand)
|
||||
|
||||
// sw:resize
|
||||
@ -458,7 +457,7 @@ func ScreenArchiveCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/screen:archive cannot re-open screen: %v", err)
|
||||
}
|
||||
screen, err := sstore.GetScreenById(ctx, ids.SessionId, screenId)
|
||||
screen, err := sstore.GetScreenById(ctx, screenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/screen:archive cannot get updated screen obj: %v", err)
|
||||
}
|
||||
@ -512,17 +511,17 @@ func ScreenSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
|
||||
return nil, err
|
||||
}
|
||||
var varsUpdated []string
|
||||
var setNonAnchor bool // anchor does not receive an update
|
||||
updateMap := make(map[string]interface{})
|
||||
if pk.Kwargs["name"] != "" {
|
||||
newName := pk.Kwargs["name"]
|
||||
err = validateName(newName, "screen")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = sstore.SetScreenName(ctx, ids.SessionId, ids.ScreenId, newName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("setting screen name: %v", err)
|
||||
}
|
||||
updateMap[sstore.ScreenField_Name] = newName
|
||||
varsUpdated = append(varsUpdated, "name")
|
||||
setNonAnchor = true
|
||||
}
|
||||
if pk.Kwargs["tabcolor"] != "" {
|
||||
color := pk.Kwargs["tabcolor"]
|
||||
@ -530,39 +529,67 @@ func ScreenSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
screenObj, err := sstore.GetScreenById(ctx, ids.SessionId, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts := screenObj.ScreenOpts
|
||||
if opts == nil {
|
||||
opts = &sstore.ScreenOptsType{}
|
||||
}
|
||||
opts.TabColor = color
|
||||
err = sstore.SetScreenOpts(ctx, ids.SessionId, ids.ScreenId, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("setting screen opts: %v", err)
|
||||
}
|
||||
updateMap[sstore.ScreenField_TabColor] = color
|
||||
varsUpdated = append(varsUpdated, "tabcolor")
|
||||
setNonAnchor = true
|
||||
}
|
||||
if pk.Kwargs["pos"] != "" {
|
||||
|
||||
varsUpdated = append(varsUpdated, "pos")
|
||||
setNonAnchor = true
|
||||
}
|
||||
if pk.Kwargs["focus"] != "" {
|
||||
focusVal := pk.Kwargs["focus"]
|
||||
if focusVal != sstore.ScreenFocusInput && focusVal != sstore.ScreenFocusCmd && focusVal != sstore.ScreenFocusCmdFg {
|
||||
return nil, fmt.Errorf("/screen:set invalid focus argument %q, must be %s", focusVal, formatStrs([]string{sstore.ScreenFocusInput, sstore.ScreenFocusCmd, sstore.ScreenFocusCmdFg}, "or", false))
|
||||
}
|
||||
updateMap[sstore.ScreenField_Focus] = focusVal
|
||||
setNonAnchor = true
|
||||
}
|
||||
if pk.Kwargs["line"] != "" {
|
||||
screen, err := sstore.GetScreenById(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/screen:set cannot get screen: %v", err)
|
||||
}
|
||||
var selectedLineStr string
|
||||
if screen.SelectedLine > 0 {
|
||||
selectedLineStr = strconv.Itoa(int(screen.SelectedLine))
|
||||
}
|
||||
ritem, err := resolveLine(ctx, screen.SessionId, screen.WindowId, pk.Kwargs["line"], selectedLineStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/screen:set error resolving line: %v", err)
|
||||
}
|
||||
if ritem == nil {
|
||||
return nil, fmt.Errorf("/screen:set could not resolve line %q", pk.Kwargs["line"])
|
||||
}
|
||||
setNonAnchor = true
|
||||
updateMap[sstore.ScreenField_SelectedLine] = ritem.Num
|
||||
}
|
||||
if pk.Kwargs["anchor"] != "" {
|
||||
m := swAnchorRe.FindStringSubmatch(pk.Kwargs["anchor"])
|
||||
if m == nil {
|
||||
return nil, fmt.Errorf("/screen:set invalid anchor argument (must be [line] or [line]:[offset])")
|
||||
}
|
||||
anchorLine, _ := strconv.Atoi(m[1])
|
||||
updateMap[sstore.ScreenField_AnchorLine] = anchorLine
|
||||
if m[2] != "" {
|
||||
anchorOffset, _ := strconv.Atoi(m[2])
|
||||
updateMap[sstore.ScreenField_AnchorOffset] = anchorOffset
|
||||
} else {
|
||||
updateMap[sstore.ScreenField_AnchorOffset] = 0
|
||||
}
|
||||
}
|
||||
if len(varsUpdated) == 0 {
|
||||
return nil, fmt.Errorf("/screen:set no updates, can set %s", formatStrs([]string{"name", "pos", "tabcolor"}, "or", false))
|
||||
return nil, fmt.Errorf("/screen:set no updates, can set %s", formatStrs([]string{"name", "pos", "tabcolor", "focus", "anchor", "line"}, "or", false))
|
||||
}
|
||||
screenObj, err := sstore.GetScreenById(ctx, ids.SessionId, ids.ScreenId)
|
||||
screen, err := sstore.UpdateScreen(ctx, ids.ScreenId, updateMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("error updating screen: %v", err)
|
||||
}
|
||||
bareSession, err := sstore.GetBareSessionById(ctx, ids.SessionId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/screen:set cannot retrieve session: %v", err)
|
||||
if !setNonAnchor {
|
||||
return nil, nil
|
||||
}
|
||||
bareSession.Screens = append(bareSession.Screens, screenObj)
|
||||
update := sstore.ModelUpdate{
|
||||
Sessions: []*sstore.SessionType{bareSession},
|
||||
Screens: []*sstore.ScreenType{screen},
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoMsg: fmt.Sprintf("screen updated %s", formatStrs(varsUpdated, "and", false)),
|
||||
TimeoutMs: 2000,
|
||||
@ -593,69 +620,8 @@ func ScreenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstor
|
||||
|
||||
var swAnchorRe = regexp.MustCompile("^(\\d+)(?::(-?\\d+))?$")
|
||||
|
||||
func SwSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/sw:set cannot resolve current screen-window: %w", err)
|
||||
}
|
||||
var setNonST bool // scrolltop does not receive an update
|
||||
updateMap := make(map[string]interface{})
|
||||
if pk.Kwargs["anchor"] != "" {
|
||||
m := swAnchorRe.FindStringSubmatch(pk.Kwargs["anchor"])
|
||||
if m == nil {
|
||||
return nil, fmt.Errorf("/sw:set invalid anchor argument (must be [line] or [line]:[offset])")
|
||||
}
|
||||
anchorLine, _ := strconv.Atoi(m[1])
|
||||
updateMap[sstore.SWField_AnchorLine] = anchorLine
|
||||
if m[2] != "" {
|
||||
anchorOffset, _ := strconv.Atoi(m[2])
|
||||
updateMap[sstore.SWField_AnchorOffset] = anchorOffset
|
||||
} else {
|
||||
updateMap[sstore.SWField_AnchorOffset] = 0
|
||||
}
|
||||
}
|
||||
if pk.Kwargs["focus"] != "" {
|
||||
focusVal := pk.Kwargs["focus"]
|
||||
if focusVal != sstore.SWFocusInput && focusVal != sstore.SWFocusCmd && focusVal != sstore.SWFocusCmdFg {
|
||||
return nil, fmt.Errorf("/sw:set invalid focus argument %q, must be %s", focusVal, formatStrs([]string{sstore.SWFocusInput, sstore.SWFocusCmd, sstore.SWFocusCmdFg}, "or", false))
|
||||
}
|
||||
updateMap[sstore.SWField_Focus] = focusVal
|
||||
setNonST = true
|
||||
}
|
||||
if pk.Kwargs["line"] != "" {
|
||||
sw, err := sstore.GetScreenWindowByIds(ctx, ids.SessionId, ids.ScreenId, ids.WindowId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/sw:set cannot get screen-window: %v", err)
|
||||
}
|
||||
var selectedLineStr string
|
||||
if sw.SelectedLine > 0 {
|
||||
selectedLineStr = strconv.Itoa(sw.SelectedLine)
|
||||
}
|
||||
ritem, err := resolveLine(ctx, ids.SessionId, ids.WindowId, pk.Kwargs["line"], selectedLineStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/sw:set error resolving line: %v", err)
|
||||
}
|
||||
if ritem == nil {
|
||||
return nil, fmt.Errorf("/sw:set could not resolve line %q", pk.Kwargs["line"])
|
||||
}
|
||||
setNonST = true
|
||||
updateMap[sstore.SWField_SelectedLine] = ritem.Num
|
||||
}
|
||||
if len(updateMap) == 0 {
|
||||
return nil, fmt.Errorf("/sw:set no updates, can set %s", formatStrs([]string{"line", "scrolltop", "focus"}, "or", false))
|
||||
}
|
||||
sw, err := sstore.UpdateScreenWindow(ctx, ids.SessionId, ids.ScreenId, ids.WindowId, updateMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/sw:set failed to update: %v", err)
|
||||
}
|
||||
if !setNonST {
|
||||
return nil, nil
|
||||
}
|
||||
return sstore.ModelUpdate{ScreenWindows: []*sstore.ScreenWindowType{sw}}, nil
|
||||
}
|
||||
|
||||
func RemoteInstallCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -669,7 +635,7 @@ func RemoteInstallCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
}
|
||||
|
||||
func RemoteInstallCancelCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -683,7 +649,7 @@ func RemoteInstallCancelCommand(ctx context.Context, pk *scpacket.FeCommandPacke
|
||||
}
|
||||
|
||||
func RemoteConnectCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -696,7 +662,7 @@ func RemoteConnectCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
}
|
||||
|
||||
func RemoteDisconnectCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -946,7 +912,7 @@ func RemoteNewCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
|
||||
}
|
||||
|
||||
func RemoteSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -976,7 +942,7 @@ func RemoteSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
|
||||
}
|
||||
|
||||
func RemoteShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1039,29 +1005,20 @@ func ScreenResetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
screen, err := sstore.GetScreenById(ctx, ids.SessionId, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error retrieving screen: %v", err)
|
||||
}
|
||||
localRemote := remote.GetLocalRemote()
|
||||
if localRemote == nil {
|
||||
return nil, fmt.Errorf("error getting local remote (not found)")
|
||||
}
|
||||
rptr := sstore.RemotePtrType{RemoteId: localRemote.RemoteId}
|
||||
var windows []*sstore.WindowType
|
||||
sessionUpdate := &sstore.SessionType{SessionId: ids.SessionId}
|
||||
for _, sw := range screen.Windows {
|
||||
ris, err := sstore.WindowReset(ctx, ids.SessionId, sw.WindowId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error resetting screen window: %v", err)
|
||||
}
|
||||
sessionUpdate.Remotes = append(sessionUpdate.Remotes, ris...)
|
||||
err = sstore.UpdateCurRemote(ctx, ids.SessionId, sw.WindowId, rptr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot reset window remote back to local: %w", err)
|
||||
}
|
||||
winUpdate := &sstore.WindowType{SessionId: ids.SessionId, WindowId: sw.WindowId, CurRemote: rptr}
|
||||
windows = append(windows, winUpdate)
|
||||
ris, err := sstore.ScreenReset(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error resetting screen window: %v", err)
|
||||
}
|
||||
sessionUpdate.Remotes = append(sessionUpdate.Remotes, ris...)
|
||||
err = sstore.UpdateCurRemote(ctx, ids.ScreenId, rptr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot reset screen remote back to local: %w", err)
|
||||
}
|
||||
outputStr := "reset screen state (all remote state reset)"
|
||||
cmd, err := makeStaticCmd(ctx, "screen:reset", ids, pk.GetRawStr(), []byte(outputStr))
|
||||
@ -1075,13 +1032,12 @@ func ScreenResetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (
|
||||
return nil, err
|
||||
}
|
||||
update.Interactive = pk.Interactive
|
||||
update.Windows = windows
|
||||
update.Sessions = []*sstore.SessionType{sessionUpdate}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
func RemoteArchiveCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1091,13 +1047,16 @@ func RemoteArchiveCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
}
|
||||
update := sstore.InfoMsgUpdate("remote [%s] archived", ids.Remote.DisplayName)
|
||||
localRemote := remote.GetLocalRemote()
|
||||
if localRemote != nil {
|
||||
update.Windows = []*sstore.WindowType{&sstore.WindowType{
|
||||
SessionId: ids.SessionId,
|
||||
WindowId: ids.WindowId,
|
||||
CurRemote: sstore.RemotePtrType{RemoteId: localRemote.GetRemoteId()},
|
||||
}}
|
||||
rptr := sstore.RemotePtrType{RemoteId: localRemote.GetRemoteId()}
|
||||
err = sstore.UpdateCurRemote(ctx, ids.ScreenId, rptr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot switch remote back to local: %w", err)
|
||||
}
|
||||
screen, err := sstore.GetScreenById(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get updated screen: %w", err)
|
||||
}
|
||||
update.Screens = []*sstore.ScreenType{screen}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
@ -1173,7 +1132,7 @@ func GetFullRemoteDisplayName(rptr *sstore.RemotePtrType, rstate *remote.RemoteR
|
||||
}
|
||||
|
||||
func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/%s error: %w", GetCmdStr(pk), err)
|
||||
}
|
||||
@ -1191,7 +1150,7 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
|
||||
if rstate.Archived {
|
||||
return nil, fmt.Errorf("/%s error: remote %q cannot switch to archived remote", GetCmdStr(pk), newRemote)
|
||||
}
|
||||
err = sstore.UpdateCurRemote(ctx, ids.SessionId, ids.WindowId, *rptr)
|
||||
err = sstore.UpdateCurRemote(ctx, ids.ScreenId, *rptr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/%s error: cannot update curremote: %w", GetCmdStr(pk), err)
|
||||
}
|
||||
@ -1206,11 +1165,6 @@ func CrCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.Up
|
||||
// TODO tricky error since the command was a success, but we can't show the output
|
||||
return nil, err
|
||||
}
|
||||
update.Windows = []*sstore.WindowType{&sstore.WindowType{
|
||||
SessionId: ids.SessionId,
|
||||
WindowId: ids.WindowId,
|
||||
CurRemote: *rptr,
|
||||
}}
|
||||
update.Interactive = pk.Interactive
|
||||
return update, nil
|
||||
}
|
||||
@ -1252,27 +1206,27 @@ func addLineForCmd(ctx context.Context, metaCmd string, shouldFocus bool, ids re
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sw, err := sstore.GetScreenWindowByIds(ctx, ids.SessionId, ids.ScreenId, ids.WindowId)
|
||||
screen, err := sstore.GetScreenById(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
// ignore error here, because the command has already run (nothing to do)
|
||||
log.Printf("%s error getting screen-window: %v\n", metaCmd, err)
|
||||
log.Printf("%s error getting screen: %v\n", metaCmd, err)
|
||||
}
|
||||
if sw != nil {
|
||||
if screen != nil {
|
||||
updateMap := make(map[string]interface{})
|
||||
updateMap[sstore.SWField_SelectedLine] = rtnLine.LineNum
|
||||
updateMap[sstore.ScreenField_SelectedLine] = rtnLine.LineNum
|
||||
if shouldFocus {
|
||||
updateMap[sstore.SWField_Focus] = sstore.SWFocusCmdFg
|
||||
updateMap[sstore.ScreenField_Focus] = sstore.ScreenFocusCmdFg
|
||||
}
|
||||
sw, err = sstore.UpdateScreenWindow(ctx, ids.SessionId, ids.ScreenId, ids.WindowId, updateMap)
|
||||
screen, err = sstore.UpdateScreen(ctx, ids.ScreenId, updateMap)
|
||||
if err != nil {
|
||||
// ignore error again (nothing to do)
|
||||
log.Printf("%s error updating screen-window selected line: %v\n", metaCmd, err)
|
||||
log.Printf("%s error updating screen selected line: %v\n", metaCmd, err)
|
||||
}
|
||||
}
|
||||
update := &sstore.ModelUpdate{
|
||||
Line: rtnLine,
|
||||
Cmd: cmd,
|
||||
ScreenWindows: []*sstore.ScreenWindowType{sw},
|
||||
Line: rtnLine,
|
||||
Cmd: cmd,
|
||||
Screens: []*sstore.ScreenType{screen},
|
||||
}
|
||||
updateHistoryContext(ctx, rtnLine, cmd)
|
||||
return update, nil
|
||||
@ -1374,7 +1328,7 @@ func doCompGen(ctx context.Context, pk *scpacket.FeCommandPacketType, prefix str
|
||||
if !packet.IsValidCompGenType(compType) {
|
||||
return nil, false, fmt.Errorf("/_compgen invalid type '%s'", compType)
|
||||
}
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_RemoteConnected)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window|R_RemoteConnected)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("/_compgen error: %w", err)
|
||||
}
|
||||
@ -1447,7 +1401,7 @@ func CompGenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
|
||||
}
|
||||
|
||||
func CommentCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window)
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/comment error: %w", err)
|
||||
}
|
||||
@ -1461,14 +1415,14 @@ func CommentCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto
|
||||
}
|
||||
updateHistoryContext(ctx, rtnLine, nil)
|
||||
updateMap := make(map[string]interface{})
|
||||
updateMap[sstore.SWField_SelectedLine] = rtnLine.LineNum
|
||||
updateMap[sstore.SWField_Focus] = sstore.SWFocusInput
|
||||
sw, err := sstore.UpdateScreenWindow(ctx, ids.SessionId, ids.ScreenId, ids.WindowId, updateMap)
|
||||
updateMap[sstore.ScreenField_SelectedLine] = rtnLine.LineNum
|
||||
updateMap[sstore.ScreenField_Focus] = sstore.ScreenFocusInput
|
||||
screen, err := sstore.UpdateScreen(ctx, ids.ScreenId, updateMap)
|
||||
if err != nil {
|
||||
// ignore error again (nothing to do)
|
||||
log.Printf("/comment error updating screen-window selected line: %v\n", err)
|
||||
}
|
||||
update := sstore.ModelUpdate{Line: rtnLine, ScreenWindows: []*sstore.ScreenWindowType{sw}}
|
||||
update := sstore.ModelUpdate{Line: rtnLine, Screens: []*sstore.ScreenType{screen}}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
@ -1809,22 +1763,22 @@ func ClearCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore
|
||||
return nil, err
|
||||
}
|
||||
if resolveBool(pk.Kwargs["purge"], false) {
|
||||
update, err := sstore.PurgeWindowLines(ctx, ids.SessionId, ids.WindowId)
|
||||
update, err := sstore.PurgeScreenLines(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("clearing window: %v", err)
|
||||
return nil, fmt.Errorf("clearing screen: %v", err)
|
||||
}
|
||||
update.Info = &sstore.InfoMsgType{
|
||||
InfoMsg: fmt.Sprintf("window cleared (all lines purged)"),
|
||||
InfoMsg: fmt.Sprintf("screen cleared (all lines purged)"),
|
||||
TimeoutMs: 2000,
|
||||
}
|
||||
return update, nil
|
||||
} else {
|
||||
update, err := sstore.ArchiveWindowLines(ctx, ids.SessionId, ids.WindowId)
|
||||
update, err := sstore.ArchiveScreenLines(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("clearing window: %v", err)
|
||||
return nil, fmt.Errorf("clearing screen: %v", err)
|
||||
}
|
||||
update.Info = &sstore.InfoMsgType{
|
||||
InfoMsg: fmt.Sprintf("window cleared"),
|
||||
InfoMsg: fmt.Sprintf("screen cleared"),
|
||||
TimeoutMs: 2000,
|
||||
}
|
||||
return update, nil
|
||||
@ -2121,11 +2075,11 @@ func LineViewCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sst
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:view invalid screen arg: %v", err)
|
||||
}
|
||||
screen, err := sstore.GetScreenById(ctx, sessionId, screenRItem.Id)
|
||||
screen, err := sstore.GetScreenById(ctx, screenRItem.Id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:view could not get screen: %v", err)
|
||||
}
|
||||
lineRItem, err := resolveLine(ctx, sessionId, screen.ActiveWindowId, lineArg, "")
|
||||
lineRItem, err := resolveLine(ctx, sessionId, screen.WindowId, lineArg, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/line:view invalid line arg: %v", err)
|
||||
}
|
||||
@ -2134,14 +2088,14 @@ func LineViewCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sst
|
||||
return nil, err
|
||||
}
|
||||
updateMap := make(map[string]interface{})
|
||||
updateMap[sstore.SWField_SelectedLine] = lineRItem.Num
|
||||
updateMap[sstore.SWField_AnchorLine] = lineRItem.Num
|
||||
updateMap[sstore.SWField_AnchorOffset] = 0
|
||||
sw, err := sstore.UpdateScreenWindow(ctx, sessionId, screenRItem.Id, screen.ActiveWindowId, updateMap)
|
||||
updateMap[sstore.ScreenField_SelectedLine] = lineRItem.Num
|
||||
updateMap[sstore.ScreenField_AnchorLine] = lineRItem.Num
|
||||
updateMap[sstore.ScreenField_AnchorOffset] = 0
|
||||
screen, err = sstore.UpdateScreen(ctx, screenRItem.Id, updateMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update.ScreenWindows = []*sstore.ScreenWindowType{sw}
|
||||
update.Screens = []*sstore.ScreenType{screen}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
|
99
pkg/mapqueue/mapqueue.go
Normal file
99
pkg/mapqueue/mapqueue.go
Normal file
@ -0,0 +1,99 @@
|
||||
package mapqueue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type MQEntry struct {
|
||||
Lock *sync.Mutex
|
||||
Running bool
|
||||
Queue chan func()
|
||||
}
|
||||
|
||||
type MapQueue struct {
|
||||
Lock *sync.Mutex
|
||||
M map[string]*MQEntry
|
||||
QueueSize int
|
||||
}
|
||||
|
||||
func MakeMapQueue(queueSize int) *MapQueue {
|
||||
rtn := &MapQueue{
|
||||
Lock: &sync.Mutex{},
|
||||
M: make(map[string]*MQEntry),
|
||||
QueueSize: queueSize,
|
||||
}
|
||||
return rtn
|
||||
}
|
||||
|
||||
func (mq *MapQueue) getEntry(id string) *MQEntry {
|
||||
mq.Lock.Lock()
|
||||
defer mq.Lock.Unlock()
|
||||
entry := mq.M[id]
|
||||
if entry == nil {
|
||||
entry = &MQEntry{
|
||||
Lock: &sync.Mutex{},
|
||||
Running: false,
|
||||
Queue: make(chan func(), mq.QueueSize),
|
||||
}
|
||||
mq.M[id] = entry
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
func (entry *MQEntry) add(fn func()) error {
|
||||
select {
|
||||
case entry.Queue <- fn:
|
||||
break
|
||||
default:
|
||||
return fmt.Errorf("input queue full")
|
||||
}
|
||||
entry.tryRun()
|
||||
return nil
|
||||
}
|
||||
|
||||
func runFn(fn func()) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
log.Printf("[error] panic in MQEntry runFn: %v\n", r)
|
||||
debug.PrintStack()
|
||||
return
|
||||
}()
|
||||
fn()
|
||||
}
|
||||
|
||||
func (entry *MQEntry) tryRun() {
|
||||
entry.Lock.Lock()
|
||||
defer entry.Lock.Unlock()
|
||||
if entry.Running {
|
||||
return
|
||||
}
|
||||
if len(entry.Queue) > 0 {
|
||||
entry.Running = true
|
||||
go entry.run()
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *MQEntry) run() {
|
||||
for fn := range entry.Queue {
|
||||
runFn(fn)
|
||||
}
|
||||
entry.Lock.Lock()
|
||||
entry.Running = false
|
||||
entry.Lock.Unlock()
|
||||
entry.tryRun()
|
||||
}
|
||||
|
||||
func (mq *MapQueue) Enqueue(id string, fn func()) error {
|
||||
entry := mq.getEntry(id)
|
||||
err := entry.add(fn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot enqueue: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1499,12 +1499,12 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
msh.WriteToPtyBuffer("*error updating cmddone: %v\n", err)
|
||||
return
|
||||
}
|
||||
sws, err := sstore.UpdateSWsWithCmdFg(context.Background(), donePk.CK.GetSessionId(), donePk.CK.GetCmdId())
|
||||
screens, err := sstore.UpdateScreensWithCmdFg(context.Background(), donePk.CK.GetSessionId(), donePk.CK.GetCmdId())
|
||||
if err != nil {
|
||||
msh.WriteToPtyBuffer("*error trying to update cmd-fg screen windows: %v\n", err)
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
update.ScreenWindows = sws
|
||||
update.Screens = screens
|
||||
rct := msh.GetRunningCmd(donePk.CK)
|
||||
var statePtr *sstore.ShellStatePtr
|
||||
if donePk.FinalState != nil && rct != nil {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/scripthaus-dev/mshell/pkg/packet"
|
||||
"github.com/scripthaus-dev/sh2-server/pkg/mapqueue"
|
||||
"github.com/scripthaus-dev/sh2-server/pkg/remote"
|
||||
"github.com/scripthaus-dev/sh2-server/pkg/scpacket"
|
||||
"github.com/scripthaus-dev/sh2-server/pkg/sstore"
|
||||
@ -17,6 +18,13 @@ import (
|
||||
|
||||
const WSStatePacketChSize = 20
|
||||
const MaxInputDataSize = 1000
|
||||
const RemoteInputQueueSize = 100
|
||||
|
||||
var RemoteInputMapQueue *mapqueue.MapQueue
|
||||
|
||||
func init() {
|
||||
RemoteInputMapQueue = mapqueue.MakeMapQueue(RemoteInputQueueSize)
|
||||
}
|
||||
|
||||
type WSState struct {
|
||||
Lock *sync.Mutex
|
||||
@ -227,13 +235,16 @@ func (ws *WSState) RunWSRead() {
|
||||
log.Printf("[error] invalid input packet, remoteid is not set\n")
|
||||
continue
|
||||
}
|
||||
go func() {
|
||||
// TODO enforce a strong ordering (channel with list)
|
||||
err := RemoteInputMapQueue.Enqueue(feInputPk.Remote.RemoteId, func() {
|
||||
err = sendCmdInput(feInputPk)
|
||||
if err != nil {
|
||||
log.Printf("[error] sending command input: %v\n", err)
|
||||
}
|
||||
}()
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("[error] could not queue sendCmdInput: %v\n", err)
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
if pk.GetType() == scpacket.RemoteInputPacketStr {
|
||||
|
@ -405,9 +405,8 @@ func GetAllSessions(ctx context.Context) (*ModelUpdate, error) {
|
||||
sessionMap[session.SessionId] = session
|
||||
session.Full = true
|
||||
}
|
||||
var screens []*ScreenType
|
||||
query = `SELECT * FROM screen ORDER BY archived, screenidx, archivedts`
|
||||
tx.Select(&screens, query)
|
||||
screens := SelectMapsGen[*ScreenType](tx, query)
|
||||
screenMap := make(map[string][]*ScreenType)
|
||||
for _, screen := range screens {
|
||||
screenArr := screenMap[screen.SessionId]
|
||||
@ -417,20 +416,6 @@ func GetAllSessions(ctx context.Context) (*ModelUpdate, error) {
|
||||
for _, session := range rtn {
|
||||
session.Screens = screenMap[session.SessionId]
|
||||
}
|
||||
var sws []*ScreenWindowType
|
||||
query = `SELECT * FROM screen_window`
|
||||
tx.Select(&sws, query)
|
||||
screenIdMap := make(map[string]*ScreenType)
|
||||
for _, screen := range screens {
|
||||
screenIdMap[screen.SessionId+screen.ScreenId] = screen
|
||||
}
|
||||
for _, sw := range sws {
|
||||
screen := screenIdMap[sw.SessionId+sw.ScreenId]
|
||||
if screen == nil {
|
||||
continue
|
||||
}
|
||||
screen.Windows = append(screen.Windows, sw)
|
||||
}
|
||||
query = `SELECT * FROM remote_instance`
|
||||
riArr := SelectMapsGen[*RemoteInstance](tx, query)
|
||||
for _, ri := range riArr {
|
||||
@ -449,22 +434,20 @@ func GetAllSessions(ctx context.Context) (*ModelUpdate, error) {
|
||||
return &ModelUpdate{Sessions: rtn, ActiveSessionId: activeSessionId}, nil
|
||||
}
|
||||
|
||||
func GetWindowById(ctx context.Context, sessionId string, windowId string) (*WindowType, error) {
|
||||
var rtnWindow *WindowType
|
||||
err := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT * FROM window WHERE sessionid = ? AND windowid = ?`
|
||||
m := tx.GetMap(query, sessionId, windowId)
|
||||
if m == nil {
|
||||
return nil
|
||||
func GetFullScreenById(ctx context.Context, screenId string) (*ScreenType, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) (*ScreenType, error) {
|
||||
query := `SELECT * FROM screen WHERE screenid = ?`
|
||||
screen := GetMapGen[*ScreenType](tx, query, screenId)
|
||||
if screen == nil {
|
||||
return nil, nil
|
||||
}
|
||||
rtnWindow = FromMap[*WindowType](m)
|
||||
query = `SELECT * FROM line WHERE sessionid = ? AND windowid = ? ORDER BY linenum`
|
||||
tx.Select(&rtnWindow.Lines, query, sessionId, windowId)
|
||||
tx.Select(&screen.Lines, query, screen.SessionId, screen.WindowId)
|
||||
query = `SELECT * FROM cmd WHERE cmdid IN (SELECT cmdid FROM line WHERE sessionid = ? AND windowid = ?)`
|
||||
rtnWindow.Cmds = SelectMapsGen[*CmdType](tx, query, sessionId, windowId)
|
||||
return nil
|
||||
screen.Cmds = SelectMapsGen[*CmdType](tx, query, screen.SessionId, screen.WindowId)
|
||||
screen.Full = true
|
||||
return screen, nil
|
||||
})
|
||||
return rtnWindow, err
|
||||
}
|
||||
|
||||
// includes archived screens (does not include screen windows)
|
||||
@ -649,11 +632,11 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string,
|
||||
if !tx.Exists(query, sessionId) {
|
||||
return fmt.Errorf("cannot create screen, no session found (or session archived)")
|
||||
}
|
||||
remoteId := tx.GetString(`SELECT remoteid FROM remote WHERE remotealias = ?`, LocalRemoteAlias)
|
||||
if remoteId == "" {
|
||||
localRemoteId := tx.GetString(`SELECT remoteid FROM remote WHERE remotealias = ?`, LocalRemoteAlias)
|
||||
if localRemoteId == "" {
|
||||
return fmt.Errorf("cannot create screen, no local remote found")
|
||||
}
|
||||
newWindowId := txCreateWindow(tx, sessionId, RemotePtrType{RemoteId: remoteId})
|
||||
newWindowId := scbase.GenPromptUUID()
|
||||
maxScreenIdx := tx.GetInt(`SELECT COALESCE(max(screenidx), 0) FROM screen WHERE sessionid = ? AND NOT archived`, sessionId)
|
||||
var screenName string
|
||||
if origScreenName == "" {
|
||||
@ -663,11 +646,25 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string,
|
||||
screenName = origScreenName
|
||||
}
|
||||
newScreenId = scbase.GenPromptUUID()
|
||||
query = `INSERT INTO screen (sessionid, screenid, name, activewindowid, screenidx, screenopts, ownerid, sharemode, incognito, archived, archivedts) VALUES (?, ?, ?, ?, ?, ?, '', 'local', 0, 0, 0)`
|
||||
tx.Exec(query, sessionId, newScreenId, screenName, newWindowId, maxScreenIdx+1, ScreenOptsType{})
|
||||
layout := LayoutType{Type: LayoutFull}
|
||||
query = `INSERT INTO screen_window (sessionid, screenid, windowid, name, layout, selectedline, anchor, focustype) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
tx.Exec(query, sessionId, newScreenId, newWindowId, DefaultScreenWindowName, layout, 0, SWAnchorType{}, "input")
|
||||
screen := &ScreenType{
|
||||
SessionId: sessionId,
|
||||
ScreenId: newScreenId,
|
||||
WindowId: newWindowId,
|
||||
Name: screenName,
|
||||
ScreenIdx: int64(maxScreenIdx) + 1,
|
||||
ScreenOpts: ScreenOptsType{},
|
||||
OwnerId: "",
|
||||
ShareMode: ShareModeLocal,
|
||||
CurRemote: RemotePtrType{RemoteId: localRemoteId},
|
||||
NextLineNum: 1,
|
||||
SelectedLine: 0,
|
||||
Anchor: ScreenAnchorType{},
|
||||
FocusType: ScreenFocusInput,
|
||||
Archived: false,
|
||||
ArchivedTs: 0,
|
||||
}
|
||||
query = `INSERT INTO screen (sessionid, screenid, windowid, name, screenidx, screenopts, ownerid, sharemode, curremoteownerid, curremoteid, curremotename, nextlinenum, selectedline, anchor, focustype, archived, archivedts) VALUES (:sessionid,:screenid,:windowid,:name,:screenidx,:screenopts,:ownerid,:sharemode,:curremoteownerid,:curremoteid,:curremotename,:nextlinenum,:selectedline,:anchor,:focustype,:archived,:archivedts)`
|
||||
tx.NamedExec(query, screen.ToMap())
|
||||
if activate {
|
||||
query = `UPDATE session SET activescreenid = ? WHERE sessionid = ?`
|
||||
tx.Exec(query, newScreenId, sessionId)
|
||||
@ -677,7 +674,7 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string,
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
newScreen, err := GetScreenById(ctx, sessionId, newScreenId)
|
||||
newScreen, err := GetScreenById(ctx, newScreenId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -689,42 +686,12 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string,
|
||||
return ModelUpdate{Sessions: []*SessionType{bareSession}}, nil
|
||||
}
|
||||
|
||||
func GetScreenById(ctx context.Context, sessionId string, screenId string) (*ScreenType, error) {
|
||||
var rtnScreen *ScreenType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT * FROM screen WHERE sessionid = ? AND screenid = ?`
|
||||
var screen ScreenType
|
||||
found := tx.Get(&screen, query, sessionId, screenId)
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
rtnScreen = &screen
|
||||
query = `SELECT * FROM screen_window WHERE sessionid = ? AND screenid = ?`
|
||||
tx.Select(&screen.Windows, query, sessionId, screenId)
|
||||
screen.Full = true
|
||||
return nil
|
||||
func GetScreenById(ctx context.Context, screenId string) (*ScreenType, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) (*ScreenType, error) {
|
||||
query := `SELECT * FROM screen WHERE screenid = ?`
|
||||
screen := GetMapGen[*ScreenType](tx, query, screenId)
|
||||
return screen, nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
return rtnScreen, nil
|
||||
}
|
||||
|
||||
func txCreateWindow(tx *TxWrap, sessionId string, curRemote RemotePtrType) string {
|
||||
w := &WindowType{
|
||||
SessionId: sessionId,
|
||||
WindowId: scbase.GenPromptUUID(),
|
||||
CurRemote: curRemote,
|
||||
NextLineNum: 1,
|
||||
WinOpts: WindowOptsType{},
|
||||
ShareMode: ShareModeLocal,
|
||||
ShareOpts: WindowShareOptsType{},
|
||||
}
|
||||
wmap := w.ToMap()
|
||||
query := `INSERT INTO window ( sessionid, windowid, curremoteownerid, curremoteid, curremotename, nextlinenum, winopts, ownerid, sharemode, shareopts)
|
||||
VALUES (:sessionid,:windowid,:curremoteownerid,:curremoteid,:curremotename,:nextlinenum,:winopts,:ownerid,:sharemode,:shareopts)`
|
||||
tx.NamedExec(query, wmap)
|
||||
return w.WindowId
|
||||
}
|
||||
|
||||
func FindLineIdByArg(ctx context.Context, sessionId string, windowId string, lineArg string) (string, error) {
|
||||
@ -1071,7 +1038,7 @@ func ArchiveScreen(ctx context.Context, sessionId string, screenId string) (Upda
|
||||
return nil, txErr
|
||||
}
|
||||
update := ModelUpdate{Sessions: []*SessionType{bareSession}}
|
||||
newScreen, _ := GetScreenById(ctx, sessionId, screenId)
|
||||
newScreen, _ := GetScreenById(ctx, screenId)
|
||||
if newScreen != nil {
|
||||
bareSession.Screens = append(bareSession.Screens, newScreen)
|
||||
}
|
||||
@ -1264,17 +1231,16 @@ func UpdateRemoteState(ctx context.Context, sessionId string, windowId string, r
|
||||
return ri, txErr
|
||||
}
|
||||
|
||||
func UpdateCurRemote(ctx context.Context, sessionId string, windowId string, remotePtr RemotePtrType) error {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT windowid FROM window WHERE sessionid = ? AND windowid = ?`
|
||||
if !tx.Exists(query, sessionId, windowId) {
|
||||
return fmt.Errorf("cannot update curremote: no window found")
|
||||
func UpdateCurRemote(ctx context.Context, screenId string, remotePtr RemotePtrType) error {
|
||||
return WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT screenid FROM screen WHERE screenid = ?`
|
||||
if !tx.Exists(query, screenId) {
|
||||
return fmt.Errorf("cannot update curremote: no screen found")
|
||||
}
|
||||
query = `UPDATE window SET curremoteownerid = ?, curremoteid = ?, curremotename = ? WHERE sessionid = ? AND windowid = ?`
|
||||
tx.Exec(query, remotePtr.OwnerId, remotePtr.RemoteId, remotePtr.Name, sessionId, windowId)
|
||||
query = `UPDATE screen SET curremoteownerid = ?, curremoteid = ?, curremotename = ? WHERE screenid = ?`
|
||||
tx.Exec(query, remotePtr.OwnerId, remotePtr.RemoteId, remotePtr.Name, screenId)
|
||||
return nil
|
||||
})
|
||||
return txErr
|
||||
}
|
||||
|
||||
func reorderStrings(strs []string, toMove string, newIndex int) []string {
|
||||
@ -1353,77 +1319,65 @@ func SetScreenName(ctx context.Context, sessionId string, screenId string, name
|
||||
return txErr
|
||||
}
|
||||
|
||||
func SetScreenOpts(ctx context.Context, sessionId string, screenId string, opts *ScreenOptsType) error {
|
||||
if opts == nil {
|
||||
return fmt.Errorf("invalid screen opts cannot be nil")
|
||||
}
|
||||
func ArchiveScreenLines(ctx context.Context, screenId string) (*ModelUpdate, error) {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT screenid FROM screen WHERE sessionid = ? AND screenid = ?`
|
||||
if !tx.Exists(query, sessionId, screenId) {
|
||||
return fmt.Errorf("screen does not exist")
|
||||
}
|
||||
query = `UPDATE screen SET screenopts = ? WHERE sessionid = ? AND screenid = ?`
|
||||
tx.Exec(query, opts, sessionId, screenId)
|
||||
return nil
|
||||
})
|
||||
return txErr
|
||||
}
|
||||
|
||||
func ArchiveWindowLines(ctx context.Context, sessionId string, windowId string) (*ModelUpdate, error) {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT windowid FROM window WHERE sessionid = ? AND windowid = ?`
|
||||
if !tx.Exists(query, sessionId, windowId) {
|
||||
return fmt.Errorf("window does not exist")
|
||||
query := `SELECT sessionid, windowid FROM screen WHERE screenid = ?`
|
||||
var swkeys SWKeys
|
||||
tx.Get(&swkeys, query, screenId)
|
||||
if swkeys.SessionId == "" || swkeys.WindowId == "" {
|
||||
return fmt.Errorf("screen windowid does not exist")
|
||||
}
|
||||
query = `UPDATE line SET archived = 1 WHERE sessionid = ? AND windowid = ?`
|
||||
tx.Exec(query, sessionId, windowId)
|
||||
tx.Exec(query, swkeys.SessionId, swkeys.WindowId)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
win, err := GetWindowById(ctx, sessionId, windowId)
|
||||
screen, err := GetFullScreenById(ctx, screenId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ModelUpdate{Windows: []*WindowType{win}}, nil
|
||||
return &ModelUpdate{Screens: []*ScreenType{screen}}, nil
|
||||
}
|
||||
|
||||
func PurgeWindowLines(ctx context.Context, sessionId string, windowId string) (*ModelUpdate, error) {
|
||||
func PurgeScreenLines(ctx context.Context, screenId string) (*ModelUpdate, error) {
|
||||
var lineIds []string
|
||||
var swkeys SWKeys
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT windowid FROM window WHERE sessionid = ? AND windowid = ?`
|
||||
if !tx.Exists(query, sessionId, windowId) {
|
||||
return fmt.Errorf("window does not exist")
|
||||
query := `SELECT sessionid, windowid FROM screen WHERE screenid = ?`
|
||||
tx.Get(&swkeys, query, screenId)
|
||||
if swkeys.SessionId == "" || swkeys.WindowId == "" {
|
||||
return fmt.Errorf("screen windowid does not exist")
|
||||
}
|
||||
query = `SELECT lineid FROM line WHERE sessionid = ? AND windowid = ?`
|
||||
lineIds = tx.SelectStrings(query, sessionId, windowId)
|
||||
lineIds = tx.SelectStrings(query, swkeys.SessionId, swkeys.WindowId)
|
||||
query = `DELETE FROM line WHERE sessionid = ? AND windowid = ?`
|
||||
tx.Exec(query, sessionId, windowId)
|
||||
tx.Exec(query, swkeys.SessionId, swkeys.WindowId)
|
||||
query = `DELETE FROM history WHERE sessionid = ? AND windowid = ?`
|
||||
tx.Exec(query, sessionId, windowId)
|
||||
query = `UPDATE window SET nextlinenum = 1 WHERE sessionid = ? AND windowid = ?`
|
||||
tx.Exec(query, sessionId, windowId)
|
||||
tx.Exec(query, swkeys.SessionId, swkeys.WindowId)
|
||||
query = `UPDATE screen SET nextlinenum = 1 WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
go cleanSessionCmds(context.Background(), sessionId)
|
||||
win, err := GetWindowById(ctx, sessionId, windowId)
|
||||
go cleanSessionCmds(context.Background(), swkeys.SessionId)
|
||||
screen, err := GetFullScreenById(ctx, screenId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, lineId := range lineIds {
|
||||
line := &LineType{
|
||||
SessionId: sessionId,
|
||||
WindowId: windowId,
|
||||
SessionId: swkeys.SessionId,
|
||||
WindowId: swkeys.WindowId,
|
||||
LineId: lineId,
|
||||
Remove: true,
|
||||
}
|
||||
win.Lines = append(win.Lines, line)
|
||||
screen.Lines = append(screen.Lines, line)
|
||||
}
|
||||
return &ModelUpdate{Windows: []*WindowType{win}}, nil
|
||||
return &ModelUpdate{Screens: []*ScreenType{screen}}, nil
|
||||
}
|
||||
|
||||
func GetRunningWindowCmds(ctx context.Context, sessionId string, windowId string) ([]*CmdType, error) {
|
||||
@ -1449,24 +1403,25 @@ func UpdateCmdTermOpts(ctx context.Context, sessionId string, cmdId string, term
|
||||
}
|
||||
|
||||
// returns riids of deleted RIs
|
||||
func WindowReset(ctx context.Context, sessionId string, windowId string) ([]*RemoteInstance, error) {
|
||||
var delRis []*RemoteInstance
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT windowid FROM window WHERE sessionid = ? AND windowid = ?`
|
||||
if !tx.Exists(query, sessionId, windowId) {
|
||||
return fmt.Errorf("window does not exist")
|
||||
func ScreenReset(ctx context.Context, screenId string) ([]*RemoteInstance, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) ([]*RemoteInstance, error) {
|
||||
var swkeys SWKeys
|
||||
query := `SELECT sessionid, windowid FROM screen WHERE screenid = ?`
|
||||
tx.Get(&swkeys, query, screenId)
|
||||
if swkeys.SessionId == "" || swkeys.WindowId == "" {
|
||||
return nil, fmt.Errorf("screen does not exist")
|
||||
}
|
||||
query = `SELECT riid FROM remote_instance WHERE sessionid = ? AND windowid = ?`
|
||||
riids := tx.SelectStrings(query, sessionId, windowId)
|
||||
riids := tx.SelectStrings(query, swkeys.SessionId, swkeys.WindowId)
|
||||
var delRis []*RemoteInstance
|
||||
for _, riid := range riids {
|
||||
ri := &RemoteInstance{SessionId: sessionId, WindowId: windowId, RIId: riid, Remove: true}
|
||||
ri := &RemoteInstance{SessionId: swkeys.SessionId, WindowId: swkeys.WindowId, RIId: riid, Remove: true}
|
||||
delRis = append(delRis, ri)
|
||||
}
|
||||
query = `DELETE FROM remote_instance WHERE sessionid = ? AND windowid = ?`
|
||||
tx.Exec(query, sessionId, windowId)
|
||||
return nil
|
||||
tx.Exec(query, swkeys.SessionId, swkeys.WindowId)
|
||||
return delRis, nil
|
||||
})
|
||||
return delRis, txErr
|
||||
}
|
||||
|
||||
func DeleteSession(ctx context.Context, sessionId string) (UpdatePacket, error) {
|
||||
@ -1480,10 +1435,6 @@ func DeleteSession(ctx context.Context, sessionId string) (UpdatePacket, error)
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM screen WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM screen_window WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM window WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM history WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
query = `DELETE FROM line WHERE sessionid = ?`
|
||||
@ -1693,64 +1644,55 @@ func UpdateRemote(ctx context.Context, remoteId string, editMap map[string]inter
|
||||
}
|
||||
|
||||
const (
|
||||
SWField_AnchorLine = "anchorline" // int
|
||||
SWField_AnchorOffset = "anchoroffset" // int
|
||||
SWField_SelectedLine = "selectedline" // int
|
||||
SWField_Focus = "focustype" // string
|
||||
ScreenField_AnchorLine = "anchorline" // int
|
||||
ScreenField_AnchorOffset = "anchoroffset" // int
|
||||
ScreenField_SelectedLine = "selectedline" // int
|
||||
ScreenField_Focus = "focustype" // string
|
||||
ScreenField_TabColor = "tabcolor" // string
|
||||
ScreenField_PTerm = "pterm" // string
|
||||
ScreenField_Name = "name" // string
|
||||
)
|
||||
|
||||
func UpdateScreenWindow(ctx context.Context, sessionId string, screenId string, windowId string, editMap map[string]interface{}) (*ScreenWindowType, error) {
|
||||
var rtn *ScreenWindowType
|
||||
func UpdateScreen(ctx context.Context, screenId string, editMap map[string]interface{}) (*ScreenType, error) {
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT sessionid FROM screen_window WHERE sessionid = ? AND screenid = ? AND windowid = ?`
|
||||
if !tx.Exists(query, sessionId, screenId, windowId) {
|
||||
return fmt.Errorf("screen-window not found")
|
||||
query := `SELECT screenid FROM screen WHERE screenid = ?`
|
||||
if !tx.Exists(query, screenId) {
|
||||
return fmt.Errorf("screen not found")
|
||||
}
|
||||
if anchorLine, found := editMap[SWField_AnchorLine]; found {
|
||||
query = `UPDATE screen_window SET anchor = json_set(anchor, '$.anchorline', ?) WHERE sessionid = ? AND screenid = ? AND windowid = ?`
|
||||
tx.Exec(query, anchorLine, sessionId, screenId, windowId)
|
||||
if anchorLine, found := editMap[ScreenField_AnchorLine]; found {
|
||||
query = `UPDATE screen SET anchor = json_set(anchor, '$.anchorline', ?) WHERE screenid = ?`
|
||||
tx.Exec(query, anchorLine, screenId)
|
||||
}
|
||||
if anchorOffset, found := editMap[SWField_AnchorOffset]; found {
|
||||
query = `UPDATE screen_window SET anchor = json_set(anchor, '$.anchoroffset', ?) WHERE sessionid = ? AND screenid = ? AND windowid = ?`
|
||||
tx.Exec(query, anchorOffset, sessionId, screenId, windowId)
|
||||
if anchorOffset, found := editMap[ScreenField_AnchorOffset]; found {
|
||||
query = `UPDATE screen SET anchor = json_set(anchor, '$.anchoroffset', ?) WHERE screenid = ?`
|
||||
tx.Exec(query, anchorOffset, screenId)
|
||||
}
|
||||
if sline, found := editMap[SWField_SelectedLine]; found {
|
||||
query = `UPDATE screen_window SET selectedline = ? WHERE sessionid = ? AND screenid = ? AND windowid = ?`
|
||||
tx.Exec(query, sline, sessionId, screenId, windowId)
|
||||
if sline, found := editMap[ScreenField_SelectedLine]; found {
|
||||
query = `UPDATE screen SET selectedline = ? WHERE screenid = ?`
|
||||
tx.Exec(query, sline, screenId)
|
||||
}
|
||||
if focusType, found := editMap[SWField_Focus]; found {
|
||||
query = `UPDATE screen_window SET focustype = ? WHERE sessionid = ? AND screenid = ? AND windowid = ?`
|
||||
tx.Exec(query, focusType, sessionId, screenId, windowId)
|
||||
if focusType, found := editMap[ScreenField_Focus]; found {
|
||||
query = `UPDATE screen SET focustype = ? WHERE screenid = ?`
|
||||
tx.Exec(query, focusType, screenId)
|
||||
}
|
||||
var sw ScreenWindowType
|
||||
query = `SELECT * FROM screen_window WHERE sessionid = ? AND screenid = ? AND windowid = ?`
|
||||
found := tx.Get(&sw, query, sessionId, screenId, windowId)
|
||||
if found {
|
||||
rtn = &sw
|
||||
if tabColor, found := editMap[ScreenField_TabColor]; found {
|
||||
query = `UPDATE screen SET screenopts = json_set(screenopts, '$.tabcolor', ?) WHERE screenid = ?`
|
||||
tx.Exec(query, tabColor, screenId)
|
||||
}
|
||||
if pterm, found := editMap[ScreenField_PTerm]; found {
|
||||
query = `UPDATE screen SET screenopts = json_set(screenopts, '$.pterm', ?) WHERE screenid = ?`
|
||||
tx.Exec(query, pterm, screenId)
|
||||
}
|
||||
if name, found := editMap[ScreenField_Name]; found {
|
||||
query = `UPDATE screen SET name = ? WHERE screenid = ?`
|
||||
tx.Exec(query, name, screenId)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
return rtn, nil
|
||||
}
|
||||
|
||||
func GetScreenWindowByIds(ctx context.Context, sessionId string, screenId string, windowId string) (*ScreenWindowType, error) {
|
||||
var rtn *ScreenWindowType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
var sw ScreenWindowType
|
||||
query := `SELECT * FROM screen_window WHERE sessionid = ? AND screenid = ? AND windowid = ?`
|
||||
found := tx.Get(&sw, query, sessionId, screenId, windowId)
|
||||
if found {
|
||||
rtn = &sw
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
return rtn, nil
|
||||
return GetScreenById(ctx, screenId)
|
||||
}
|
||||
|
||||
func GetLineResolveItems(ctx context.Context, sessionId string, windowId string) ([]ResolveItem, error) {
|
||||
@ -1766,33 +1708,32 @@ func GetLineResolveItems(ctx context.Context, sessionId string, windowId string)
|
||||
return rtn, nil
|
||||
}
|
||||
|
||||
func UpdateSWsWithCmdFg(ctx context.Context, sessionId string, cmdId string) ([]*ScreenWindowType, error) {
|
||||
var rtn []*ScreenWindowType
|
||||
func UpdateScreensWithCmdFg(ctx context.Context, sessionId string, cmdId string) ([]*ScreenType, error) {
|
||||
var rtn []*ScreenType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT sessionid, screenid, windowid
|
||||
FROM screen_window sw
|
||||
WHERE
|
||||
sessionid = ?
|
||||
AND focustype = 'cmd-fg'
|
||||
AND selectedline IN (SELECT linenum
|
||||
FROM line l
|
||||
WHERE l.sessionid = sw.sessionid
|
||||
AND l.windowid = sw.windowid
|
||||
AND l.cmdid = ?
|
||||
)`
|
||||
var swKeys []SWKey
|
||||
tx.Select(&swKeys, query, sessionId, cmdId)
|
||||
if len(swKeys) == 0 {
|
||||
query := `SELECT screenid
|
||||
FROM screen s
|
||||
WHERE
|
||||
s.sessionid = ?
|
||||
AND s.focustype = 'cmd-fg'
|
||||
AND s.selectedline IN (SELECT linenum
|
||||
FROM line l
|
||||
WHERE l.sessionid = s.sessionid
|
||||
AND l.windowid = s.windowid
|
||||
AND l.cmdid = ?
|
||||
)`
|
||||
screenIds := tx.SelectStrings(query, sessionId, cmdId)
|
||||
if len(screenIds) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, key := range swKeys {
|
||||
for _, screenId := range screenIds {
|
||||
editMap := make(map[string]interface{})
|
||||
editMap[SWField_Focus] = SWFocusInput
|
||||
sw, err := UpdateScreenWindow(tx.Context(), key.SessionId, key.ScreenId, key.WindowId, editMap)
|
||||
editMap[ScreenField_Focus] = ScreenFocusInput
|
||||
screen, err := UpdateScreen(tx.Context(), screenId, editMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rtn = append(rtn, sw)
|
||||
rtn = append(rtn, screen)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
)
|
||||
|
||||
const MaxMigration = 8
|
||||
const MaxMigration = 9
|
||||
const MigratePrimaryScreenVersion = 9
|
||||
|
||||
func MakeMigrate() (*migrate.Migrate, error) {
|
||||
|
@ -73,9 +73,9 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
SWFocusInput = "input"
|
||||
SWFocusCmd = "cmd"
|
||||
SWFocusCmdFg = "cmd-fg"
|
||||
ScreenFocusInput = "input"
|
||||
ScreenFocusCmd = "cmd"
|
||||
ScreenFocusCmdFg = "cmd-fg"
|
||||
)
|
||||
|
||||
const MaxTzNameLen = 50
|
||||
@ -276,29 +276,6 @@ type SessionStatsType struct {
|
||||
DiskStats SessionDiskSizeType `json:"diskstats"`
|
||||
}
|
||||
|
||||
type WindowOptsType struct {
|
||||
PTerm string `json:"pterm,omitempty"`
|
||||
}
|
||||
|
||||
func (opts *WindowOptsType) Scan(val interface{}) error {
|
||||
return quickScanJson(opts, val)
|
||||
}
|
||||
|
||||
func (opts WindowOptsType) Value() (driver.Value, error) {
|
||||
return quickValueJson(opts)
|
||||
}
|
||||
|
||||
type WindowShareOptsType struct {
|
||||
}
|
||||
|
||||
func (opts *WindowShareOptsType) Scan(val interface{}) error {
|
||||
return quickScanJson(opts, val)
|
||||
}
|
||||
|
||||
func (opts WindowShareOptsType) Value() (driver.Value, error) {
|
||||
return quickValueJson(opts)
|
||||
}
|
||||
|
||||
var RemoteNameRe = regexp.MustCompile("^\\*?[a-zA-Z0-9_-]+$")
|
||||
|
||||
type RemotePtrType struct {
|
||||
@ -361,51 +338,6 @@ func (r RemotePtrType) MakeFullRemoteRef() string {
|
||||
return fmt.Sprintf("@%s:%s:%s", r.OwnerId, r.RemoteId, r.Name)
|
||||
}
|
||||
|
||||
type WindowType struct {
|
||||
SessionId string `json:"sessionid"`
|
||||
WindowId string `json:"windowid"`
|
||||
CurRemote RemotePtrType `json:"curremote"`
|
||||
WinOpts WindowOptsType `json:"winopts"`
|
||||
OwnerId string `json:"ownerid"`
|
||||
NextLineNum int64 `json:"nextlinenum"`
|
||||
ShareMode string `json:"sharemode"`
|
||||
ShareOpts WindowShareOptsType `json:"shareopts"`
|
||||
Lines []*LineType `json:"lines"`
|
||||
Cmds []*CmdType `json:"cmds"`
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
func (w *WindowType) ToMap() map[string]interface{} {
|
||||
rtn := make(map[string]interface{})
|
||||
rtn["sessionid"] = w.SessionId
|
||||
rtn["windowid"] = w.WindowId
|
||||
rtn["curremoteownerid"] = w.CurRemote.OwnerId
|
||||
rtn["curremoteid"] = w.CurRemote.RemoteId
|
||||
rtn["curremotename"] = w.CurRemote.Name
|
||||
rtn["nextlinenum"] = w.NextLineNum
|
||||
rtn["winopts"] = quickJson(w.WinOpts)
|
||||
rtn["ownerid"] = w.OwnerId
|
||||
rtn["sharemode"] = w.ShareMode
|
||||
rtn["shareopts"] = quickJson(w.ShareOpts)
|
||||
return rtn
|
||||
}
|
||||
|
||||
func (w *WindowType) FromMap(m map[string]interface{}) bool {
|
||||
quickSetStr(&w.SessionId, m, "sessionid")
|
||||
quickSetStr(&w.WindowId, m, "windowid")
|
||||
quickSetStr(&w.CurRemote.OwnerId, m, "curremoteownerid")
|
||||
quickSetStr(&w.CurRemote.RemoteId, m, "curremoteid")
|
||||
quickSetStr(&w.CurRemote.Name, m, "curremotename")
|
||||
quickSetInt64(&w.NextLineNum, m, "nextlinenum")
|
||||
quickSetJson(&w.WinOpts, m, "winopts")
|
||||
quickSetStr(&w.OwnerId, m, "ownerid")
|
||||
quickSetStr(&w.ShareMode, m, "sharemode")
|
||||
quickSetJson(&w.ShareOpts, m, "shareopts")
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *HistoryItemType) ToMap() map[string]interface{} {
|
||||
rtn := make(map[string]interface{})
|
||||
rtn["historyid"] = h.HistoryId
|
||||
@ -448,35 +380,83 @@ func (h *HistoryItemType) FromMap(m map[string]interface{}) bool {
|
||||
|
||||
type ScreenOptsType struct {
|
||||
TabColor string `json:"tabcolor,omitempty"`
|
||||
PTerm string `json:"pterm,omitempty"`
|
||||
}
|
||||
|
||||
func (opts *ScreenOptsType) Scan(val interface{}) error {
|
||||
return quickScanJson(opts, val)
|
||||
}
|
||||
|
||||
func (opts ScreenOptsType) Value() (driver.Value, error) {
|
||||
return quickValueJson(opts)
|
||||
type SWKeys struct {
|
||||
SessionId string
|
||||
WindowId string
|
||||
}
|
||||
|
||||
type ScreenType struct {
|
||||
SessionId string `json:"sessionid"`
|
||||
ScreenId string `json:"screenid"`
|
||||
ScreenIdx int64 `json:"screenidx"`
|
||||
Name string `json:"name"`
|
||||
ActiveWindowId string `json:"activewindowid"`
|
||||
ScreenOpts *ScreenOptsType `json:"screenopts"`
|
||||
OwnerId string `json:"ownerid"`
|
||||
ShareMode string `json:"sharemode"`
|
||||
Incognito bool `json:"incognito,omitempty"`
|
||||
Archived bool `json:"archived,omitempty"`
|
||||
ArchivedTs int64 `json:"archivedts,omitempty"`
|
||||
Windows []*ScreenWindowType `json:"windows"`
|
||||
SessionId string `json:"sessionid"`
|
||||
ScreenId string `json:"screenid"`
|
||||
WindowId string `json:"windowid"`
|
||||
Name string `json:"name"`
|
||||
ScreenIdx int64 `json:"screenidx"`
|
||||
ScreenOpts ScreenOptsType `json:"screenopts"`
|
||||
OwnerId string `json:"ownerid"`
|
||||
ShareMode string `json:"sharemode"`
|
||||
CurRemote RemotePtrType `json:"curremote"`
|
||||
NextLineNum int64 `json:"nextlinenum"`
|
||||
SelectedLine int64 `json:"selectedline"`
|
||||
Anchor ScreenAnchorType `json:"anchor"`
|
||||
FocusType string `json:"focustype"`
|
||||
Archived bool `json:"archived,omitempty"`
|
||||
ArchivedTs int64 `json:"archivedts,omitempty"`
|
||||
|
||||
// only for "full"
|
||||
Lines []*LineType `json:"lines"`
|
||||
Cmds []*CmdType `json:"cmds"`
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
Full bool `json:"full,omitempty"`
|
||||
}
|
||||
|
||||
func (s *ScreenType) ToMap() map[string]interface{} {
|
||||
rtn := make(map[string]interface{})
|
||||
rtn["sessionid"] = s.SessionId
|
||||
rtn["screenid"] = s.ScreenId
|
||||
rtn["windowid"] = s.WindowId
|
||||
rtn["name"] = s.Name
|
||||
rtn["screenidx"] = s.ScreenIdx
|
||||
rtn["screenopts"] = quickJson(s.ScreenOpts)
|
||||
rtn["ownerid"] = s.OwnerId
|
||||
rtn["sharemode"] = s.ShareMode
|
||||
rtn["curremoteownerid"] = s.CurRemote.OwnerId
|
||||
rtn["curremoteid"] = s.CurRemote.RemoteId
|
||||
rtn["curremotename"] = s.CurRemote.Name
|
||||
rtn["nextlinenum"] = s.NextLineNum
|
||||
rtn["selectedline"] = s.SelectedLine
|
||||
rtn["anchor"] = quickJson(s.Anchor)
|
||||
rtn["focustype"] = s.FocusType
|
||||
rtn["archived"] = s.Archived
|
||||
rtn["archivedts"] = s.ArchivedTs
|
||||
return rtn
|
||||
}
|
||||
|
||||
func (s *ScreenType) FromMap(m map[string]interface{}) bool {
|
||||
quickSetStr(&s.SessionId, m, "sessionid")
|
||||
quickSetStr(&s.ScreenId, m, "screenid")
|
||||
quickSetStr(&s.WindowId, m, "windowid")
|
||||
quickSetStr(&s.Name, m, "name")
|
||||
quickSetInt64(&s.ScreenIdx, m, "screenidx")
|
||||
quickSetJson(&s.ScreenOpts, m, "screenopts")
|
||||
quickSetStr(&s.OwnerId, m, "ownerid")
|
||||
quickSetStr(&s.ShareMode, m, "sharemode")
|
||||
quickSetStr(&s.CurRemote.OwnerId, m, "curremoteownerid")
|
||||
quickSetStr(&s.CurRemote.RemoteId, m, "curremoteid")
|
||||
quickSetStr(&s.CurRemote.Name, m, "curremotename")
|
||||
quickSetInt64(&s.NextLineNum, m, "nextlinenum")
|
||||
quickSetInt64(&s.SelectedLine, m, "selectedline")
|
||||
quickSetJson(&s.Anchor, m, "anchor")
|
||||
quickSetStr(&s.FocusType, m, "focustype")
|
||||
quickSetBool(&s.Archived, m, "archived")
|
||||
quickSetInt64(&s.ArchivedTs, m, "archivedts")
|
||||
return true
|
||||
}
|
||||
|
||||
const (
|
||||
LayoutFull = "full"
|
||||
)
|
||||
@ -502,39 +482,11 @@ func (l LayoutType) Value() (driver.Value, error) {
|
||||
return quickValueJson(l)
|
||||
}
|
||||
|
||||
type SWAnchorType struct {
|
||||
type ScreenAnchorType struct {
|
||||
AnchorLine int `json:"anchorline,omitempty"`
|
||||
AnchorOffset int `json:"anchoroffset,omitempty"`
|
||||
}
|
||||
|
||||
func (a *SWAnchorType) Scan(val interface{}) error {
|
||||
return quickScanJson(a, val)
|
||||
}
|
||||
|
||||
func (a SWAnchorType) Value() (driver.Value, error) {
|
||||
return quickValueJson(a)
|
||||
}
|
||||
|
||||
type SWKey struct {
|
||||
SessionId string
|
||||
ScreenId string
|
||||
WindowId string
|
||||
}
|
||||
|
||||
type ScreenWindowType struct {
|
||||
SessionId string `json:"sessionid"`
|
||||
ScreenId string `json:"screenid"`
|
||||
WindowId string `json:"windowid"`
|
||||
Name string `json:"name"`
|
||||
Layout LayoutType `json:"layout"`
|
||||
SelectedLine int `json:"selectedline"`
|
||||
Anchor SWAnchorType `json:"anchor"`
|
||||
FocusType string `json:"focustype"`
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
type HistoryItemType struct {
|
||||
HistoryId string `json:"historyid"`
|
||||
Ts int64 `json:"ts"`
|
||||
|
@ -30,24 +30,23 @@ func (PtyDataUpdate) UpdateType() string {
|
||||
}
|
||||
|
||||
type ModelUpdate struct {
|
||||
Sessions []*SessionType `json:"sessions,omitempty"`
|
||||
ActiveSessionId string `json:"activesessionid,omitempty"`
|
||||
Windows []*WindowType `json:"windows,omitempty"`
|
||||
ScreenWindows []*ScreenWindowType `json:"screenwindows,omitempty"`
|
||||
Line *LineType `json:"line,omitempty"`
|
||||
Lines []*LineType `json:"lines,omitempty"`
|
||||
Cmd *CmdType `json:"cmd,omitempty"`
|
||||
CmdLine *CmdLineType `json:"cmdline,omitempty"`
|
||||
Info *InfoMsgType `json:"info,omitempty"`
|
||||
ClearInfo bool `json:"clearinfo,omitempty"`
|
||||
Remotes []interface{} `json:"remotes,omitempty"` // []*remote.RemoteState
|
||||
History *HistoryInfoType `json:"history,omitempty"`
|
||||
Interactive bool `json:"interactive"`
|
||||
Connect bool `json:"connect,omitempty"`
|
||||
MainView string `json:"mainview,omitempty"`
|
||||
Bookmarks []*BookmarkType `json:"bookmarks,omitempty"`
|
||||
HistoryViewData *HistoryViewData `json:"historyviewdata,omitempty"`
|
||||
ClientData *ClientData `json:"clientdata,omitempty"`
|
||||
Sessions []*SessionType `json:"sessions,omitempty"`
|
||||
ActiveSessionId string `json:"activesessionid,omitempty"`
|
||||
Screens []*ScreenType `json:"screens,omitempty"`
|
||||
Line *LineType `json:"line,omitempty"`
|
||||
Lines []*LineType `json:"lines,omitempty"`
|
||||
Cmd *CmdType `json:"cmd,omitempty"`
|
||||
CmdLine *CmdLineType `json:"cmdline,omitempty"`
|
||||
Info *InfoMsgType `json:"info,omitempty"`
|
||||
ClearInfo bool `json:"clearinfo,omitempty"`
|
||||
Remotes []interface{} `json:"remotes,omitempty"` // []*remote.RemoteState
|
||||
History *HistoryInfoType `json:"history,omitempty"`
|
||||
Interactive bool `json:"interactive"`
|
||||
Connect bool `json:"connect,omitempty"`
|
||||
MainView string `json:"mainview,omitempty"`
|
||||
Bookmarks []*BookmarkType `json:"bookmarks,omitempty"`
|
||||
HistoryViewData *HistoryViewData `json:"historyviewdata,omitempty"`
|
||||
ClientData *ClientData `json:"clientdata,omitempty"`
|
||||
}
|
||||
|
||||
func (ModelUpdate) UpdateType() string {
|
||||
|
Loading…
Reference in New Issue
Block a user