mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +01:00
one commit - added fileview backend changes
This commit is contained in:
parent
46b9c22f10
commit
8e907066ad
318
diff.txt
Normal file
318
diff.txt
Normal file
@ -0,0 +1,318 @@
|
||||
diff --git a/src/app/workspace/cmdinput/textareainput.tsx b/src/app/workspace/cmdinput/textareainput.tsx
|
||||
index c5461a90..0d43a66c 100644
|
||||
--- a/src/app/workspace/cmdinput/textareainput.tsx
|
||||
+++ b/src/app/workspace/cmdinput/textareainput.tsx
|
||||
@@ -131,165 +131,177 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: ()
|
||||
this.checkHeight(false);
|
||||
this.updateSP();
|
||||
let keybindManager = GlobalModel.keybindManager;
|
||||
- keybindManager.registerKeybinding("pane", "cmdinput", "any", (waveEvent) => {
|
||||
- return mobx.action(() => {
|
||||
- let inputRef = this.mainInputRef.current;
|
||||
- if (util.isModKeyPress(waveEvent)) {
|
||||
- return false;
|
||||
- }
|
||||
- let model = GlobalModel;
|
||||
- let inputModel = model.inputModel;
|
||||
- let ctrlMod = waveEvent.control || waveEvent.cmd || waveEvent.shift;
|
||||
- let curLine = inputModel.getCurLine();
|
||||
-
|
||||
- let lastTab = this.lastTab;
|
||||
- this.lastTab = keybindManager.checkKeyPressed(waveEvent, "cmdinput:autocomplete");
|
||||
- let lastHist = this.lastHistoryUpDown;
|
||||
- this.lastHistoryUpDown = false;
|
||||
-
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:autocomplete")) {
|
||||
- if (lastTab) {
|
||||
- GlobalModel.submitCommand(
|
||||
- "_compgen",
|
||||
- null,
|
||||
- [curLine],
|
||||
- { comppos: String(curLine.length), compshow: "1", nohist: "1" },
|
||||
- true
|
||||
- );
|
||||
- } else {
|
||||
- GlobalModel.submitCommand(
|
||||
- "_compgen",
|
||||
- null,
|
||||
- [curLine],
|
||||
- { comppos: String(curLine.length), nohist: "1" },
|
||||
- true
|
||||
- );
|
||||
+ if (GlobalModel.activeMainView.get() == "session") {
|
||||
+ console.log("session");
|
||||
+ keybindManager.registerKeybinding("pane", "cmdinput", "any", (waveEvent) => {
|
||||
+ return mobx.action(() => {
|
||||
+ let inputRef = this.mainInputRef.current;
|
||||
+ if (util.isModKeyPress(waveEvent)) {
|
||||
+ return false;
|
||||
}
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "generic:confirm")) {
|
||||
- if (!ctrlMod) {
|
||||
- if (GlobalModel.inputModel.isEmpty()) {
|
||||
- let activeWindow = GlobalModel.getScreenLinesForActiveScreen();
|
||||
- let activeScreen = GlobalModel.getActiveScreen();
|
||||
- if (activeScreen != null && activeWindow != null && activeWindow.lines.length > 0) {
|
||||
- activeScreen.setSelectedLine(0);
|
||||
- GlobalCommandRunner.screenSelectLine("E");
|
||||
- }
|
||||
+ let model = GlobalModel;
|
||||
+ let inputModel = model.inputModel;
|
||||
+ let ctrlMod = waveEvent.control || waveEvent.cmd || waveEvent.shift;
|
||||
+ let curLine = inputModel.getCurLine();
|
||||
+
|
||||
+ let lastTab = this.lastTab;
|
||||
+ this.lastTab = keybindManager.checkKeyPressed(waveEvent, "cmdinput:autocomplete");
|
||||
+ let lastHist = this.lastHistoryUpDown;
|
||||
+ this.lastHistoryUpDown = false;
|
||||
+
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:autocomplete")) {
|
||||
+ if (lastTab) {
|
||||
+ GlobalModel.submitCommand(
|
||||
+ "_compgen",
|
||||
+ null,
|
||||
+ [curLine],
|
||||
+ { comppos: String(curLine.length), compshow: "1", nohist: "1" },
|
||||
+ true
|
||||
+ );
|
||||
} else {
|
||||
- setTimeout(() => GlobalModel.inputModel.uiSubmitCommand(), 0);
|
||||
+ GlobalModel.submitCommand(
|
||||
+ "_compgen",
|
||||
+ null,
|
||||
+ [curLine],
|
||||
+ { comppos: String(curLine.length), nohist: "1" },
|
||||
+ true
|
||||
+ );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
- inputRef.setRangeText("\n", inputRef.selectionStart, inputRef.selectionEnd, "end");
|
||||
- GlobalModel.inputModel.setCurLine(inputRef.value);
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "generic:cancel")) {
|
||||
- let inputModel = GlobalModel.inputModel;
|
||||
- inputModel.toggleInfoMsg();
|
||||
- console.log("hello?", inputModel.inputMode.get());
|
||||
- if (inputModel.inputMode.get() != null) {
|
||||
- inputModel.resetInputMode();
|
||||
- console.log("hello? 2");
|
||||
- }
|
||||
- console.log("hello 3?");
|
||||
- inputModel.closeAIAssistantChat(true);
|
||||
- console.log("hello 4?");
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:expandInput")) {
|
||||
- let inputModel = GlobalModel.inputModel;
|
||||
- inputModel.toggleExpandInput();
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:clearInput")) {
|
||||
- inputModel.resetInput();
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:cutLineLeftOfCursor")) {
|
||||
- this.controlU();
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:previousHistoryItem")) {
|
||||
- this.controlP();
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:nextHistoryItem")) {
|
||||
- this.controlN();
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:cutWordLeftOfCursor")) {
|
||||
- this.controlW();
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:paste")) {
|
||||
- this.controlY();
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:openHistory")) {
|
||||
- inputModel.openHistory();
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeysPressed(waveEvent, ["generic:selectAbove", "generic:selectBelow"])) {
|
||||
- if (!inputModel.isHistoryLoaded()) {
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "generic:selectAbove")) {
|
||||
- this.lastHistoryUpDown = true;
|
||||
- inputModel.loadHistory(false, 1, "screen");
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "generic:confirm")) {
|
||||
+ if (!ctrlMod) {
|
||||
+ if (GlobalModel.inputModel.isEmpty()) {
|
||||
+ let activeWindow = GlobalModel.getScreenLinesForActiveScreen();
|
||||
+ let activeScreen = GlobalModel.getActiveScreen();
|
||||
+ if (activeScreen != null && activeWindow != null && activeWindow.lines.length > 0) {
|
||||
+ activeScreen.setSelectedLine(0);
|
||||
+ GlobalCommandRunner.screenSelectLine("E");
|
||||
+ }
|
||||
+ } else {
|
||||
+ setTimeout(() => GlobalModel.inputModel.uiSubmitCommand(), 0);
|
||||
+ }
|
||||
+ return true;
|
||||
}
|
||||
+ inputRef.setRangeText("\n", inputRef.selectionStart, inputRef.selectionEnd, "end");
|
||||
+ GlobalModel.inputModel.setCurLine(inputRef.value);
|
||||
return true;
|
||||
}
|
||||
- // invisible history movement
|
||||
- let linePos = this.getLinePos(inputRef);
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "generic:selectAbove")) {
|
||||
- if (!lastHist && linePos.linePos > 1) {
|
||||
- // regular arrow
|
||||
- return false;
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "generic:cancel")) {
|
||||
+ let inputModel = GlobalModel.inputModel;
|
||||
+ inputModel.toggleInfoMsg();
|
||||
+ if (inputModel.inputMode.get() != null) {
|
||||
+ inputModel.resetInputMode();
|
||||
}
|
||||
- inputModel.moveHistorySelection(1);
|
||||
- this.lastHistoryUpDown = true;
|
||||
+ inputModel.closeAIAssistantChat(true);
|
||||
return true;
|
||||
}
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "generic:selectBelow")) {
|
||||
- if (!lastHist && linePos.linePos < linePos.numLines) {
|
||||
- // regular arrow
|
||||
- return false;
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:expandInput")) {
|
||||
+ let inputModel = GlobalModel.inputModel;
|
||||
+ inputModel.toggleExpandInput();
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:clearInput")) {
|
||||
+ inputModel.resetInput();
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:cutLineLeftOfCursor")) {
|
||||
+ this.controlU();
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:previousHistoryItem")) {
|
||||
+ this.controlP();
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:nextHistoryItem")) {
|
||||
+ this.controlN();
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:cutWordLeftOfCursor")) {
|
||||
+ this.controlW();
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:paste")) {
|
||||
+ this.controlY();
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:openHistory")) {
|
||||
+ inputModel.openHistory();
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (keybindManager.checkKeysPressed(waveEvent, ["generic:selectAbove", "generic:selectBelow"])) {
|
||||
+ if (!inputModel.isHistoryLoaded()) {
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "generic:selectAbove")) {
|
||||
+ this.lastHistoryUpDown = true;
|
||||
+ inputModel.loadHistory(false, 1, "screen");
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ // invisible history movement
|
||||
+ let linePos = this.getLinePos(inputRef);
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "generic:selectAbove")) {
|
||||
+ if (!lastHist && linePos.linePos > 1) {
|
||||
+ // regular arrow
|
||||
+ return false;
|
||||
+ }
|
||||
+ inputModel.moveHistorySelection(1);
|
||||
+ this.lastHistoryUpDown = true;
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "generic:selectBelow")) {
|
||||
+ if (!lastHist && linePos.linePos < linePos.numLines) {
|
||||
+ // regular arrow
|
||||
+ return false;
|
||||
+ }
|
||||
+ inputModel.moveHistorySelection(-1);
|
||||
+ this.lastHistoryUpDown = true;
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ if (
|
||||
+ keybindManager.checkKeysPressed(waveEvent, [
|
||||
+ "generic:selectPageAbove",
|
||||
+ "generic:selectPageBelow",
|
||||
+ ])
|
||||
+ ) {
|
||||
+ let infoScroll = inputModel.hasScrollingInfoMsg();
|
||||
+ if (infoScroll) {
|
||||
+ let div = document.querySelector(".cmd-input-info");
|
||||
+ let amt = pageSize(div);
|
||||
+ scrollDiv(
|
||||
+ div,
|
||||
+ keybindManager.checkKeyPressed(waveEvent, "generic:selectPageAbove") ? -amt : amt
|
||||
+ );
|
||||
}
|
||||
- inputModel.moveHistorySelection(-1);
|
||||
- this.lastHistoryUpDown = true;
|
||||
return true;
|
||||
}
|
||||
- }
|
||||
- if (
|
||||
- keybindManager.checkKeysPressed(waveEvent, ["generic:selectPageAbove", "generic:selectPageBelow"])
|
||||
- ) {
|
||||
- let infoScroll = inputModel.hasScrollingInfoMsg();
|
||||
- if (infoScroll) {
|
||||
- let div = document.querySelector(".cmd-input-info");
|
||||
- let amt = pageSize(div);
|
||||
- scrollDiv(
|
||||
- div,
|
||||
- keybindManager.checkKeyPressed(waveEvent, "generic:selectPageAbove") ? -amt : amt
|
||||
- );
|
||||
+ if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:openAIChat")) {
|
||||
+ inputModel.openAIAssistantChat();
|
||||
+ return true;
|
||||
}
|
||||
- return true;
|
||||
- }
|
||||
- if (keybindManager.checkKeyPressed(waveEvent, "cmdinput:openAIChat")) {
|
||||
- inputModel.openAIAssistantChat();
|
||||
- return true;
|
||||
- }
|
||||
- // console.log(e.code, e.keyCode, e.key, event.which, ctrlMod, e);
|
||||
- return false;
|
||||
- })();
|
||||
- });
|
||||
+ // console.log(e.code, e.keyCode, e.key, event.which, ctrlMod, e);
|
||||
+ return false;
|
||||
+ })();
|
||||
+ });
|
||||
+ } else {
|
||||
+ console.log("not session");
|
||||
+ keybindManager.unregisterDomain("cmdinput");
|
||||
+ }
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
+ console.log("component unmounted??");
|
||||
let keybindManager = GlobalModel.keybindManager;
|
||||
keybindManager.unregisterDomain("cmdinput");
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
+ console.log("component update");
|
||||
+ if (GlobalModel.activeMainView.get() != "session") {
|
||||
+ console.log("unregistering");
|
||||
+ let keybindManager = GlobalModel.keybindManager;
|
||||
+ keybindManager.unregisterDomain("cmdinput");
|
||||
+ }
|
||||
let activeScreen = GlobalModel.getActiveScreen();
|
||||
if (activeScreen != null) {
|
||||
let focusType = activeScreen.focusType.get();
|
4
prettify.sh
Executable file
4
prettify.sh
Executable file
@ -0,0 +1,4 @@
|
||||
dirs=$(git diff main --name-only --diff-filter d | grep -e '\.[tj]sx\?$' | xargs)
|
||||
echo dirs: $dirs
|
||||
node_modules/prettier/bin-prettier.js --write $dirs
|
||||
|
5
prettifyAndPush.sh
Executable file
5
prettifyAndPush.sh
Executable file
@ -0,0 +1,5 @@
|
||||
dirs=$(git diff main --name-only --diff-filter d | grep -e '\.[tj]sx\?$' | xargs)
|
||||
node_modules/prettier/bin-prettier.js --write $dirs
|
||||
git add $dirs
|
||||
git commit --amend
|
||||
git push
|
@ -64,6 +64,8 @@ const (
|
||||
FileStatPacketStr = "filestat"
|
||||
LogPacketStr = "log" // logging packet (sent from waveshell back to server)
|
||||
ShellStatePacketStr = "shellstate"
|
||||
ListDirPacketStr = "listdir"
|
||||
SearchDirPacketStr = "searchdir"
|
||||
RpcInputPacketStr = "rpcinput" // rpc-followup
|
||||
SudoRequestPacketStr = "sudorequest"
|
||||
SudoResponsePacketStr = "sudoresponse"
|
||||
@ -120,6 +122,8 @@ func init() {
|
||||
TypeStrToFactory[WriteFileDonePacketStr] = reflect.TypeOf(WriteFileDonePacketType{})
|
||||
TypeStrToFactory[LogPacketStr] = reflect.TypeOf(LogPacketType{})
|
||||
TypeStrToFactory[ShellStatePacketStr] = reflect.TypeOf(ShellStatePacketType{})
|
||||
TypeStrToFactory[ListDirPacketStr] = reflect.TypeOf(ListDirPacketType{})
|
||||
TypeStrToFactory[SearchDirPacketStr] = reflect.TypeOf(SearchDirPacketType{})
|
||||
TypeStrToFactory[FileStatPacketStr] = reflect.TypeOf(FileStatPacketType{})
|
||||
TypeStrToFactory[RpcInputPacketStr] = reflect.TypeOf(RpcInputPacketType{})
|
||||
TypeStrToFactory[SudoRequestPacketStr] = reflect.TypeOf(SudoRequestPacketType{})
|
||||
@ -133,6 +137,8 @@ func init() {
|
||||
var _ RpcPacketType = (*ReInitPacketType)(nil)
|
||||
var _ RpcPacketType = (*StreamFilePacketType)(nil)
|
||||
var _ RpcPacketType = (*WriteFilePacketType)(nil)
|
||||
var _ RpcPacketType = (*ListDirPacketType)(nil)
|
||||
var _ RpcPacketType = (*SearchDirPacketType)(nil)
|
||||
|
||||
var _ RpcResponsePacketType = (*CmdStartPacketType)(nil)
|
||||
var _ RpcResponsePacketType = (*ResponsePacketType)(nil)
|
||||
@ -449,8 +455,12 @@ func MakeFileStatPacketType() *FileStatPacketType {
|
||||
return &FileStatPacketType{Type: FileStatPacketStr}
|
||||
}
|
||||
|
||||
func MakeFileStatPacketFromFileInfo(finfo fs.FileInfo, err string, done bool) *FileStatPacketType {
|
||||
func MakeFileStatPacketFromFileInfo(listDirPk *ListDirPacketType, finfo fs.FileInfo, err string, done bool) *FileStatPacketType {
|
||||
resp := MakeFileStatPacketType()
|
||||
if listDirPk != nil {
|
||||
resp.RespId = listDirPk.ReqId
|
||||
resp.Path = listDirPk.Path
|
||||
}
|
||||
resp.Error = err
|
||||
resp.Done = done
|
||||
|
||||
@ -464,6 +474,50 @@ func MakeFileStatPacketFromFileInfo(finfo fs.FileInfo, err string, done bool) *F
|
||||
return resp
|
||||
}
|
||||
|
||||
type ListDirPacketType struct {
|
||||
Type string `json:"type"`
|
||||
ReqId string `json:"reqid"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
func (*ListDirPacketType) GetType() string {
|
||||
return ListDirPacketStr
|
||||
}
|
||||
|
||||
func (p *ListDirPacketType) GetReqId() string {
|
||||
return p.ReqId
|
||||
}
|
||||
|
||||
func MakeListDirPacket() *ListDirPacketType {
|
||||
return &ListDirPacketType{Type: ListDirPacketStr}
|
||||
}
|
||||
|
||||
type SearchDirPacketType struct {
|
||||
Type string `json:"type"`
|
||||
ReqId string `json:"reqid"`
|
||||
Path string `json:"path"`
|
||||
SearchQuery string `json:"searchquery"`
|
||||
}
|
||||
|
||||
func (*SearchDirPacketType) GetType() string {
|
||||
return SearchDirPacketStr
|
||||
}
|
||||
|
||||
func (p *SearchDirPacketType) GetReqId() string {
|
||||
return p.ReqId
|
||||
}
|
||||
|
||||
func (p *SearchDirPacketType) ConvertToListDir() *ListDirPacketType {
|
||||
rtn := MakeListDirPacket()
|
||||
rtn.ReqId = p.ReqId
|
||||
rtn.Path = p.Path
|
||||
return rtn
|
||||
}
|
||||
|
||||
func MakeSearchDirPacket() *SearchDirPacketType {
|
||||
return &SearchDirPacketType{Type: SearchDirPacketStr}
|
||||
}
|
||||
|
||||
type StreamFilePacketType struct {
|
||||
Type string `json:"type"`
|
||||
ReqId string `json:"reqid"`
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -660,6 +661,97 @@ func (m *MServer) streamFile(pk *packet.StreamFilePacketType) {
|
||||
return
|
||||
}
|
||||
|
||||
func (m *MServer) writeListDirErrPacket(err error, reqId string) {
|
||||
resp := packet.MakeFileStatPacketType()
|
||||
resp.RespId = reqId
|
||||
resp.Error = fmt.Sprintf("Error in list dir: %v", err)
|
||||
resp.Done = true
|
||||
m.Sender.SendPacket(resp)
|
||||
}
|
||||
|
||||
func (m *MServer) ListDir(listDirPk *packet.ListDirPacketType) {
|
||||
dirEntries, err := os.ReadDir(listDirPk.Path)
|
||||
var readDirError string = ""
|
||||
if err != nil {
|
||||
readDirError = fmt.Sprintf("error in list dir: %v", err)
|
||||
}
|
||||
curDirStat, err := os.Stat(listDirPk.Path)
|
||||
if err != nil {
|
||||
m.writeListDirErrPacket(err, listDirPk.ReqId)
|
||||
}
|
||||
resp := packet.MakeFileStatPacketFromFileInfo(listDirPk, curDirStat, readDirError, false)
|
||||
resp.Name = "."
|
||||
m.Sender.SendPacket(resp)
|
||||
curDirStat, err = os.Stat(filepath.Join(listDirPk.Path, ".."))
|
||||
if err != nil {
|
||||
m.writeListDirErrPacket(err, listDirPk.ReqId)
|
||||
return
|
||||
}
|
||||
resp = packet.MakeFileStatPacketFromFileInfo(listDirPk, curDirStat, readDirError, len(dirEntries) == 0)
|
||||
resp.Name = ".."
|
||||
m.Sender.SendPacket(resp)
|
||||
|
||||
for index := 0; index < len(dirEntries); index++ {
|
||||
dirEntry := dirEntries[index]
|
||||
dirEntryFileInfo, err := dirEntry.Info()
|
||||
if err != nil {
|
||||
m.writeListDirErrPacket(err, listDirPk.ReqId)
|
||||
return
|
||||
}
|
||||
done := index == len(dirEntries)-1
|
||||
resp = packet.MakeFileStatPacketFromFileInfo(listDirPk, dirEntryFileInfo, readDirError, done)
|
||||
m.Sender.SendPacket(resp)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MServer) SearchDir(searchDirPk *packet.SearchDirPacketType) {
|
||||
searchEmpty := true
|
||||
foundRoot := false
|
||||
err := filepath.WalkDir(searchDirPk.Path, func(path string, dirEntry fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
errString := fmt.Sprintf("%v", err)
|
||||
if strings.Contains(errString, "operation not permitted") {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
}
|
||||
fileName := filepath.Base(path)
|
||||
match, err := regexp.MatchString(searchDirPk.SearchQuery, fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if match {
|
||||
base.Logf("matched file: %v %v", path, searchDirPk.SearchQuery)
|
||||
// special case where walkdir includes the current path, which messes up the stat pk
|
||||
rootName := filepath.Base(searchDirPk.Path)
|
||||
if !foundRoot && fileName == rootName {
|
||||
foundRoot = true
|
||||
return nil
|
||||
}
|
||||
dirEntryFileInfo, err := dirEntry.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
searchEmpty = false
|
||||
resp := packet.MakeFileStatPacketFromFileInfo(searchDirPk.ConvertToListDir(), dirEntryFileInfo, "", false)
|
||||
m.Sender.SendPacket(resp)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
m.writeListDirErrPacket(err, searchDirPk.ReqId)
|
||||
} else {
|
||||
searchError := ""
|
||||
if searchEmpty {
|
||||
searchError = "none"
|
||||
}
|
||||
resp := packet.MakeFileStatPacketType()
|
||||
resp.Error = searchError
|
||||
resp.Done = true
|
||||
m.Sender.SendPacket(resp)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func int64Min(v1 int64, v2 int64) int64 {
|
||||
if v1 < v2 {
|
||||
return v1
|
||||
@ -703,6 +795,14 @@ func (m *MServer) ProcessRpcPacket(pk packet.RpcPacketType) {
|
||||
go m.writeFile(writePk, wfc)
|
||||
return
|
||||
}
|
||||
if listDirPk, ok := pk.(*packet.ListDirPacketType); ok {
|
||||
go m.ListDir(listDirPk)
|
||||
return
|
||||
}
|
||||
if searchDirPk, ok := pk.(*packet.SearchDirPacketType); ok {
|
||||
go m.SearchDir(searchDirPk)
|
||||
return
|
||||
}
|
||||
m.Sender.SendErrorResponse(reqId, fmt.Errorf("invalid rpc type '%s'", pk.GetType()))
|
||||
}
|
||||
|
||||
|
@ -1033,7 +1033,7 @@ func configDirHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var files []*packet.FileStatPacketType
|
||||
for index := 0; index < len(entries); index++ {
|
||||
curEntry := entries[index]
|
||||
curFile := packet.MakeFileStatPacketFromFileInfo(curEntry, "", false)
|
||||
curFile := packet.MakeFileStatPacketFromFileInfo(nil, curEntry, "", false)
|
||||
files = append(files, curFile)
|
||||
}
|
||||
dirListJson, err := json.Marshal(files)
|
||||
|
@ -279,6 +279,7 @@ func init() {
|
||||
registerCmdFn("set", SetCommand)
|
||||
|
||||
registerCmdFn("view:stat", ViewStatCommand)
|
||||
registerCmdFn("view:dir", ViewDirCommand)
|
||||
registerCmdFn("view:test", ViewTestCommand)
|
||||
|
||||
registerCmdFn("edit:test", EditTestCommand)
|
||||
@ -287,6 +288,8 @@ func init() {
|
||||
registerCmdFn("codeedit", CodeEditCommand)
|
||||
registerCmdFn("codeview", CodeEditCommand)
|
||||
|
||||
registerCmdFn("searchdir", SearchDirCommand)
|
||||
|
||||
registerCmdFn("imageview", ImageViewCommand)
|
||||
registerCmdFn("mdview", MarkdownViewCommand)
|
||||
registerCmdFn("markdownview", MarkdownViewCommand)
|
||||
@ -1323,6 +1326,15 @@ func doCopyLocalFileToRemote(ctx context.Context, cmd *sstore.CmdType, remoteWsh
|
||||
return
|
||||
}
|
||||
defer localFile.Close()
|
||||
fileStat, err := localFile.Stat()
|
||||
if err != nil {
|
||||
writeStringToPty(ctx, cmd, fmt.Sprintf("error: could not get file stat: %v", err), &outputPos)
|
||||
return
|
||||
}
|
||||
if fileStat.IsDir() {
|
||||
writeStringToPty(ctx, cmd, "Cant copy a directory, try zipping it up first", &outputPos)
|
||||
return
|
||||
}
|
||||
writePk := packet.MakeWriteFilePacket()
|
||||
writePk.ReqId = uuid.New().String()
|
||||
writePk.Path = destPath
|
||||
@ -1337,11 +1349,6 @@ func doCopyLocalFileToRemote(ctx context.Context, cmd *sstore.CmdType, remoteWsh
|
||||
writeStringToPty(ctx, cmd, fmt.Sprintf("Write ready packet error: %v\r\n", err), &outputPos)
|
||||
return
|
||||
}
|
||||
fileStat, err := localFile.Stat()
|
||||
if err != nil {
|
||||
writeStringToPty(ctx, cmd, fmt.Sprintf("error: could not get file stat: %v", err), &outputPos)
|
||||
return
|
||||
}
|
||||
fileSizeBytes := fileStat.Size()
|
||||
bytesWritten := int64(0)
|
||||
lastFileTransferPercentage := float64(0)
|
||||
@ -1434,6 +1441,10 @@ func doCopyRemoteFileToRemote(ctx context.Context, cmd *sstore.CmdType, sourceWs
|
||||
writeStringToPty(ctx, cmd, fmt.Sprintf("Response packet has error: %v\r\n", err), &outputPos)
|
||||
return
|
||||
}
|
||||
if resp.Info.IsDir {
|
||||
writeStringToPty(ctx, cmd, "Cant copy a directory, try zipping it up first", &outputPos)
|
||||
return
|
||||
}
|
||||
fileSizeBytes := resp.Info.Size
|
||||
if fileSizeBytes == 0 {
|
||||
writeStringToPty(ctx, cmd, "Source file does not exist or is empty - exiting\r\n", &outputPos)
|
||||
@ -1525,6 +1536,10 @@ func doCopyLocalFileToLocal(ctx context.Context, cmd *sstore.CmdType, sourcePath
|
||||
writeStringToPty(ctx, cmd, fmt.Sprintf("error getting filestat %v", err), &outputPos)
|
||||
return
|
||||
}
|
||||
if sourceFileStat.IsDir() {
|
||||
writeStringToPty(ctx, cmd, "Cant copy a directory, try zipping it up first", &outputPos)
|
||||
return
|
||||
}
|
||||
fileSizeBytes := sourceFileStat.Size()
|
||||
writeStringToPty(ctx, cmd, fmt.Sprintf("Source File Size: %v\r\n", prettyPrintByteSize(fileSizeBytes)), &outputPos)
|
||||
destFile, err := os.Create(destPath)
|
||||
@ -1571,6 +1586,10 @@ func doCopyRemoteFileToLocal(ctx context.Context, cmd *sstore.CmdType, remoteWsh
|
||||
writeStringToPty(ctx, cmd, fmt.Sprintf("Response packet has error: %v\r\n", err), &outputPos)
|
||||
return
|
||||
}
|
||||
if resp.Info.IsDir {
|
||||
writeStringToPty(ctx, cmd, "Cant copy a directory, try zipping it up first", &outputPos)
|
||||
return
|
||||
}
|
||||
fileSizeBytes := resp.Info.Size
|
||||
if fileSizeBytes == 0 {
|
||||
writeStringToPty(ctx, cmd, "Source file doesn't exist or file is empty - exiting\r\n", &outputPos)
|
||||
@ -1610,6 +1629,7 @@ func doCopyRemoteFileToLocal(ctx context.Context, cmd *sstore.CmdType, remoteWsh
|
||||
fileTransferPercentage = float64(bytesWritten) / float64(fileSizeBytes)
|
||||
|
||||
if fileTransferPercentage-lastFileTransferPercentage > float64(0.05) {
|
||||
log.Printf("updating percentage\n")
|
||||
writeStringToPty(ctx, cmd, "-", &outputPos)
|
||||
lastFileTransferPercentage = fileTransferPercentage
|
||||
}
|
||||
@ -1647,6 +1667,15 @@ func parseCopyFileParam(info string) (remote string, path string, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func fileIsDir(ctx context.Context, ids resolvedIds, remote *ResolvedRemote, filePath string) bool {
|
||||
fileStat, err := getSingleFileStat(ctx, ids, remote, filePath)
|
||||
log.Printf("file is dir: %v", err)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return fileStat.IsDir
|
||||
}
|
||||
|
||||
func CopyFileCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.UpdatePacket, error) {
|
||||
if len(pk.Args) == 0 {
|
||||
return nil, fmt.Errorf("usage: /copyfile [file to copy] local=[path to copy to on local]")
|
||||
@ -1716,9 +1745,10 @@ func CopyFileCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scb
|
||||
sourceFullPath = filepath.Join(sourceCwd, sourcePathWithHome)
|
||||
}
|
||||
}
|
||||
if destPath[len(destPath)-1:] == "/" {
|
||||
if destPath[len(destPath)-1:] == "/" || fileIsDir(ctx, ids, destRemoteId, destPath) {
|
||||
sourceFileName := filepath.Base(sourceFullPath)
|
||||
destPath = filepath.Join(destPath, sourceFileName)
|
||||
log.Printf("destPath: %v", destPath)
|
||||
}
|
||||
destWsh := destRemoteId.Waveshell
|
||||
if destWsh == nil {
|
||||
@ -1746,15 +1776,15 @@ func CopyFileCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scb
|
||||
cmd, err := makeDynCmd(ctx, "copy file", ids, pk.GetRawStr(), *pkTermOpts, nil)
|
||||
writeStringToPty(ctx, cmd, outputStr, &outputPos)
|
||||
if err != nil {
|
||||
// TODO tricky error since the command was a success, but we can't show the output
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("cannot make termopts: %w", err)
|
||||
}
|
||||
update, err := addLineForCmd(ctx, "/copy file", false, ids, cmd, "", nil)
|
||||
pkTermOpts := convertTermOpts(termOpts)
|
||||
cmd, err := makeDynCmd(ctx, "copy file", ids, pk.GetRawStr(), *pkTermOpts, nil)
|
||||
writeStringToPty(ctx, cmd, outputStr, &outputPos)
|
||||
if err != nil {
|
||||
// TODO tricky error since the command was a success, but we can't show the output
|
||||
return nil, err
|
||||
}
|
||||
update.AddUpdate(sstore.InteractiveUpdate(pk.Interactive))
|
||||
if destRemote != ConnectedRemote && destRemoteId != nil && !destRemoteId.RState.IsConnected() {
|
||||
writeStringToPty(ctx, cmd, fmt.Sprintf("Attempting to autoconnect to remote %v\r\n", destRemote), &outputPos)
|
||||
err = destRemoteId.Waveshell.TryAutoConnect()
|
||||
@ -1773,8 +1803,7 @@ func CopyFileCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scb
|
||||
writeStringToPty(ctx, cmd, "Auto connect successful\r\n", &outputPos)
|
||||
}
|
||||
}
|
||||
scbus.MainUpdateBus.DoScreenUpdate(cmd.ScreenId, update)
|
||||
update = scbus.MakeUpdatePacket()
|
||||
update := scbus.MakeUpdatePacket()
|
||||
if destRemote == LocalRemote && sourceRemote == LocalRemote {
|
||||
go doCopyLocalFileToLocal(context.Background(), cmd, sourceFullPath, destFullPath, outputPos)
|
||||
} else if destRemote == LocalRemote && sourceRemote != LocalRemote {
|
||||
@ -5039,6 +5068,10 @@ func SetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.Up
|
||||
func makeStreamFilePk(ids resolvedIds, pk *scpacket.FeCommandPacketType) (*packet.StreamFilePacketType, error) {
|
||||
cwd := ids.Remote.FeState["cwd"]
|
||||
fileArg := pk.Args[0]
|
||||
return makeStreamFilePkFromParams(cwd, fileArg)
|
||||
}
|
||||
|
||||
func makeStreamFilePkFromParams(cwd string, fileArg string) (*packet.StreamFilePacketType, error) {
|
||||
if fileArg == "" {
|
||||
return nil, fmt.Errorf("/view:stat file argument must be set (cannot be empty)")
|
||||
}
|
||||
@ -5050,6 +5083,7 @@ func makeStreamFilePk(ids resolvedIds, pk *scpacket.FeCommandPacketType) (*packe
|
||||
streamPk.Path = filepath.Join(cwd, fileArg)
|
||||
}
|
||||
return streamPk, nil
|
||||
|
||||
}
|
||||
|
||||
func ViewStatCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.UpdatePacket, error) {
|
||||
@ -5060,42 +5094,18 @@ func ViewStatCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scb
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
streamPk, err := makeStreamFilePk(ids, pk)
|
||||
fileArg := pk.Args[0]
|
||||
statPk, streamPk, err := getFileStat(ctx, ids, fileArg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
streamPk.StatOnly = true
|
||||
wsh := ids.Remote.Waveshell
|
||||
iter, err := wsh.StreamFile(ctx, streamPk)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/view:stat error: %v", err)
|
||||
}
|
||||
defer iter.Close()
|
||||
respIf, err := iter.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("/view:stat error getting response: %v", err)
|
||||
}
|
||||
resp, ok := respIf.(*packet.StreamFileResponseType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("/view:stat error, bad response packet type: %T", respIf)
|
||||
}
|
||||
if resp.Error != "" {
|
||||
return nil, fmt.Errorf("/view:stat error: %s", resp.Error)
|
||||
}
|
||||
if resp.Info == nil {
|
||||
return nil, fmt.Errorf("/view:stat error, no file info")
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "path", resp.Info.Name))
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %d\n", "size", resp.Info.Size))
|
||||
modTs := time.UnixMilli(resp.Info.ModTs)
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "path", statPk.Name))
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %d\n", "size", statPk.Size))
|
||||
modTs := statPk.ModTs
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "modts", modTs.Format(TsFormatStr)))
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %v\n", "isdir", resp.Info.IsDir))
|
||||
modeStr := fs.FileMode(resp.Info.Perm).String()
|
||||
if len(modeStr) > 9 {
|
||||
modeStr = modeStr[len(modeStr)-9:]
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "perms", modeStr))
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %v\n", "isdir", statPk.IsDir))
|
||||
buf.WriteString(fmt.Sprintf(" %-15s %s\n", "perms", statPk.ModeStr))
|
||||
update := scbus.MakeUpdatePacket()
|
||||
update.AddUpdate(sstore.InfoMsgType{
|
||||
InfoTitle: fmt.Sprintf("view stat %q", streamPk.Path),
|
||||
@ -5104,6 +5114,62 @@ func ViewStatCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scb
|
||||
return update, nil
|
||||
}
|
||||
|
||||
func getSingleFileStat(ctx context.Context, ids resolvedIds, remote *ResolvedRemote, fileArg string) (*packet.FileStatPacketType, error) {
|
||||
if remote.RemoteCopy.IsLocal() {
|
||||
fileStat, err := os.Stat(fileArg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
statPk := packet.MakeFileStatPacketFromFileInfo(nil, fileStat, "", true)
|
||||
return statPk, nil
|
||||
} else {
|
||||
statPk, _, err := getFileStat(ctx, ids, fileArg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return statPk, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getFileStat(ctx context.Context, ids resolvedIds, fileArg string) (*packet.FileStatPacketType, *packet.StreamFilePacketType, error) {
|
||||
streamPk, err := makeStreamFilePkFromParams(ids.Remote.FeState["cwd"], fileArg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
streamPk.StatOnly = true
|
||||
wsh := ids.Remote.Waveshell
|
||||
iter, err := wsh.StreamFile(ctx, streamPk)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("/view:stat error: %v", err)
|
||||
}
|
||||
defer iter.Close()
|
||||
respIf, err := iter.Next(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("/view:stat error getting response: %v", err)
|
||||
}
|
||||
resp, ok := respIf.(*packet.StreamFileResponseType)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("/view:stat error, bad response packet type: %T", respIf)
|
||||
}
|
||||
if resp.Error != "" {
|
||||
return nil, nil, fmt.Errorf("/view:stat error: %s", resp.Error)
|
||||
}
|
||||
if resp.Info == nil {
|
||||
return nil, nil, fmt.Errorf("/view:stat error, no file info")
|
||||
}
|
||||
statPk := packet.MakeFileStatPacketType()
|
||||
statPk.Name = resp.Info.Name
|
||||
statPk.Size = resp.Info.Size
|
||||
statPk.ModTs = time.UnixMilli(resp.Info.ModTs)
|
||||
statPk.IsDir = resp.Info.IsDir
|
||||
statPk.Perm = resp.Info.Perm
|
||||
statPk.ModeStr = fs.FileMode(statPk.Perm).String()
|
||||
if len(statPk.ModeStr) > 9 {
|
||||
statPk.ModeStr = statPk.ModeStr[len(statPk.ModeStr)-9:]
|
||||
}
|
||||
return statPk, streamPk, nil
|
||||
}
|
||||
|
||||
func ViewTestCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.UpdatePacket, error) {
|
||||
if len(pk.Args) == 0 {
|
||||
return nil, fmt.Errorf("/view:test requires an argument (file name)")
|
||||
@ -5388,6 +5454,209 @@ func MarkdownViewCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
return update, nil
|
||||
}
|
||||
|
||||
func StatDir(ctx context.Context, ids resolvedIds, path string, fileCallback func(pk *packet.FileStatPacketType, done bool, err error)) {
|
||||
statPk, _, err := getFileStat(ctx, ids, path)
|
||||
log.Printf("statPk: %\n", statPk)
|
||||
if err != nil {
|
||||
fileCallback(nil, true, err)
|
||||
return
|
||||
}
|
||||
if !statPk.IsDir {
|
||||
fileCallback(statPk, true, nil)
|
||||
return
|
||||
} else {
|
||||
cwd := ids.Remote.FeState["cwd"]
|
||||
listDirPk := packet.MakeListDirPacket()
|
||||
listDirPk.ReqId = uuid.New().String()
|
||||
if filepath.IsAbs(path) {
|
||||
listDirPk.Path = path
|
||||
} else {
|
||||
listDirPk.Path = filepath.Join(cwd, path)
|
||||
}
|
||||
msh := ids.Remote.Waveshell
|
||||
listDirIter, err := msh.ListDir(ctx, listDirPk)
|
||||
if err != nil {
|
||||
fileCallback(nil, true, err)
|
||||
return
|
||||
}
|
||||
defer listDirIter.Close()
|
||||
for {
|
||||
respIf, err := listDirIter.Next(ctx)
|
||||
if err != nil {
|
||||
fileCallback(nil, true, err)
|
||||
return
|
||||
}
|
||||
resp, ok := respIf.(*packet.FileStatPacketType)
|
||||
if !ok || resp == nil {
|
||||
fileCallback(nil, true, fmt.Errorf("error unmarshalling file stat response type %v %v", resp, respIf))
|
||||
return
|
||||
}
|
||||
if resp.Error != "" {
|
||||
err = fmt.Errorf(resp.Error)
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
fileCallback(resp, resp.Done, err)
|
||||
if resp.Done {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SearchDir(ctx context.Context, ids resolvedIds, path string, searchQuery string, fileCallback func(pk *packet.FileStatPacketType, done bool, err error)) {
|
||||
log.Printf("running searchdir %v %v \n", path, searchQuery)
|
||||
statPk, _, err := getFileStat(ctx, ids, path)
|
||||
if err != nil {
|
||||
fileCallback(nil, true, err)
|
||||
return
|
||||
}
|
||||
if !statPk.IsDir {
|
||||
match, err := regexp.MatchString(searchQuery, statPk.Name)
|
||||
if err != nil {
|
||||
fileCallback(nil, true, err)
|
||||
}
|
||||
if match {
|
||||
fileCallback(statPk, true, nil)
|
||||
} else {
|
||||
fileCallback(nil, true, nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
cwd := ids.Remote.FeState["cwd"]
|
||||
searchDirPk := packet.MakeSearchDirPacket()
|
||||
searchDirPk.ReqId = uuid.New().String()
|
||||
if filepath.IsAbs(path) {
|
||||
searchDirPk.Path = path
|
||||
} else {
|
||||
searchDirPk.Path = filepath.Join(cwd, path)
|
||||
}
|
||||
searchDirPk.SearchQuery = searchQuery
|
||||
msh := ids.Remote.Waveshell
|
||||
searchDirIter, err := msh.SearchDir(ctx, searchDirPk)
|
||||
if err != nil {
|
||||
fileCallback(nil, true, err)
|
||||
return
|
||||
}
|
||||
defer searchDirIter.Close()
|
||||
for {
|
||||
respIf, err := searchDirIter.Next(ctx)
|
||||
log.Printf("got next\n")
|
||||
if err != nil {
|
||||
fileCallback(nil, true, err)
|
||||
return
|
||||
}
|
||||
resp, ok := respIf.(*packet.FileStatPacketType)
|
||||
if !ok || resp == nil {
|
||||
fileCallback(nil, true, fmt.Errorf("error unmarshalling file stat response type %v %v", resp, respIf))
|
||||
return
|
||||
}
|
||||
log.Printf("resp: %v\n", resp)
|
||||
if resp.Error == "none" {
|
||||
fileCallback(nil, true, nil)
|
||||
return
|
||||
} else if resp.Error != "" {
|
||||
err = fmt.Errorf(resp.Error)
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
if resp.Done {
|
||||
return
|
||||
}
|
||||
fileCallback(resp, resp.Done, err)
|
||||
}
|
||||
}
|
||||
|
||||
func SearchDirCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_RemoteConnected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := ids.Remote.FeState["cwd"]
|
||||
if len(pk.Args) > 0 {
|
||||
path = pk.Args[0]
|
||||
}
|
||||
var searchQuery string
|
||||
if len(pk.Args) > 1 {
|
||||
searchQuery = pk.Args[1]
|
||||
} else {
|
||||
return nil, fmt.Errorf("no search query specified - usage /searchdir [path] [query]")
|
||||
}
|
||||
lineId := pk.Kwargs["lineid"]
|
||||
screenId := pk.Kwargs["screenid"]
|
||||
cmd, err := sstore.GetCmdByScreenId(ctx, screenId, lineId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outputPty := resolveBool(pk.Kwargs["outputpty"], false)
|
||||
if outputPty {
|
||||
ids.Remote.Waveshell.ResetDataPos(base.MakeCommandKey(screenId, lineId))
|
||||
err = sstore.ClearCmdPtyFile(ctx, screenId, lineId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error clearing existing pty file: %v", err)
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
var outputPos int64
|
||||
searchCtx := context.Background()
|
||||
SearchDir(searchCtx, ids, path, searchQuery, func(statPk *packet.FileStatPacketType, done bool, err error) {
|
||||
log.Printf("got callback\n")
|
||||
if err != nil {
|
||||
log.Printf("got error: %v\n", err)
|
||||
} else {
|
||||
err = writePacketToPty(searchCtx, cmd, statPk, &outputPos)
|
||||
if err != nil {
|
||||
log.Printf("err writing packet to pty: %v\n", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}()
|
||||
update := scbus.MakeUpdatePacket()
|
||||
return update, nil
|
||||
}
|
||||
|
||||
func ViewDirCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_RemoteConnected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := ids.Remote.FeState["cwd"]
|
||||
if len(pk.Args) > 0 {
|
||||
path = pk.Args[0]
|
||||
}
|
||||
lineId := pk.Kwargs["lineid"]
|
||||
screenId := pk.Kwargs["screenid"]
|
||||
cmd, err := sstore.GetCmdByScreenId(ctx, screenId, lineId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outputPty := resolveBool(pk.Kwargs["outputpty"], false)
|
||||
if outputPty {
|
||||
ids.Remote.Waveshell.ResetDataPos(base.MakeCommandKey(screenId, lineId))
|
||||
err = sstore.ClearCmdPtyFile(ctx, screenId, lineId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error clearing existing pty file: %v", err)
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
var outputPos int64
|
||||
statCtx := context.Background()
|
||||
StatDir(statCtx, ids, path, func(statPk *packet.FileStatPacketType, done bool, err error) {
|
||||
if err != nil {
|
||||
log.Printf("got error: %v\n", err)
|
||||
} else {
|
||||
err = writePacketToPty(statCtx, cmd, statPk, &outputPos)
|
||||
if err != nil {
|
||||
log.Printf("err writing packet to pty: %v\n", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}()
|
||||
update := scbus.MakeUpdatePacket()
|
||||
return update, nil
|
||||
}
|
||||
|
||||
func EditTestCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.UpdatePacket, error) {
|
||||
if len(pk.Args) == 0 {
|
||||
return nil, fmt.Errorf("/edit:test requires an argument (file name)")
|
||||
@ -5982,6 +6251,52 @@ func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sc
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error updating client ai base url: %v", err)
|
||||
}
|
||||
feOpts := clientData.FeOpts
|
||||
feOpts.SudoPwStore = strings.ToLower(sudoPwStoreStr)
|
||||
err = sstore.UpdateClientFeOpts(ctx, feOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error updating client feopts: %v", err)
|
||||
}
|
||||
// clear all sudo pw if turning off
|
||||
if feOpts.SudoPwStore == "off" {
|
||||
for _, proc := range remote.GetRemoteMap() {
|
||||
proc.ClearCachedSudoPw()
|
||||
}
|
||||
}
|
||||
varsUpdated = append(varsUpdated, "sudopwstore")
|
||||
}
|
||||
if sudoPwTimeoutStr, found := pk.Kwargs["sudopwtimeout"]; found {
|
||||
oldPwTimeout := clientData.FeOpts.SudoPwTimeoutMs / 1000 / 60 // ms to minutes
|
||||
if oldPwTimeout == 0 {
|
||||
oldPwTimeout = sstore.DefaultSudoTimeout
|
||||
}
|
||||
newSudoPwTimeout, err := resolveNonNegInt(sudoPwTimeoutStr, sstore.DefaultSudoTimeout)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid sudo pw timeout, must be a number greater than 0: %v", err)
|
||||
}
|
||||
if newSudoPwTimeout == 0 {
|
||||
return nil, fmt.Errorf("invalid sudo pw timeout, must be a number greater than 0")
|
||||
}
|
||||
feOpts := clientData.FeOpts
|
||||
feOpts.SudoPwTimeoutMs = newSudoPwTimeout * 60 * 1000 // minutes to ms
|
||||
err = sstore.UpdateClientFeOpts(ctx, feOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error updating client feopts: %v", err)
|
||||
}
|
||||
for _, proc := range remote.GetRemoteMap() {
|
||||
proc.ChangeSudoTimeout(int64(newSudoPwTimeout - oldPwTimeout))
|
||||
}
|
||||
varsUpdated = append(varsUpdated, "sudopwtimeout")
|
||||
}
|
||||
if sudoPwClearOnSleepStr, found := pk.Kwargs["sudopwclearonsleep"]; found {
|
||||
newSudoPwClearOnSleep := resolveBool(sudoPwClearOnSleepStr, true)
|
||||
feOpts := clientData.FeOpts
|
||||
feOpts.NoSudoPwClearOnSleep = !newSudoPwClearOnSleep
|
||||
err = sstore.UpdateClientFeOpts(ctx, feOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error updating client feopts: %v", err)
|
||||
}
|
||||
varsUpdated = append(varsUpdated, "sudopwclearonsleep")
|
||||
}
|
||||
if aiTimeoutStr, found := CheckOptionAlias(pk.Kwargs, "openaitimeout", "aitimeout"); found {
|
||||
aiTimeout, err := strconv.ParseFloat(aiTimeoutStr, 64)
|
||||
|
@ -1522,6 +1522,18 @@ func (wsh *WaveshellProc) StreamFile(ctx context.Context, streamPk *packet.Strea
|
||||
return wsh.PacketRpcIter(ctx, streamPk)
|
||||
}
|
||||
|
||||
func (msh *WaveshellProc) ListDir(ctx context.Context, listDirPk *packet.ListDirPacketType) (*packet.RpcResponseIter, error) {
|
||||
return msh.PacketRpcIter(ctx, listDirPk)
|
||||
}
|
||||
|
||||
func (msh *WaveshellProc) SearchDir(ctx context.Context, searchDirPk *packet.SearchDirPacketType) (*packet.RpcResponseIter, error) {
|
||||
return msh.PacketRpcIter(ctx, searchDirPk)
|
||||
}
|
||||
|
||||
func (wsh *WaveshellProc) StreamFile(ctx context.Context, streamPk *packet.StreamFilePacketType) (*packet.RpcResponseIter, error) {
|
||||
return wsh.PacketRpcIter(ctx, streamPk)
|
||||
}
|
||||
|
||||
func addScVarsToState(state *packet.ShellState) *packet.ShellState {
|
||||
if state == nil {
|
||||
return nil
|
||||
@ -2210,6 +2222,7 @@ func (wsh *WaveshellProc) PacketRpcIter(ctx context.Context, pk packet.RpcPacket
|
||||
if pk == nil {
|
||||
return nil, fmt.Errorf("PacketRpc passed nil packet")
|
||||
}
|
||||
log.Printf("sending packet: %v", pk)
|
||||
reqId := pk.GetReqId()
|
||||
wsh.ServerProc.Output.RegisterRpcSz(reqId, RpcIterChannelSize)
|
||||
err := wsh.ServerProc.Input.SendPacketCtx(ctx, pk)
|
||||
|
Loading…
Reference in New Issue
Block a user