mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
153 lines
4.2 KiB
Go
153 lines
4.2 KiB
Go
// Copyright 2023, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/wavetermdev/waveterm/waveshell/pkg/base"
|
|
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
|
|
"github.com/wavetermdev/waveterm/waveshell/pkg/server"
|
|
"github.com/wavetermdev/waveterm/waveshell/pkg/shexec"
|
|
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
|
)
|
|
|
|
// this is set from build/linker flags
|
|
var BuildTime = "0"
|
|
|
|
func readFullRunPacket(packetParser *packet.PacketParser) (*packet.RunPacketType, error) {
|
|
rpb := packet.MakeRunPacketBuilder()
|
|
for pk := range packetParser.MainCh {
|
|
ok, runPacket := rpb.ProcessPacket(pk)
|
|
if runPacket != nil {
|
|
return runPacket, nil
|
|
}
|
|
if !ok {
|
|
return nil, fmt.Errorf("invalid packet '%s' sent to mshell", pk.GetType())
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("no run packet received")
|
|
}
|
|
|
|
func handleSingle() {
|
|
packetParser := packet.MakePacketParser(os.Stdin, nil)
|
|
sender := packet.MakePacketSender(os.Stdout, nil)
|
|
defer func() {
|
|
sender.Close()
|
|
sender.WaitForDone()
|
|
}()
|
|
wlog.LogConsumer = sender.SendLogPacket
|
|
initPacket := shexec.MakeInitPacket()
|
|
sender.SendPacket(initPacket)
|
|
if len(os.Args) >= 3 && os.Args[2] == "--version" {
|
|
return
|
|
}
|
|
runPacket, err := readFullRunPacket(packetParser)
|
|
if err != nil {
|
|
sender.SendErrorResponse(runPacket.ReqId, err)
|
|
return
|
|
}
|
|
err = shexec.ValidateRunPacket(runPacket)
|
|
if err != nil {
|
|
sender.SendErrorResponse(runPacket.ReqId, err)
|
|
return
|
|
}
|
|
err = runPacket.CK.Validate("run packet")
|
|
if err != nil {
|
|
sender.SendErrorResponse(runPacket.ReqId, fmt.Errorf("run packets from server must have a CK: %v", err))
|
|
}
|
|
if runPacket.Detached {
|
|
sender.SendErrorResponse(runPacket.ReqId, fmt.Errorf("detached mode not supported"))
|
|
return
|
|
} else {
|
|
shexec.IgnoreSigPipe()
|
|
ticker := time.NewTicker(1 * time.Minute)
|
|
go func() {
|
|
for range ticker.C {
|
|
// this will let the command detect when the server has gone away
|
|
// that will then trigger cmd.SendHup() to send SIGHUP to the exec'ed process
|
|
sender.SendPacket(packet.MakePingPacket())
|
|
}
|
|
}()
|
|
defer ticker.Stop()
|
|
cmd, err := shexec.RunCommandSimple(runPacket, sender, true)
|
|
if err != nil {
|
|
sender.SendErrorResponse(runPacket.ReqId, fmt.Errorf("error running command: %w", err))
|
|
return
|
|
}
|
|
defer cmd.Close()
|
|
startPacket := cmd.MakeCmdStartPacket(runPacket.ReqId)
|
|
sender.SendPacket(startPacket)
|
|
go func() {
|
|
exitErr := sender.WaitForDone()
|
|
if exitErr != nil {
|
|
base.Logf("I/O error talking to server, sending SIGHUP to children\n")
|
|
cmd.SendSignal(syscall.SIGHUP)
|
|
}
|
|
}()
|
|
cmd.RunRemoteIOAndWait(packetParser, sender)
|
|
return
|
|
}
|
|
}
|
|
|
|
func handleUsage() {
|
|
usage := `
|
|
mshell is a helper program for wave terminal. it is used to execute commands
|
|
|
|
Options:
|
|
--help - prints this message
|
|
--version - print version
|
|
--server - multiplexer to run multiple commands
|
|
--single - run a single command (connected to multiplexer)
|
|
--single --version - return an init packet with version info
|
|
|
|
mshell does not open any external ports and does not require any additional permissions.
|
|
it communicates exclusively through stdin/stdout with an attached process
|
|
via a JSON packet format.
|
|
`
|
|
fmt.Printf("%s\n\n", strings.TrimSpace(usage))
|
|
}
|
|
|
|
func main() {
|
|
base.SetBuildTime(BuildTime)
|
|
if len(os.Args) == 1 {
|
|
handleUsage()
|
|
return
|
|
}
|
|
firstArg := os.Args[1]
|
|
if firstArg == "--help" {
|
|
handleUsage()
|
|
return
|
|
} else if firstArg == "--version" {
|
|
fmt.Printf("mshell %s+%s\n", base.MShellVersion, base.BuildTime)
|
|
return
|
|
} else if firstArg == "--single" || firstArg == "--single-from-server" {
|
|
base.ProcessType = base.ProcessType_WaveShellSingle
|
|
wlog.GlobalSubsystem = base.ProcessType_WaveShellSingle
|
|
base.InitDebugLog("single")
|
|
handleSingle()
|
|
return
|
|
} else if firstArg == "--server" {
|
|
base.ProcessType = base.ProcessType_WaveShellServer
|
|
wlog.GlobalSubsystem = base.ProcessType_WaveShellServer
|
|
base.InitDebugLog("server")
|
|
base.EnsureRcFilesDir()
|
|
rtnCode, err := server.RunServer()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "[error] %v\n", err)
|
|
}
|
|
if rtnCode != 0 {
|
|
os.Exit(rtnCode)
|
|
}
|
|
return
|
|
} else {
|
|
handleUsage()
|
|
return
|
|
}
|
|
}
|