mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-03-10 13:09:14 +01:00
checkpoint
This commit is contained in:
parent
c1ace6f5d6
commit
275e177218
@ -9,6 +9,7 @@ import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -190,6 +191,30 @@ func HandleCreateWindow(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// params: sessionid, name, activate
|
||||
func HandleCreateScreen(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
|
||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
w.Header().Set("Vary", "Origin")
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
qvals := r.URL.Query()
|
||||
sessionId := qvals.Get("sessionid")
|
||||
if _, err := uuid.Parse(sessionId); err != nil {
|
||||
WriteJsonError(w, fmt.Errorf("invalid sessionid: %w", err))
|
||||
return
|
||||
}
|
||||
name := qvals.Get("name")
|
||||
activateStr := qvals.Get("activate")
|
||||
activate := activateStr != ""
|
||||
screenId, err := sstore.InsertScreen(r.Context(), sessionId, name, activate)
|
||||
if err != nil {
|
||||
WriteJsonError(w, fmt.Errorf("inserting screen: %w", err))
|
||||
return
|
||||
}
|
||||
WriteJsonSuccess(w, screenId)
|
||||
return
|
||||
}
|
||||
|
||||
// params: [none]
|
||||
func HandleGetRemotes(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
|
||||
@ -339,20 +364,45 @@ func HandleRunCommand(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func ProcessFeCommandPacket(ctx context.Context, pk *scpacket.FeCommandPacketType) (*runCommandResponse, error) {
|
||||
// parse metacmd
|
||||
commandStr := strings.TrimSpace(pk.CmdStr)
|
||||
if commandStr == "" {
|
||||
return nil, fmt.Errorf("invalid emtpty command")
|
||||
}
|
||||
if strings.HasPrefix(commandStr, "/comment ") {
|
||||
text := strings.TrimSpace(commandStr[9:])
|
||||
metaCmd := ""
|
||||
metaSubCmd := ""
|
||||
if commandStr == "cd" || strings.HasPrefix(commandStr, "cd ") {
|
||||
metaCmd = "cd"
|
||||
commandStr = strings.TrimSpace(commandStr[2:])
|
||||
} else if commandStr[0] == '/' {
|
||||
spaceIdx := strings.Index(commandStr, " ")
|
||||
if spaceIdx == -1 {
|
||||
metaCmd = commandStr[1:]
|
||||
commandStr = ""
|
||||
} else {
|
||||
metaCmd = commandStr[1:spaceIdx]
|
||||
commandStr = strings.TrimSpace(commandStr[spaceIdx+1:])
|
||||
}
|
||||
colonIdx := strings.Index(metaCmd, ":")
|
||||
if colonIdx != -1 {
|
||||
metaCmd = metaCmd[0:colonIdx]
|
||||
metaSubCmd = metaCmd[colonIdx+1:]
|
||||
}
|
||||
if metaCmd == "" {
|
||||
return nil, fmt.Errorf("invalid command, got bare '/', with no command")
|
||||
}
|
||||
}
|
||||
|
||||
// execute metacmd
|
||||
if metaCmd == "comment" {
|
||||
text := commandStr
|
||||
rtnLine, err := sstore.AddCommentLine(ctx, pk.SessionId, pk.WindowId, pk.UserId, text)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &runCommandResponse{Line: rtnLine}, nil
|
||||
}
|
||||
if strings.HasPrefix(commandStr, "cd ") {
|
||||
newDir := strings.TrimSpace(commandStr[3:])
|
||||
} else if metaCmd == "cd" {
|
||||
newDir := commandStr
|
||||
cdPacket := packet.MakeCdPacket()
|
||||
cdPacket.ReqId = uuid.New().String()
|
||||
cdPacket.Dir = newDir
|
||||
@ -366,7 +416,13 @@ func ProcessFeCommandPacket(ctx context.Context, pk *scpacket.FeCommandPacketTyp
|
||||
}
|
||||
fmt.Printf("GOT cd RESP: %v\n", resp)
|
||||
return nil, nil
|
||||
} else if metaCmd == "s" || metaCmd == "screen" {
|
||||
err := RunScreenCmd(ctx, pk.SessionId, pk.ScreenId, metaSubCmd, commandStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
} else if metaCmd == "" {
|
||||
cmdId := uuid.New().String()
|
||||
cmd, err := remote.RunCommand(ctx, pk, cmdId)
|
||||
if err != nil {
|
||||
@ -377,6 +433,36 @@ func ProcessFeCommandPacket(ctx context.Context, pk *scpacket.FeCommandPacketTyp
|
||||
return nil, err
|
||||
}
|
||||
return &runCommandResponse{Line: rtnLine, Cmd: cmd}, nil
|
||||
} else {
|
||||
fmt.Printf("INVALID metacmd '%s'\n", metaCmd)
|
||||
return nil, fmt.Errorf("Invalid command type /%s", metaCmd)
|
||||
}
|
||||
}
|
||||
|
||||
func RunScreenCmd(ctx context.Context, sessionId string, screenId string, subCmd string, commandStr string) error {
|
||||
if subCmd != "" {
|
||||
return fmt.Errorf("invalid /screen subcommand '%s'", subCmd)
|
||||
}
|
||||
if commandStr == "" {
|
||||
return fmt.Errorf("usage /screen [screen-name|screen-index|screen-id], no param specified")
|
||||
}
|
||||
screens, err := sstore.GetSessionScreens(ctx, sessionId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not retreive screens for session=%s", sessionId)
|
||||
}
|
||||
screenNum, err := strconv.Atoi(commandStr)
|
||||
if err == nil {
|
||||
if screenNum < 1 || screenNum > len(screens) {
|
||||
return fmt.Errorf("could not switch to screen #%d (out of range), valid screens 1-%d", screenNum, len(screens))
|
||||
}
|
||||
return sstore.SwitchScreenById(ctx, sessionId, screens[screenNum-1].ScreenId)
|
||||
}
|
||||
for _, screen := range screens {
|
||||
if screen.Name == commandStr {
|
||||
return sstore.SwitchScreenById(ctx, sessionId, screen.ScreenId)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("could not switch to screen '%s' (name not found)", commandStr)
|
||||
}
|
||||
|
||||
// /api/start-session
|
||||
@ -384,12 +470,6 @@ func ProcessFeCommandPacket(ctx context.Context, pk *scpacket.FeCommandPacketTyp
|
||||
// * userid
|
||||
// * sessionid
|
||||
//
|
||||
// /api/get-session
|
||||
// params:
|
||||
// * name
|
||||
// returns:
|
||||
// * session
|
||||
//
|
||||
// /api/ptyout (pos=[position]) - returns contents of ptyout file
|
||||
// params:
|
||||
// * sessionid
|
||||
@ -525,10 +605,10 @@ func main() {
|
||||
gr.HandleFunc("/api/ptyout", HandleGetPtyOut)
|
||||
gr.HandleFunc("/api/get-all-sessions", HandleGetAllSessions)
|
||||
gr.HandleFunc("/api/create-session", HandleCreateSession)
|
||||
gr.HandleFunc("/api/get-session", HandleGetSession)
|
||||
gr.HandleFunc("/api/get-window", HandleGetWindow)
|
||||
gr.HandleFunc("/api/get-remotes", HandleGetRemotes)
|
||||
gr.HandleFunc("/api/create-window", HandleCreateWindow)
|
||||
gr.HandleFunc("/api/create-screen", HandleCreateScreen)
|
||||
gr.HandleFunc("/api/run-command", HandleRunCommand).Methods("GET", "POST", "OPTIONS")
|
||||
server := &http.Server{
|
||||
Addr: MainServerAddr,
|
||||
|
@ -18,6 +18,7 @@ type RemoteState struct {
|
||||
type FeCommandPacketType struct {
|
||||
Type string `json:"type"`
|
||||
SessionId string `json:"sessionid"`
|
||||
ScreenId string `json:"screenid"`
|
||||
WindowId string `json:"windowid"`
|
||||
UserId string `json:"userid"`
|
||||
CmdStr string `json:"cmdstr"`
|
||||
|
@ -90,18 +90,6 @@ func GetAllSessions(ctx context.Context) ([]*SessionType, error) {
|
||||
err := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT * FROM session`
|
||||
tx.SelectWrap(&rtn, query)
|
||||
var windows []*WindowType
|
||||
query = `SELECT * FROM window`
|
||||
tx.SelectWrap(&windows, query)
|
||||
winMap := make(map[string][]*WindowType)
|
||||
for _, win := range windows {
|
||||
winArr := winMap[win.SessionId]
|
||||
winArr = append(winArr, win)
|
||||
winMap[win.SessionId] = winArr
|
||||
}
|
||||
for _, session := range rtn {
|
||||
session.Windows = winMap[session.SessionId]
|
||||
}
|
||||
var screens []*ScreenType
|
||||
query = `SELECT * FROM screen ORDER BY screenidx`
|
||||
tx.SelectWrap(&screens, query)
|
||||
@ -155,6 +143,16 @@ func GetWindowById(ctx context.Context, sessionId string, windowId string) (*Win
|
||||
return rtnWindow, err
|
||||
}
|
||||
|
||||
func GetSessionScreens(ctx context.Context, sessionId string) ([]*ScreenType, error) {
|
||||
var rtn []*ScreenType
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT * FROM screen WHERE sessionid = ? ORDER BY screenidx`
|
||||
tx.SelectWrap(&rtn, query, sessionId)
|
||||
return nil
|
||||
})
|
||||
return rtn, txErr
|
||||
}
|
||||
|
||||
func GetSessionById(ctx context.Context, id string) (*SessionType, error) {
|
||||
var rtnSession *SessionType
|
||||
err := WithTx(ctx, func(tx *TxWrap) error {
|
||||
@ -165,15 +163,10 @@ func GetSessionById(ctx context.Context, id string) (*SessionType, error) {
|
||||
return nil
|
||||
}
|
||||
rtnSession = &session
|
||||
query = `SELECT * FROM window WHERE sessionid = ?`
|
||||
tx.SelectWrap(&session.Windows, query, session.SessionId)
|
||||
query = `SELECT * FROM screen WHERE sessionid = ? ORDER BY screenidx`
|
||||
tx.SelectWrap(&session.Screens, query, session.SessionId)
|
||||
query = `SELECT * FROM remote_instance WHERE sessionid = ?`
|
||||
tx.SelectWrap(&session.Remotes, query, session.SessionId)
|
||||
query = `SELECT * FROM cmd WHERE sessionid = ?`
|
||||
marr := tx.SelectMaps(query, session.SessionId)
|
||||
for _, m := range marr {
|
||||
session.Cmds = append(session.Cmds, CmdFromMap(m))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@ -209,15 +202,16 @@ func InsertSessionWithName(ctx context.Context, sessionName string) (string, err
|
||||
maxSessionIdx := tx.GetInt(`SELECT COALESCE(max(sessionidx), 0) FROM session`)
|
||||
query := `INSERT INTO session (sessionid, name, activescreenid, sessionidx, notifynum) VALUES (?, ?, '', ?, ?)`
|
||||
tx.ExecWrap(query, newSessionId, sessionName, maxSessionIdx+1, 0)
|
||||
screenId, err := InsertScreen(tx.Context(), newSessionId, "")
|
||||
_, err := InsertScreen(tx.Context(), newSessionId, "", true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
query = `UPDATE session SET activescreenid = ? WHERE sessionid = ?`
|
||||
tx.ExecWrap(query, screenId, newSessionId)
|
||||
return nil
|
||||
})
|
||||
return newSessionId, txErr
|
||||
if txErr != nil {
|
||||
return "", txErr
|
||||
}
|
||||
return newSessionId, nil
|
||||
}
|
||||
|
||||
func containsStr(strs []string, testStr string) bool {
|
||||
@ -253,7 +247,7 @@ func fmtUniqueName(name string, defaultFmtStr string, startIdx int, strs []strin
|
||||
}
|
||||
}
|
||||
|
||||
func InsertScreen(ctx context.Context, sessionId string, screenName string) (string, error) {
|
||||
func InsertScreen(ctx context.Context, sessionId string, screenName string, activate bool) (string, error) {
|
||||
var newScreenId string
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT sessionid FROM session WHERE sessionid = ?`
|
||||
@ -270,11 +264,35 @@ func InsertScreen(ctx context.Context, sessionId string, screenName string) (str
|
||||
layout := LayoutType{Type: LayoutFull}
|
||||
query = `INSERT INTO screen_window (sessionid, screenid, windowid, name, layout) VALUES (?, ?, ?, ?, ?)`
|
||||
tx.ExecWrap(query, sessionId, newScreenId, newWindowId, DefaultScreenWindowName, layout)
|
||||
if activate {
|
||||
query = `UPDATE session SET activescreenid = ? WHERE sessionid = ?`
|
||||
tx.ExecWrap(query, newScreenId, sessionId)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return newScreenId, txErr
|
||||
}
|
||||
|
||||
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.GetWrap(&screen, query, sessionId, screenId)
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
rtnScreen = &screen
|
||||
query = `SELECT * FROM screen_window WHERE sessionid = ? AND screenid = ?`
|
||||
tx.SelectWrap(&screen.Windows, query, sessionId, screenId)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
return rtnScreen, nil
|
||||
}
|
||||
|
||||
func txCreateWindow(tx *TxWrap, sessionId string) string {
|
||||
windowId := uuid.New().String()
|
||||
query := `INSERT INTO window (sessionid, windowid, curremote, winopts) VALUES (?, ?, ?, ?)`
|
||||
@ -366,3 +384,25 @@ func HangupRunningCmdsByRemoteId(ctx context.Context, remoteId string) error {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func SwitchScreenById(ctx context.Context, sessionId string, screenId string) 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("cannot switch to screen, screen=%s does not exist in session=%s", screenId, sessionId)
|
||||
}
|
||||
query = `UPDATE session SET activescreenid = ? WHERE sessionid = ?`
|
||||
tx.ExecWrap(query, screenId, sessionId)
|
||||
return nil
|
||||
})
|
||||
sessionUpdate := SessionType{
|
||||
SessionId: sessionId,
|
||||
ActiveScreenId: screenId,
|
||||
NotifyNum: -1,
|
||||
}
|
||||
update := &SessionUpdate{
|
||||
Sessions: []SessionType{sessionUpdate},
|
||||
}
|
||||
MainBus.SendUpdate("", update)
|
||||
return txErr
|
||||
}
|
||||
|
@ -63,9 +63,11 @@ type SessionType struct {
|
||||
ActiveScreenId string `json:"activescreenid"`
|
||||
NotifyNum int64 `json:"notifynum"`
|
||||
Screens []*ScreenType `json:"screens"`
|
||||
Windows []*WindowType `json:"windows"`
|
||||
Cmds []*CmdType `json:"cmds"`
|
||||
Remotes []*RemoteInstance `json:"remotes"`
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
Full bool `json:"full,omitempty"`
|
||||
}
|
||||
|
||||
type WindowOptsType struct {
|
||||
@ -88,6 +90,9 @@ type WindowType struct {
|
||||
Cmds []*CmdType `json:"cmds"`
|
||||
History []*HistoryItemType `json:"history"`
|
||||
Remotes []*RemoteInstance `json:"remotes"`
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
type ScreenOptsType struct {
|
||||
@ -110,6 +115,10 @@ type ScreenType struct {
|
||||
ActiveWindowId string `json:"activewindowid"`
|
||||
ScreenOpts ScreenOptsType `json:"screenopts"`
|
||||
Windows []*ScreenWindowType `json:"windows"`
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
Full bool `json:"full,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
@ -143,6 +152,9 @@ type ScreenWindowType struct {
|
||||
WindowId string `json:"windowid"`
|
||||
Name string `json:"name"`
|
||||
Layout LayoutType `json:"layout"`
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
type HistoryItemType struct {
|
||||
|
@ -23,8 +23,7 @@ type WindowUpdate struct {
|
||||
}
|
||||
|
||||
type SessionUpdate struct {
|
||||
Session SessionType `json:"session"`
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
Sessions []SessionType `json:"sessions"`
|
||||
}
|
||||
|
||||
type CmdUpdate struct {
|
||||
@ -32,11 +31,6 @@ type CmdUpdate struct {
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
type ScreenUpdate struct {
|
||||
Screen CmdType `json:"screen"`
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateChannel struct {
|
||||
SessionId string
|
||||
ClientId string
|
||||
|
Loading…
Reference in New Issue
Block a user