diff --git a/frontend/app/store/wshrpc.ts b/frontend/app/store/wshrpc.ts index 32be95b00..653820f07 100644 --- a/frontend/app/store/wshrpc.ts +++ b/frontend/app/store/wshrpc.ts @@ -103,6 +103,14 @@ function handleIncomingRpcMessage(msg: RpcMessage, eventHandlerFn: (event: WaveE } return; } + if (msg.command == "message") { + if (msg.data?.oref != null) { + console.log("rpc:message", msg.data?.oref, msg.data?.message); + } else { + console.log("rpc:message", msg.data?.message); + } + return; + } console.log("rpc command not supported", msg); return; diff --git a/frontend/app/store/wshserver.ts b/frontend/app/store/wshserver.ts index c27e5d777..63d57113c 100644 --- a/frontend/app/store/wshserver.ts +++ b/frontend/app/store/wshserver.ts @@ -107,6 +107,11 @@ class WshServerType { return WOS.wshServerRpcHelper_call("remotefileinfo", data, opts); } + // command "remotefilejoin" [call] + RemoteFileJoinCommand(data: string[], opts?: RpcOpts): Promise { + return WOS.wshServerRpcHelper_call("remotefilejoin", data, opts); + } + // command "remotestreamcpudata" [responsestream] RemoteStreamCpuDataCommand(opts?: RpcOpts): AsyncGenerator { return WOS.wshServerRpcHelper_responsestream("remotestreamcpudata", null, opts); diff --git a/frontend/app/view/preview/preview.tsx b/frontend/app/view/preview/preview.tsx index 45682114e..ee979b34a 100644 --- a/frontend/app/view/preview/preview.tsx +++ b/frontend/app/view/preview/preview.tsx @@ -4,6 +4,7 @@ import { TypeAheadModal } from "@/app/modals/typeaheadmodal"; import { ContextMenuModel } from "@/app/store/contextmenu"; import { tryReinjectKey } from "@/app/store/keymodel"; +import { WshServer } from "@/app/store/wshserver"; import { Markdown } from "@/element/markdown"; import { NodeModel } from "@/layout/index"; import { createBlock, globalStore, refocusNode } from "@/store/global"; @@ -42,6 +43,13 @@ const SpecializedViewMap: { [view: string]: ({ model }: SpecializedViewProps) => directory: DirectoryPreview, }; +function makeConnRoute(conn: string): string { + if (util.isBlank(conn)) { + return "conn:local"; + } + return "conn:" + conn; +} + function isTextFile(mimeType: string): boolean { if (mimeType == null) { return false; @@ -484,13 +492,18 @@ export class PreviewModel implements ViewModel { this.updateOpenFileModalAndError(false); return true; } - const newPath = fileInfo.dir + "/" + filePath; - const conn = globalStore.get(this.connection) ?? ""; - const newFileInfo = await services.FileService.StatFile(conn, newPath); - this.updateOpenFileModalAndError(false); - this.goHistory(newFileInfo.path); - refocusNode(this.blockId); - return true; + const conn = globalStore.get(this.connection); + try { + const newFileInfo = await WshServer.RemoteFileJoinCommand([fileInfo.dir, filePath], { + route: makeConnRoute(conn), + }); + this.updateOpenFileModalAndError(false); + this.goHistory(newFileInfo.path); + refocusNode(this.blockId); + } catch (e) { + globalStore.set(this.openFileError, e.message); + console.error("Error opening file", fileInfo.dir, filePath, e); + } } isSpecializedView(sv: string): boolean { diff --git a/pkg/wshrpc/wshclient/wshclient.go b/pkg/wshrpc/wshclient/wshclient.go index b2adb1401..cfc65028d 100644 --- a/pkg/wshrpc/wshclient/wshclient.go +++ b/pkg/wshrpc/wshclient/wshclient.go @@ -132,6 +132,12 @@ func RemoteFileInfoCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) return resp, err } +// command "remotefilejoin", wshserver.RemoteFileJoinCommand +func RemoteFileJoinCommand(w *wshutil.WshRpc, data []string, opts *wshrpc.RpcOpts) (*wshrpc.FileInfo, error) { + resp, err := sendRpcRequestCallHelper[*wshrpc.FileInfo](w, "remotefilejoin", data, opts) + return resp, err +} + // command "remotestreamcpudata", wshserver.RemoteStreamCpuDataCommand func RemoteStreamCpuDataCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[wshrpc.TimeSeriesData] { return sendRpcRequestResponseStreamHelper[wshrpc.TimeSeriesData](w, "remotestreamcpudata", nil, opts) diff --git a/pkg/wshrpc/wshremote/wshremote.go b/pkg/wshrpc/wshremote/wshremote.go index e02baa97e..28c6a6280 100644 --- a/pkg/wshrpc/wshremote/wshremote.go +++ b/pkg/wshrpc/wshremote/wshremote.go @@ -279,6 +279,27 @@ func (*ServerImpl) fileInfoInternal(path string, extended bool) (*wshrpc.FileInf return rtn, nil } +func resolvePaths(paths []string) string { + if len(paths) == 0 { + return wavebase.ExpandHomeDir("~") + } + var rtnPath = wavebase.ExpandHomeDir(paths[0]) + for _, path := range paths[1:] { + path = wavebase.ExpandHomeDir(path) + if filepath.IsAbs(path) { + rtnPath = path + continue + } + rtnPath = filepath.Join(rtnPath, path) + } + return rtnPath +} + +func (impl *ServerImpl) RemoteFileJoinCommand(ctx context.Context, paths []string) (*wshrpc.FileInfo, error) { + rtnPath := resolvePaths(paths) + return impl.fileInfoInternal(rtnPath, true) +} + func (impl *ServerImpl) RemoteFileInfoCommand(ctx context.Context, path string) (*wshrpc.FileInfo, error) { return impl.fileInfoInternal(path, true) } diff --git a/pkg/wshrpc/wshrpctypes.go b/pkg/wshrpc/wshrpctypes.go index b26b8723b..4c780c4d3 100644 --- a/pkg/wshrpc/wshrpctypes.go +++ b/pkg/wshrpc/wshrpctypes.go @@ -62,6 +62,7 @@ const ( Command_RemoteFileInfo = "remotefileinfo" Command_RemoteWriteFile = "remotewritefile" Command_RemoteFileDelete = "remotefiledelete" + Command_RemoteFileJoiin = "remotefilejoin" ) type RespOrErrorUnion[T any] struct { @@ -105,6 +106,7 @@ type WshRpcInterface interface { RemoteFileInfoCommand(ctx context.Context, path string) (*FileInfo, error) RemoteFileDeleteCommand(ctx context.Context, path string) error RemoteWriteFileCommand(ctx context.Context, data CommandRemoteWriteFileData) error + RemoteFileJoinCommand(ctx context.Context, paths []string) (*FileInfo, error) RemoteStreamCpuDataCommand(ctx context.Context) chan RespOrErrorUnion[TimeSeriesData] } diff --git a/pkg/wshutil/wshrouter.go b/pkg/wshutil/wshrouter.go index ccb849451..af5a5ef03 100644 --- a/pkg/wshutil/wshrouter.go +++ b/pkg/wshutil/wshrouter.go @@ -111,12 +111,11 @@ func (router *WshRouter) handleNoRoute(msg RpcMessage) { } // send error response response := RpcMessage{ - Route: msg.Source, ResId: msg.ReqId, Error: nrErr.Error(), } respBytes, _ := json.Marshal(response) - router.InputCh <- msgAndRoute{msgBytes: respBytes, fromRouteId: SysRoute} + router.sendRoutedMessage(respBytes, msg.Source) } func (router *WshRouter) registerRouteInfo(rpcId string, sourceRouteId string, destRouteId string) {