mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
checkpoint on domain sockets + update background colors + transparency (#160)
This commit is contained in:
@@ -8,11 +8,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/service"
|
"github.com/wavetermdev/thenextwave/pkg/service"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/tsgen"
|
"github.com/wavetermdev/thenextwave/pkg/tsgen"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshrpc/wshserver"
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func generateTypesFile(tsTypesMap map[reflect.Type]string) error {
|
func generateTypesFile(tsTypesMap map[reflect.Type]string) error {
|
||||||
@@ -43,6 +44,10 @@ func generateTypesFile(tsTypesMap map[reflect.Type]string) error {
|
|||||||
return iname < jname
|
return iname < jname
|
||||||
})
|
})
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
|
// don't output generic types
|
||||||
|
if strings.Index(key.Name(), "[") != -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
tsCode := tsTypesMap[key]
|
tsCode := tsTypesMap[key]
|
||||||
istr := utilfn.IndentString(" ", tsCode)
|
istr := utilfn.IndentString(" ", tsCode)
|
||||||
fmt.Fprint(fd, istr)
|
fmt.Fprint(fd, istr)
|
||||||
@@ -79,16 +84,17 @@ func generateWshServerFile(tsTypeMap map[reflect.Type]string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
|
declMap := wshrpc.GenerateWshCommandDeclMap()
|
||||||
fmt.Fprintf(os.Stderr, "generating wshserver file to %s\n", fd.Name())
|
fmt.Fprintf(os.Stderr, "generating wshserver file to %s\n", fd.Name())
|
||||||
fmt.Fprintf(fd, "// Copyright 2024, Command Line Inc.\n")
|
fmt.Fprintf(fd, "// Copyright 2024, Command Line Inc.\n")
|
||||||
fmt.Fprintf(fd, "// SPDX-License-Identifier: Apache-2.0\n\n")
|
fmt.Fprintf(fd, "// SPDX-License-Identifier: Apache-2.0\n\n")
|
||||||
fmt.Fprintf(fd, "// generated by cmd/generate/main-generate.go\n\n")
|
fmt.Fprintf(fd, "// generated by cmd/generate/main-generate.go\n\n")
|
||||||
fmt.Fprintf(fd, "import * as WOS from \"./wos\";\n\n")
|
fmt.Fprintf(fd, "import * as WOS from \"./wos\";\n\n")
|
||||||
orderedKeys := utilfn.GetOrderedMapKeys(wshserver.WshServerCommandToDeclMap)
|
orderedKeys := utilfn.GetOrderedMapKeys(declMap)
|
||||||
fmt.Fprintf(fd, "// WshServerCommandToDeclMap\n")
|
fmt.Fprintf(fd, "// WshServerCommandToDeclMap\n")
|
||||||
fmt.Fprintf(fd, "class WshServerType {\n")
|
fmt.Fprintf(fd, "class WshServerType {\n")
|
||||||
for _, methodDecl := range orderedKeys {
|
for _, methodDecl := range orderedKeys {
|
||||||
methodDecl := wshserver.WshServerCommandToDeclMap[methodDecl]
|
methodDecl := declMap[methodDecl]
|
||||||
methodStr := tsgen.GenerateWshServerMethod(methodDecl, tsTypeMap)
|
methodStr := tsgen.GenerateWshServerMethod(methodDecl, tsTypeMap)
|
||||||
fmt.Fprint(fd, methodStr)
|
fmt.Fprint(fd, methodStr)
|
||||||
fmt.Fprintf(fd, "\n")
|
fmt.Fprintf(fd, "\n")
|
||||||
|
|||||||
@@ -8,11 +8,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshrpc/wshserver"
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func genMethod_ResponseStream(fd *os.File, methodDecl *wshserver.WshServerMethodDecl) {
|
func genMethod_ResponseStream(fd *os.File, methodDecl *wshrpc.WshRpcMethodDecl) {
|
||||||
fmt.Fprintf(fd, "// command %q, wshserver.%s\n", methodDecl.Command, methodDecl.MethodName)
|
fmt.Fprintf(fd, "// command %q, wshserver.%s\n", methodDecl.Command, methodDecl.MethodName)
|
||||||
var dataType string
|
var dataType string
|
||||||
dataVarName := "nil"
|
dataVarName := "nil"
|
||||||
@@ -29,7 +28,7 @@ func genMethod_ResponseStream(fd *os.File, methodDecl *wshserver.WshServerMethod
|
|||||||
fmt.Fprintf(fd, "}\n\n")
|
fmt.Fprintf(fd, "}\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func genMethod_Call(fd *os.File, methodDecl *wshserver.WshServerMethodDecl) {
|
func genMethod_Call(fd *os.File, methodDecl *wshrpc.WshRpcMethodDecl) {
|
||||||
fmt.Fprintf(fd, "// command %q, wshserver.%s\n", methodDecl.Command, methodDecl.MethodName)
|
fmt.Fprintf(fd, "// command %q, wshserver.%s\n", methodDecl.Command, methodDecl.MethodName)
|
||||||
var dataType string
|
var dataType string
|
||||||
dataVarName := "nil"
|
dataVarName := "nil"
|
||||||
@@ -70,14 +69,14 @@ func main() {
|
|||||||
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/wshutil\"\n")
|
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/wshutil\"\n")
|
||||||
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/wshrpc\"\n")
|
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/wshrpc\"\n")
|
||||||
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/waveobj\"\n")
|
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/waveobj\"\n")
|
||||||
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/waveai\"\n")
|
|
||||||
fmt.Fprintf(fd, ")\n\n")
|
fmt.Fprintf(fd, ")\n\n")
|
||||||
|
|
||||||
for _, key := range utilfn.GetOrderedMapKeys(wshserver.WshServerCommandToDeclMap) {
|
wshDeclMap := wshrpc.GenerateWshCommandDeclMap()
|
||||||
methodDecl := wshserver.WshServerCommandToDeclMap[key]
|
for _, key := range utilfn.GetOrderedMapKeys(wshDeclMap) {
|
||||||
if methodDecl.CommandType == wshutil.RpcType_ResponseStream {
|
methodDecl := wshDeclMap[key]
|
||||||
|
if methodDecl.CommandType == wshrpc.RpcType_ResponseStream {
|
||||||
genMethod_ResponseStream(fd, methodDecl)
|
genMethod_ResponseStream(fd, methodDecl)
|
||||||
} else if methodDecl.CommandType == wshutil.RpcType_Call {
|
} else if methodDecl.CommandType == wshrpc.RpcType_Call {
|
||||||
genMethod_Call(fd, methodDecl)
|
genMethod_Call(fd, methodDecl)
|
||||||
} else {
|
} else {
|
||||||
panic("unsupported command type " + methodDecl.CommandType)
|
panic("unsupported command type " + methodDecl.CommandType)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func runReadFile(cmd *cobra.Command, args []string) {
|
|||||||
fmt.Fprintf(os.Stderr, "error resolving oref: %v\r\n", err)
|
fmt.Fprintf(os.Stderr, "error resolving oref: %v\r\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp64, err := wshclient.ReadFile(RpcClient, wshrpc.CommandFileData{ZoneId: fullORef.OID, FileName: args[1]}, &wshrpc.WshRpcCommandOpts{Timeout: 5000})
|
resp64, err := wshclient.FileReadCommand(RpcClient, wshrpc.CommandFileData{ZoneId: fullORef.OID, FileName: args[1]}, &wshrpc.WshRpcCommandOpts{Timeout: 5000})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error reading file: %v\r\n", err)
|
fmt.Fprintf(os.Stderr, "error reading file: %v\r\n", err)
|
||||||
return
|
return
|
||||||
|
|||||||
+59
-26
@@ -34,6 +34,7 @@ const waveSrvReady: Promise<boolean> = new Promise((resolve, _) => {
|
|||||||
});
|
});
|
||||||
let globalIsQuitting = false;
|
let globalIsQuitting = false;
|
||||||
let globalIsStarting = true;
|
let globalIsStarting = true;
|
||||||
|
let globalIsRelaunching = false;
|
||||||
|
|
||||||
const isDev = !electronApp.isPackaged;
|
const isDev = !electronApp.isPackaged;
|
||||||
const isDevVite = isDev && process.env.ELECTRON_RENDERER_URL;
|
const isDevVite = isDev && process.env.ELECTRON_RENDERER_URL;
|
||||||
@@ -214,7 +215,8 @@ async function handleWSEvent(evtMsg: WSEventType) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const clientData = await services.ClientService.GetClientData();
|
const clientData = await services.ClientService.GetClientData();
|
||||||
const newWin = createBrowserWindow(clientData.oid, windowData);
|
const settings = await services.FileService.GetSettingsConfig();
|
||||||
|
const newWin = createBrowserWindow(clientData.oid, windowData, settings);
|
||||||
await newWin.readyPromise;
|
await newWin.readyPromise;
|
||||||
newWin.show();
|
newWin.show();
|
||||||
} else if (evtMsg.eventtype == "electron:closewindow") {
|
} else if (evtMsg.eventtype == "electron:closewindow") {
|
||||||
@@ -290,7 +292,11 @@ function shFrameNavHandler(event: Electron.Event<Electron.WebContentsWillFrameNa
|
|||||||
|
|
||||||
// note, this does not *show* the window.
|
// note, this does not *show* the window.
|
||||||
// to show, await win.readyPromise and then win.show()
|
// to show, await win.readyPromise and then win.show()
|
||||||
function createBrowserWindow(clientId: string, waveWindow: WaveWindow): WaveBrowserWindow {
|
function createBrowserWindow(
|
||||||
|
clientId: string,
|
||||||
|
waveWindow: WaveWindow,
|
||||||
|
settings: SettingsConfigType
|
||||||
|
): WaveBrowserWindow {
|
||||||
let winBounds = {
|
let winBounds = {
|
||||||
x: waveWindow.pos.x,
|
x: waveWindow.pos.x,
|
||||||
y: waveWindow.pos.y,
|
y: waveWindow.pos.y,
|
||||||
@@ -298,7 +304,7 @@ function createBrowserWindow(clientId: string, waveWindow: WaveWindow): WaveBrow
|
|||||||
height: waveWindow.winsize.height,
|
height: waveWindow.winsize.height,
|
||||||
};
|
};
|
||||||
winBounds = ensureBoundsAreVisible(winBounds);
|
winBounds = ensureBoundsAreVisible(winBounds);
|
||||||
const bwin = new electron.BrowserWindow({
|
const winOpts: Electron.BrowserWindowConstructorOptions = {
|
||||||
titleBarStyle: "hiddenInset",
|
titleBarStyle: "hiddenInset",
|
||||||
x: winBounds.x,
|
x: winBounds.x,
|
||||||
y: winBounds.y,
|
y: winBounds.y,
|
||||||
@@ -316,8 +322,14 @@ function createBrowserWindow(clientId: string, waveWindow: WaveWindow): WaveBrow
|
|||||||
},
|
},
|
||||||
show: false,
|
show: false,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
backgroundColor: "#000000",
|
};
|
||||||
});
|
const isTransparent = settings?.window?.transparent ?? true;
|
||||||
|
if (isTransparent) {
|
||||||
|
winOpts.transparent = true;
|
||||||
|
} else {
|
||||||
|
winOpts.backgroundColor = "#222222";
|
||||||
|
}
|
||||||
|
const bwin = new electron.BrowserWindow(winOpts);
|
||||||
(bwin as any).waveWindowId = waveWindow.oid;
|
(bwin as any).waveWindowId = waveWindow.oid;
|
||||||
let readyResolve: (value: void) => void;
|
let readyResolve: (value: void) => void;
|
||||||
(bwin as any).readyPromise = new Promise((resolve, _) => {
|
(bwin as any).readyPromise = new Promise((resolve, _) => {
|
||||||
@@ -519,7 +531,8 @@ electron.ipcMain.on("getEnv", (event, varName) => {
|
|||||||
async function createNewWaveWindow() {
|
async function createNewWaveWindow() {
|
||||||
const clientData = await services.ClientService.GetClientData();
|
const clientData = await services.ClientService.GetClientData();
|
||||||
const newWindow = await services.ClientService.MakeWindow();
|
const newWindow = await services.ClientService.MakeWindow();
|
||||||
const newBrowserWindow = createBrowserWindow(clientData.oid, newWindow);
|
const settings = await services.FileService.GetSettingsConfig();
|
||||||
|
const newBrowserWindow = createBrowserWindow(clientData.oid, newWindow, settings);
|
||||||
newBrowserWindow.show();
|
newBrowserWindow.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,6 +629,12 @@ function makeAppMenu() {
|
|||||||
{
|
{
|
||||||
role: "forceReload",
|
role: "forceReload",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "Relaunch All Windows",
|
||||||
|
click: () => {
|
||||||
|
relaunchBrowserWindows();
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
role: "toggleDevTools",
|
role: "toggleDevTools",
|
||||||
},
|
},
|
||||||
@@ -663,6 +682,9 @@ function makeAppMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
electronApp.on("window-all-closed", () => {
|
electronApp.on("window-all-closed", () => {
|
||||||
|
if (globalIsRelaunching) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (unamePlatform !== "darwin") {
|
if (unamePlatform !== "darwin") {
|
||||||
electronApp.quit();
|
electronApp.quit();
|
||||||
}
|
}
|
||||||
@@ -857,6 +879,36 @@ async function configureAutoUpdater() {
|
|||||||
}
|
}
|
||||||
// ====== AUTO-UPDATER ====== //
|
// ====== AUTO-UPDATER ====== //
|
||||||
|
|
||||||
|
async function relaunchBrowserWindows() {
|
||||||
|
globalIsRelaunching = true;
|
||||||
|
const windows = electron.BrowserWindow.getAllWindows();
|
||||||
|
for (const window of windows) {
|
||||||
|
window.removeAllListeners();
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
globalIsRelaunching = false;
|
||||||
|
|
||||||
|
const clientData = await services.ClientService.GetClientData();
|
||||||
|
const settings = await services.FileService.GetSettingsConfig();
|
||||||
|
const wins: WaveBrowserWindow[] = [];
|
||||||
|
for (const windowId of clientData.windowids.slice().reverse()) {
|
||||||
|
const windowData: WaveWindow = (await services.ObjectService.GetObject("window:" + windowId)) as WaveWindow;
|
||||||
|
if (windowData == null) {
|
||||||
|
services.WindowService.CloseWindow(windowId).catch((e) => {
|
||||||
|
/* ignore */
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const win = createBrowserWindow(clientData.oid, windowData, settings);
|
||||||
|
wins.push(win);
|
||||||
|
}
|
||||||
|
for (const win of wins) {
|
||||||
|
await win.readyPromise;
|
||||||
|
console.log("show", win.waveWindowId);
|
||||||
|
win.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function appMain() {
|
async function appMain() {
|
||||||
const startTs = Date.now();
|
const startTs = Date.now();
|
||||||
const instanceLock = electronApp.requestSingleInstanceLock();
|
const instanceLock = electronApp.requestSingleInstanceLock();
|
||||||
@@ -877,27 +929,8 @@ async function appMain() {
|
|||||||
}
|
}
|
||||||
const ready = await waveSrvReady;
|
const ready = await waveSrvReady;
|
||||||
console.log("wavesrv ready signal received", ready, Date.now() - startTs, "ms");
|
console.log("wavesrv ready signal received", ready, Date.now() - startTs, "ms");
|
||||||
console.log("get client data");
|
|
||||||
const clientData = await services.ClientService.GetClientData();
|
|
||||||
console.log("client data ready");
|
|
||||||
await electronApp.whenReady();
|
await electronApp.whenReady();
|
||||||
const wins: WaveBrowserWindow[] = [];
|
relaunchBrowserWindows();
|
||||||
for (const windowId of clientData.windowids.slice().reverse()) {
|
|
||||||
const windowData: WaveWindow = (await services.ObjectService.GetObject("window:" + windowId)) as WaveWindow;
|
|
||||||
if (windowData == null) {
|
|
||||||
services.WindowService.CloseWindow(windowId).catch((e) => {
|
|
||||||
/* ignore */
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const win = createBrowserWindow(clientData.oid, windowData);
|
|
||||||
wins.push(win);
|
|
||||||
}
|
|
||||||
for (const win of wins) {
|
|
||||||
await win.readyPromise;
|
|
||||||
console.log("show", win.waveWindowId);
|
|
||||||
win.show();
|
|
||||||
}
|
|
||||||
configureAutoUpdater();
|
configureAutoUpdater();
|
||||||
globalIsStarting = false;
|
globalIsStarting = false;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ body {
|
|||||||
font: var(--base-font);
|
font: var(--base-font);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
-webkit-font-smoothing: auto;
|
-webkit-font-smoothing: auto;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
transform: translateZ(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar {
|
*::-webkit-scrollbar {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { HTML5Backend } from "react-dnd-html5-backend";
|
|||||||
import { CenteredDiv } from "./element/quickelems";
|
import { CenteredDiv } from "./element/quickelems";
|
||||||
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import Color from "color";
|
||||||
import "overlayscrollbars/overlayscrollbars.css";
|
import "overlayscrollbars/overlayscrollbars.css";
|
||||||
import "./app.less";
|
import "./app.less";
|
||||||
|
|
||||||
@@ -200,6 +201,31 @@ function switchBlock(tabId: string, offsetX: number, offsetY: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function AppSettingsUpdater() {
|
||||||
|
const settings = jotai.useAtomValue(atoms.settingsConfigAtom);
|
||||||
|
React.useEffect(() => {
|
||||||
|
let isTransparent = settings?.window?.transparent ?? true;
|
||||||
|
let opacity = util.boundNumber(settings?.window?.opacity ?? 0.8, 0, 1);
|
||||||
|
let baseBgColor = settings?.window?.bgcolor;
|
||||||
|
console.log("window settings", settings.window);
|
||||||
|
|
||||||
|
if (isTransparent) {
|
||||||
|
document.body.classList.add("is-transparent");
|
||||||
|
const rootStyles = getComputedStyle(document.documentElement);
|
||||||
|
if (baseBgColor == null) {
|
||||||
|
baseBgColor = rootStyles.getPropertyValue("--main-bg-color").trim();
|
||||||
|
}
|
||||||
|
const color = new Color(baseBgColor);
|
||||||
|
const rgbaColor = color.alpha(opacity).string();
|
||||||
|
document.body.style.backgroundColor = rgbaColor;
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove("is-transparent");
|
||||||
|
document.body.style.opacity = null;
|
||||||
|
}
|
||||||
|
}, [settings?.window]);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const AppInner = () => {
|
const AppInner = () => {
|
||||||
const client = jotai.useAtomValue(atoms.client);
|
const client = jotai.useAtomValue(atoms.client);
|
||||||
const windowData = jotai.useAtomValue(atoms.waveWindow);
|
const windowData = jotai.useAtomValue(atoms.waveWindow);
|
||||||
@@ -251,6 +277,7 @@ const AppInner = () => {
|
|||||||
const isFullScreen = jotai.useAtomValue(atoms.isFullScreen);
|
const isFullScreen = jotai.useAtomValue(atoms.isFullScreen);
|
||||||
return (
|
return (
|
||||||
<div className={clsx("mainapp", PLATFORM, { fullscreen: isFullScreen })} onContextMenu={handleContextMenu}>
|
<div className={clsx("mainapp", PLATFORM, { fullscreen: isFullScreen })} onContextMenu={handleContextMenu}>
|
||||||
|
<AppSettingsUpdater />
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<Workspace />
|
<Workspace />
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
|
||||||
.block-frame-default-inner {
|
.block-frame-default-inner {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: var(--block-bg-color);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|||||||
@@ -7,14 +7,19 @@ import * as WOS from "./wos";
|
|||||||
|
|
||||||
// WshServerCommandToDeclMap
|
// WshServerCommandToDeclMap
|
||||||
class WshServerType {
|
class WshServerType {
|
||||||
// command "controller:input" [call]
|
// command "authenticate" [call]
|
||||||
BlockInputCommand(data: CommandBlockInputData, opts?: WshRpcCommandOpts): Promise<void> {
|
AuthenticateCommand(data: string, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
return WOS.wshServerRpcHelper_call("controller:input", data, opts);
|
return WOS.wshServerRpcHelper_call("authenticate", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "controller:restart" [call]
|
// command "controllerinput" [call]
|
||||||
BlockRestartCommand(data: CommandBlockRestartData, opts?: WshRpcCommandOpts): Promise<void> {
|
ControllerInputCommand(data: CommandBlockInputData, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
return WOS.wshServerRpcHelper_call("controller:restart", data, opts);
|
return WOS.wshServerRpcHelper_call("controllerinput", data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "controllerrestart" [call]
|
||||||
|
ControllerRestartCommand(data: CommandBlockRestartData, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
|
return WOS.wshServerRpcHelper_call("controllerrestart", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "createblock" [call]
|
// command "createblock" [call]
|
||||||
@@ -27,24 +32,49 @@ class WshServerType {
|
|||||||
return WOS.wshServerRpcHelper_call("deleteblock", data, opts);
|
return WOS.wshServerRpcHelper_call("deleteblock", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "file:append" [call]
|
// command "eventpublish" [call]
|
||||||
AppendFileCommand(data: CommandFileData, opts?: WshRpcCommandOpts): Promise<void> {
|
EventPublishCommand(data: WaveEvent, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
return WOS.wshServerRpcHelper_call("file:append", data, opts);
|
return WOS.wshServerRpcHelper_call("eventpublish", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "file:appendijson" [call]
|
// command "eventrecv" [call]
|
||||||
AppendIJsonCommand(data: CommandAppendIJsonData, opts?: WshRpcCommandOpts): Promise<void> {
|
EventRecvCommand(data: WaveEvent, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
return WOS.wshServerRpcHelper_call("file:appendijson", data, opts);
|
return WOS.wshServerRpcHelper_call("eventrecv", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "file:read" [call]
|
// command "eventsub" [call]
|
||||||
ReadFile(data: CommandFileData, opts?: WshRpcCommandOpts): Promise<string> {
|
EventSubCommand(data: SubscriptionRequest, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
return WOS.wshServerRpcHelper_call("file:read", data, opts);
|
return WOS.wshServerRpcHelper_call("eventsub", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "file:write" [call]
|
// command "eventunsub" [call]
|
||||||
WriteFile(data: CommandFileData, opts?: WshRpcCommandOpts): Promise<void> {
|
EventUnsubCommand(data: SubscriptionRequest, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
return WOS.wshServerRpcHelper_call("file:write", data, opts);
|
return WOS.wshServerRpcHelper_call("eventunsub", data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "eventunsuball" [call]
|
||||||
|
EventUnsubAllCommand(opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
|
return WOS.wshServerRpcHelper_call("eventunsuball", null, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "fileappend" [call]
|
||||||
|
FileAppendCommand(data: CommandFileData, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
|
return WOS.wshServerRpcHelper_call("fileappend", data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "fileappendijson" [call]
|
||||||
|
FileAppendIJsonCommand(data: CommandAppendIJsonData, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
|
return WOS.wshServerRpcHelper_call("fileappendijson", data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "fileread" [call]
|
||||||
|
FileReadCommand(data: CommandFileData, opts?: WshRpcCommandOpts): Promise<string> {
|
||||||
|
return WOS.wshServerRpcHelper_call("fileread", data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "filewrite" [call]
|
||||||
|
FileWriteCommand(data: CommandFileData, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
|
return WOS.wshServerRpcHelper_call("filewrite", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "getmeta" [call]
|
// command "getmeta" [call]
|
||||||
@@ -68,18 +98,18 @@ class WshServerType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// command "setview" [call]
|
// command "setview" [call]
|
||||||
BlockSetViewCommand(data: CommandBlockSetViewData, opts?: WshRpcCommandOpts): Promise<void> {
|
SetViewCommand(data: CommandBlockSetViewData, opts?: WshRpcCommandOpts): Promise<void> {
|
||||||
return WOS.wshServerRpcHelper_call("setview", data, opts);
|
return WOS.wshServerRpcHelper_call("setview", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "stream:waveai" [responsestream]
|
// command "streamtest" [responsestream]
|
||||||
RespStreamWaveAi(data: OpenAiStreamRequest, opts?: WshRpcCommandOpts): AsyncGenerator<OpenAIPacketType, void, boolean> {
|
StreamTestCommand(opts?: WshRpcCommandOpts): AsyncGenerator<number, void, boolean> {
|
||||||
return WOS.wshServerRpcHelper_responsestream("stream:waveai", data, opts);
|
return WOS.wshServerRpcHelper_responsestream("streamtest", null, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "streamtest" [responsestream]
|
// command "streamwaveai" [responsestream]
|
||||||
RespStreamTest(opts?: WshRpcCommandOpts): AsyncGenerator<number, void, boolean> {
|
StreamWaveAiCommand(data: OpenAiStreamRequest, opts?: WshRpcCommandOpts): AsyncGenerator<OpenAIPacketType, void, boolean> {
|
||||||
return WOS.wshServerRpcHelper_responsestream("streamtest", null, opts);
|
return WOS.wshServerRpcHelper_responsestream("streamwaveai", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
--title-font-size: 18px;
|
--title-font-size: 18px;
|
||||||
--secondary-text-color: rgb(195, 200, 194);
|
--secondary-text-color: rgb(195, 200, 194);
|
||||||
--grey-text-color: #666;
|
--grey-text-color: #666;
|
||||||
--main-bg-color: #454444;
|
--main-bg-color: rgb(34, 34, 34);
|
||||||
--border-color: #333333;
|
--border-color: #333333;
|
||||||
--base-font: normal 14px / normal "Inter", sans-serif;
|
--base-font: normal 14px / normal "Inter", sans-serif;
|
||||||
--fixed-font: normal 12px / normal "Hack", monospace;
|
--fixed-font: normal 12px / normal "Hack", monospace;
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
--warning-color: rgb(224, 185, 86);
|
--warning-color: rgb(224, 185, 86);
|
||||||
--success-color: rgb(78, 154, 6);
|
--success-color: rgb(78, 154, 6);
|
||||||
--hover-bg-color: rgba(255, 255, 255, 0.1);
|
--hover-bg-color: rgba(255, 255, 255, 0.1);
|
||||||
--block-bg-color: rgba(255, 255, 255, 0.05);
|
--block-bg-color: rgba(0, 0, 0, 0.5);
|
||||||
|
|
||||||
/* scrollbar colors */
|
/* scrollbar colors */
|
||||||
--scrollbar-background-color: transparent;
|
--scrollbar-background-color: transparent;
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
|||||||
}
|
}
|
||||||
if (shellProcStatusRef.current != "running" && keyutil.checkKeyPressed(waveEvent, "Enter")) {
|
if (shellProcStatusRef.current != "running" && keyutil.checkKeyPressed(waveEvent, "Enter")) {
|
||||||
// restart
|
// restart
|
||||||
WshServer.BlockRestartCommand({ blockid: blockId });
|
WshServer.ControllerRestartCommand({ blockid: blockId });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,7 +263,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const b64data = btoa(asciiVal);
|
const b64data = btoa(asciiVal);
|
||||||
WshServer.BlockInputCommand({ blockid: blockId, inputdata64: b64data });
|
WshServer.ControllerInputCommand({ blockid: blockId, inputdata64: b64data });
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class TermWrap {
|
|||||||
|
|
||||||
handleTermData(data: string) {
|
handleTermData(data: string) {
|
||||||
const b64data = btoa(data);
|
const b64data = btoa(data);
|
||||||
WshServer.BlockInputCommand({ blockid: this.blockId, inputdata64: b64data });
|
WshServer.ControllerInputCommand({ blockid: this.blockId, inputdata64: b64data });
|
||||||
}
|
}
|
||||||
|
|
||||||
addFocusListener(focusFn: () => void) {
|
addFocusListener(focusFn: () => void) {
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ export class WaveAiModel implements ViewModel {
|
|||||||
opts: opts,
|
opts: opts,
|
||||||
prompt: prompt,
|
prompt: prompt,
|
||||||
};
|
};
|
||||||
const aiGen = WshServer.RespStreamWaveAi(beMsg);
|
const aiGen = WshServer.StreamWaveAiCommand(beMsg);
|
||||||
let temp = async () => {
|
let temp = async () => {
|
||||||
let fullMsg = "";
|
let fullMsg = "";
|
||||||
for await (const msg of aiGen) {
|
for await (const msg of aiGen) {
|
||||||
|
|||||||
Vendored
+28
-5
@@ -187,7 +187,7 @@ declare global {
|
|||||||
// waveobj.ORef
|
// waveobj.ORef
|
||||||
type ORef = string;
|
type ORef = string;
|
||||||
|
|
||||||
// waveai.OpenAIOptsType
|
// wshrpc.OpenAIOptsType
|
||||||
type OpenAIOptsType = {
|
type OpenAIOptsType = {
|
||||||
model: string;
|
model: string;
|
||||||
apitoken: string;
|
apitoken: string;
|
||||||
@@ -197,7 +197,7 @@ declare global {
|
|||||||
timeout?: number;
|
timeout?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
// waveai.OpenAIPacketType
|
// wshrpc.OpenAIPacketType
|
||||||
type OpenAIPacketType = {
|
type OpenAIPacketType = {
|
||||||
type: string;
|
type: string;
|
||||||
model?: string;
|
model?: string;
|
||||||
@@ -209,21 +209,21 @@ declare global {
|
|||||||
error?: string;
|
error?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// waveai.OpenAIPromptMessageType
|
// wshrpc.OpenAIPromptMessageType
|
||||||
type OpenAIPromptMessageType = {
|
type OpenAIPromptMessageType = {
|
||||||
role: string;
|
role: string;
|
||||||
content: string;
|
content: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// waveai.OpenAIUsageType
|
// wshrpc.OpenAIUsageType
|
||||||
type OpenAIUsageType = {
|
type OpenAIUsageType = {
|
||||||
prompt_tokens?: number;
|
prompt_tokens?: number;
|
||||||
completion_tokens?: number;
|
completion_tokens?: number;
|
||||||
total_tokens?: number;
|
total_tokens?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
// waveai.OpenAiStreamRequest
|
// wshrpc.OpenAiStreamRequest
|
||||||
type OpenAiStreamRequest = {
|
type OpenAiStreamRequest = {
|
||||||
clientid?: string;
|
clientid?: string;
|
||||||
opts: OpenAIOptsType;
|
opts: OpenAIOptsType;
|
||||||
@@ -270,6 +270,7 @@ declare global {
|
|||||||
blockheader: BlockHeaderOpts;
|
blockheader: BlockHeaderOpts;
|
||||||
autoupdate: AutoUpdateOpts;
|
autoupdate: AutoUpdateOpts;
|
||||||
termthemes: {[key: string]: TermThemeType};
|
termthemes: {[key: string]: TermThemeType};
|
||||||
|
window: WindowSettingsType;
|
||||||
};
|
};
|
||||||
|
|
||||||
// wstore.StickerClickOptsType
|
// wstore.StickerClickOptsType
|
||||||
@@ -293,6 +294,13 @@ declare global {
|
|||||||
display: StickerDisplayOptsType;
|
display: StickerDisplayOptsType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// wshrpc.SubscriptionRequest
|
||||||
|
type SubscriptionRequest = {
|
||||||
|
event: string;
|
||||||
|
scopes?: string[];
|
||||||
|
allscopes?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
// wstore.Tab
|
// wstore.Tab
|
||||||
type Tab = WaveObj & {
|
type Tab = WaveObj & {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -428,6 +436,14 @@ declare global {
|
|||||||
error: string;
|
error: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// wshrpc.WaveEvent
|
||||||
|
type WaveEvent = {
|
||||||
|
event: string;
|
||||||
|
scopes?: string[];
|
||||||
|
sender?: string;
|
||||||
|
data?: any;
|
||||||
|
};
|
||||||
|
|
||||||
// filestore.WaveFile
|
// filestore.WaveFile
|
||||||
type WaveFile = {
|
type WaveFile = {
|
||||||
zoneid: string;
|
zoneid: string;
|
||||||
@@ -497,6 +513,13 @@ declare global {
|
|||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// wconfig.WindowSettingsType
|
||||||
|
type WindowSettingsType = {
|
||||||
|
transparent: boolean;
|
||||||
|
opacity: number;
|
||||||
|
bgcolor: string;
|
||||||
|
};
|
||||||
|
|
||||||
// wstore.Workspace
|
// wstore.Workspace
|
||||||
type Workspace = WaveObj & {
|
type Workspace = WaveObj & {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ function base64ToArray(b64: string): Uint8Array {
|
|||||||
return rtnArr;
|
return rtnArr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function boundNumber(num: number, min: number, max: number): number {
|
||||||
|
return Math.min(Math.max(num, min), max);
|
||||||
|
}
|
||||||
|
|
||||||
// works for json-like objects (arrays, objects, strings, numbers, booleans)
|
// works for json-like objects (arrays, objects, strings, numbers, booleans)
|
||||||
function jsonDeepEqual(v1: any, v2: any): boolean {
|
function jsonDeepEqual(v1: any, v2: any): boolean {
|
||||||
if (v1 === v2) {
|
if (v1 === v2) {
|
||||||
@@ -193,6 +197,7 @@ function getCrypto() {
|
|||||||
export {
|
export {
|
||||||
base64ToArray,
|
base64ToArray,
|
||||||
base64ToString,
|
base64ToString,
|
||||||
|
boundNumber,
|
||||||
fireAndForget,
|
fireAndForget,
|
||||||
getCrypto,
|
getCrypto,
|
||||||
getPromiseState,
|
getPromiseState,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ loadFonts();
|
|||||||
(window as any).globalWS = globalWS;
|
(window as any).globalWS = globalWS;
|
||||||
(window as any).WOS = WOS;
|
(window as any).WOS = WOS;
|
||||||
(window as any).globalStore = globalStore;
|
(window as any).globalStore = globalStore;
|
||||||
|
(window as any).globalAtoms = atoms;
|
||||||
(window as any).WshServer = WshServer;
|
(window as any).WshServer = WshServer;
|
||||||
(window as any).isFullScreen = false;
|
(window as any).isFullScreen = false;
|
||||||
|
|
||||||
|
|||||||
@@ -76,11 +76,13 @@
|
|||||||
"@table-nav/core": "^0.0.7",
|
"@table-nav/core": "^0.0.7",
|
||||||
"@table-nav/react": "^0.0.7",
|
"@table-nav/react": "^0.0.7",
|
||||||
"@tanstack/react-table": "^8.19.3",
|
"@tanstack/react-table": "^8.19.3",
|
||||||
|
"@types/color": "^3.0.6",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/addon-serialize": "^0.13.0",
|
"@xterm/addon-serialize": "^0.13.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"color": "^4.2.3",
|
||||||
"dayjs": "^1.11.12",
|
"dayjs": "^1.11.12",
|
||||||
"electron-updater": "6.3.1",
|
"electron-updater": "6.3.1",
|
||||||
"html-to-image": "^1.11.11",
|
"html-to-image": "^1.11.11",
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ package blockcontroller
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -21,12 +23,13 @@ import (
|
|||||||
"github.com/wavetermdev/thenextwave/pkg/shellexec"
|
"github.com/wavetermdev/thenextwave/pkg/shellexec"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
// set by main-server.go (for dependency inversion)
|
// set by main-server.go (for dependency inversion)
|
||||||
var WshServerFactoryFn func(inputCh chan []byte, outputCh chan []byte, initialCtx wshutil.RpcContext) = nil
|
var WshServerFactoryFn func(inputCh chan []byte, outputCh chan []byte, initialCtx wshrpc.RpcContext) = nil
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BlockController_Shell = "shell"
|
BlockController_Shell = "shell"
|
||||||
@@ -205,6 +208,46 @@ func (bc *BlockController) resetTerminalState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMetaBool(meta map[string]any, key string, def bool) bool {
|
||||||
|
val, found := meta[key]
|
||||||
|
if !found {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
if val == nil {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
if bval, ok := val.(bool); ok {
|
||||||
|
return bval
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMetaStr(meta map[string]any, key string, def string) string {
|
||||||
|
val, found := meta[key]
|
||||||
|
if !found {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
if val == nil {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
if sval, ok := val.(string); ok {
|
||||||
|
return sval
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
// every byte is 4-bits of randomness
|
||||||
|
func randomHexString(numHexDigits int) (string, error) {
|
||||||
|
numBytes := (numHexDigits + 1) / 2 // Calculate the number of bytes needed
|
||||||
|
bytes := make([]byte, numBytes)
|
||||||
|
if _, err := rand.Read(bytes); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
hexStr := hex.EncodeToString(bytes)
|
||||||
|
return hexStr[:numHexDigits], nil // Return the exact number of hex digits
|
||||||
|
}
|
||||||
|
|
||||||
func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta map[string]any) error {
|
func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta map[string]any) error {
|
||||||
// create a circular blockfile for the output
|
// create a circular blockfile for the output
|
||||||
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
@@ -232,12 +275,35 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta map[str
|
|||||||
if shellProcErr != nil {
|
if shellProcErr != nil {
|
||||||
return shellProcErr
|
return shellProcErr
|
||||||
}
|
}
|
||||||
|
var remoteDomainSocketName string
|
||||||
|
remoteName := getMetaStr(blockMeta, "connection", "")
|
||||||
|
isRemote := remoteName != ""
|
||||||
|
if isRemote {
|
||||||
|
randStr, err := randomHexString(16) // 64-bits of randomness
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error generating random string: %w", err)
|
||||||
|
}
|
||||||
|
remoteDomainSocketName = fmt.Sprintf("/tmp/waveterm-%s.sock", randStr)
|
||||||
|
}
|
||||||
var cmdStr string
|
var cmdStr string
|
||||||
cmdOpts := shellexec.CommandOptsType{
|
cmdOpts := shellexec.CommandOptsType{
|
||||||
Env: make(map[string]string),
|
Env: make(map[string]string),
|
||||||
}
|
}
|
||||||
// temporary for blockid (will switch to a JWT at some point)
|
if !getMetaBool(blockMeta, "nowsh", false) {
|
||||||
cmdOpts.Env["LC_WAVETERM_BLOCKID"] = bc.BlockId
|
if isRemote {
|
||||||
|
jwtStr, err := wshutil.MakeClientJWTToken(wshrpc.RpcContext{TabId: bc.TabId, BlockId: bc.BlockId}, remoteDomainSocketName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error making jwt token: %w", err)
|
||||||
|
}
|
||||||
|
cmdOpts.Env["WAVETERM_JWT"] = jwtStr
|
||||||
|
} else {
|
||||||
|
jwtStr, err := wshutil.MakeClientJWTToken(wshrpc.RpcContext{TabId: bc.TabId, BlockId: bc.BlockId}, wavebase.GetDomainSocketName())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error making jwt token: %w", err)
|
||||||
|
}
|
||||||
|
cmdOpts.Env["WAVETERM_JWT"] = jwtStr
|
||||||
|
}
|
||||||
|
}
|
||||||
if bc.ControllerType == BlockController_Shell {
|
if bc.ControllerType == BlockController_Shell {
|
||||||
cmdOpts.Interactive = true
|
cmdOpts.Interactive = true
|
||||||
cmdOpts.Login = true
|
cmdOpts.Login = true
|
||||||
@@ -284,11 +350,8 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta map[str
|
|||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("unknown controller type %q", bc.ControllerType)
|
return fmt.Errorf("unknown controller type %q", bc.ControllerType)
|
||||||
}
|
}
|
||||||
// pty buffer equivalent for ssh? i think if i have the ecmd or session i can manage it with output
|
|
||||||
// pty write needs stdin, so if i provide that, i might be able to write that way
|
|
||||||
// need a way to handle setsize???
|
|
||||||
var shellProc *shellexec.ShellProc
|
var shellProc *shellexec.ShellProc
|
||||||
if remoteName, ok := blockMeta["connection"].(string); ok && remoteName != "" {
|
if remoteName != "" {
|
||||||
shellProc, err = shellexec.StartRemoteShellProc(rc.TermSize, cmdStr, cmdOpts, remoteName)
|
shellProc, err = shellexec.StartRemoteShellProc(rc.TermSize, cmdStr, cmdOpts, remoteName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -309,7 +372,7 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta map[str
|
|||||||
messageCh := make(chan []byte, 32)
|
messageCh := make(chan []byte, 32)
|
||||||
ptyBuffer := wshutil.MakePtyBuffer(wshutil.WaveOSCPrefix, bc.ShellProc.Pty, messageCh)
|
ptyBuffer := wshutil.MakePtyBuffer(wshutil.WaveOSCPrefix, bc.ShellProc.Pty, messageCh)
|
||||||
outputCh := make(chan []byte, 32)
|
outputCh := make(chan []byte, 32)
|
||||||
WshServerFactoryFn(messageCh, outputCh, wshutil.RpcContext{BlockId: bc.BlockId, TabId: bc.TabId})
|
WshServerFactoryFn(messageCh, outputCh, wshrpc.RpcContext{BlockId: bc.BlockId, TabId: bc.TabId})
|
||||||
go func() {
|
go func() {
|
||||||
// handles regular output from the pty (goes to the blockfile and xterm)
|
// handles regular output from the pty (goes to the blockfile and xterm)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
+22
-22
@@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/wavetermdev/thenextwave/pkg/wconfig"
|
"github.com/wavetermdev/thenextwave/pkg/wconfig"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/web/webcmd"
|
"github.com/wavetermdev/thenextwave/pkg/web/webcmd"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshrpc/wshserver"
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
||||||
)
|
)
|
||||||
@@ -61,10 +60,13 @@ var uiContextRType = reflect.TypeOf((*wstore.UIContext)(nil)).Elem()
|
|||||||
var waveObjRType = reflect.TypeOf((*waveobj.WaveObj)(nil)).Elem()
|
var waveObjRType = reflect.TypeOf((*waveobj.WaveObj)(nil)).Elem()
|
||||||
var updatesRtnRType = reflect.TypeOf(wstore.UpdatesRtnType{})
|
var updatesRtnRType = reflect.TypeOf(wstore.UpdatesRtnType{})
|
||||||
var orefRType = reflect.TypeOf((*waveobj.ORef)(nil)).Elem()
|
var orefRType = reflect.TypeOf((*waveobj.ORef)(nil)).Elem()
|
||||||
|
var wshRpcInterfaceRType = reflect.TypeOf((*wshrpc.WshRpcInterface)(nil)).Elem()
|
||||||
|
|
||||||
func generateTSMethodTypes(method reflect.Method, tsTypesMap map[reflect.Type]string) error {
|
func generateTSMethodTypes(method reflect.Method, tsTypesMap map[reflect.Type]string, skipFirstArg bool) error {
|
||||||
for idx := 1; idx < method.Type.NumIn(); idx++ {
|
for idx := 0; idx < method.Type.NumIn(); idx++ {
|
||||||
// skip receiver
|
if skipFirstArg && idx == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
inType := method.Type.In(idx)
|
inType := method.Type.In(idx)
|
||||||
GenerateTSType(inType, tsTypesMap)
|
GenerateTSType(inType, tsTypesMap)
|
||||||
}
|
}
|
||||||
@@ -159,14 +161,13 @@ var tsRenameMap = map[string]string{
|
|||||||
|
|
||||||
func generateTSTypeInternal(rtype reflect.Type, tsTypesMap map[reflect.Type]string) (string, []reflect.Type) {
|
func generateTSTypeInternal(rtype reflect.Type, tsTypesMap map[reflect.Type]string) (string, []reflect.Type) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
waveObjType := reflect.TypeOf((*waveobj.WaveObj)(nil)).Elem()
|
|
||||||
tsTypeName := rtype.Name()
|
tsTypeName := rtype.Name()
|
||||||
if tsRename, ok := tsRenameMap[tsTypeName]; ok {
|
if tsRename, ok := tsRenameMap[tsTypeName]; ok {
|
||||||
tsTypeName = tsRename
|
tsTypeName = tsRename
|
||||||
}
|
}
|
||||||
var isWaveObj bool
|
var isWaveObj bool
|
||||||
buf.WriteString(fmt.Sprintf("// %s\n", rtype.String()))
|
buf.WriteString(fmt.Sprintf("// %s\n", rtype.String()))
|
||||||
if rtype.Implements(waveObjType) || reflect.PointerTo(rtype).Implements(waveObjType) {
|
if rtype.Implements(waveObjRType) || reflect.PointerTo(rtype).Implements(waveObjRType) {
|
||||||
isWaveObj = true
|
isWaveObj = true
|
||||||
buf.WriteString(fmt.Sprintf("type %s = WaveObj & {\n", tsTypeName))
|
buf.WriteString(fmt.Sprintf("type %s = WaveObj & {\n", tsTypeName))
|
||||||
} else {
|
} else {
|
||||||
@@ -253,6 +254,9 @@ func GenerateTSType(rtype reflect.Type, tsTypesMap map[reflect.Type]string) {
|
|||||||
if rtype == nil {
|
if rtype == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if rtype.Kind() == reflect.Chan {
|
||||||
|
rtype = rtype.Elem()
|
||||||
|
}
|
||||||
if rtype == metaRType {
|
if rtype == metaRType {
|
||||||
tsTypesMap[metaRType] = GenerateMetaType()
|
tsTypesMap[metaRType] = GenerateMetaType()
|
||||||
return
|
return
|
||||||
@@ -397,17 +401,17 @@ func GenerateServiceClass(serviceName string, serviceObj any, tsTypesMap map[ref
|
|||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateWshServerMethod(methodDecl *wshserver.WshServerMethodDecl, tsTypesMap map[reflect.Type]string) string {
|
func GenerateWshServerMethod(methodDecl *wshrpc.WshRpcMethodDecl, tsTypesMap map[reflect.Type]string) string {
|
||||||
if methodDecl.CommandType == wshutil.RpcType_ResponseStream {
|
if methodDecl.CommandType == wshrpc.RpcType_ResponseStream {
|
||||||
return GenerateWshServerMethod_ResponseStream(methodDecl, tsTypesMap)
|
return GenerateWshServerMethod_ResponseStream(methodDecl, tsTypesMap)
|
||||||
} else if methodDecl.CommandType == wshutil.RpcType_Call {
|
} else if methodDecl.CommandType == wshrpc.RpcType_Call {
|
||||||
return GenerateWshServerMethod_Call(methodDecl, tsTypesMap)
|
return GenerateWshServerMethod_Call(methodDecl, tsTypesMap)
|
||||||
} else {
|
} else {
|
||||||
panic(fmt.Sprintf("cannot generate wshserver commandtype %q", methodDecl.CommandType))
|
panic(fmt.Sprintf("cannot generate wshserver commandtype %q", methodDecl.CommandType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateWshServerMethod_ResponseStream(methodDecl *wshserver.WshServerMethodDecl, tsTypesMap map[reflect.Type]string) string {
|
func GenerateWshServerMethod_ResponseStream(methodDecl *wshrpc.WshRpcMethodDecl, tsTypesMap map[reflect.Type]string) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
sb.WriteString(fmt.Sprintf(" // command %q [%s]\n", methodDecl.Command, methodDecl.CommandType))
|
sb.WriteString(fmt.Sprintf(" // command %q [%s]\n", methodDecl.Command, methodDecl.CommandType))
|
||||||
respType := "any"
|
respType := "any"
|
||||||
@@ -429,7 +433,7 @@ func GenerateWshServerMethod_ResponseStream(methodDecl *wshserver.WshServerMetho
|
|||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateWshServerMethod_Call(methodDecl *wshserver.WshServerMethodDecl, tsTypesMap map[reflect.Type]string) string {
|
func GenerateWshServerMethod_Call(methodDecl *wshrpc.WshRpcMethodDecl, tsTypesMap map[reflect.Type]string) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
sb.WriteString(fmt.Sprintf(" // command %q [%s]\n", methodDecl.Command, methodDecl.CommandType))
|
sb.WriteString(fmt.Sprintf(" // command %q [%s]\n", methodDecl.Command, methodDecl.CommandType))
|
||||||
rtnType := "Promise<void>"
|
rtnType := "Promise<void>"
|
||||||
@@ -469,7 +473,7 @@ func GenerateServiceTypes(tsTypesMap map[reflect.Type]string) error {
|
|||||||
serviceType := reflect.TypeOf(serviceObj)
|
serviceType := reflect.TypeOf(serviceObj)
|
||||||
for midx := 0; midx < serviceType.NumMethod(); midx++ {
|
for midx := 0; midx < serviceType.NumMethod(); midx++ {
|
||||||
method := serviceType.Method(midx)
|
method := serviceType.Method(midx)
|
||||||
err := generateTSMethodTypes(method, tsTypesMap)
|
err := generateTSMethodTypes(method, tsTypesMap, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error generating TS method types for %s.%s: %v", serviceType, method.Name, err)
|
return fmt.Errorf("error generating TS method types for %s.%s: %v", serviceType, method.Name, err)
|
||||||
}
|
}
|
||||||
@@ -480,16 +484,12 @@ func GenerateServiceTypes(tsTypesMap map[reflect.Type]string) error {
|
|||||||
|
|
||||||
func GenerateWshServerTypes(tsTypesMap map[reflect.Type]string) error {
|
func GenerateWshServerTypes(tsTypesMap map[reflect.Type]string) error {
|
||||||
GenerateTSType(reflect.TypeOf(wshrpc.WshRpcCommandOpts{}), tsTypesMap)
|
GenerateTSType(reflect.TypeOf(wshrpc.WshRpcCommandOpts{}), tsTypesMap)
|
||||||
for _, methodDecl := range wshserver.WshServerCommandToDeclMap {
|
rtype := wshRpcInterfaceRType
|
||||||
GenerateTSType(methodDecl.CommandDataType, tsTypesMap)
|
for midx := 0; midx < rtype.NumMethod(); midx++ {
|
||||||
if methodDecl.DefaultResponseDataType != nil {
|
method := rtype.Method(midx)
|
||||||
GenerateTSType(methodDecl.DefaultResponseDataType, tsTypesMap)
|
err := generateTSMethodTypes(method, tsTypesMap, false)
|
||||||
}
|
if err != nil {
|
||||||
for _, rtype := range methodDecl.RequestDataTypes {
|
return fmt.Errorf("error generating TS method types for %s.%s: %v", rtype, method.Name, err)
|
||||||
GenerateTSType(rtype, tsTypesMap)
|
|
||||||
}
|
|
||||||
for _, rtype := range methodDecl.ResponseDataTypes {
|
|
||||||
GenerateTSType(rtype, tsTypesMap)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -800,3 +800,29 @@ func MoveSliceIdxToFront[T any](arr []T, idx int) []T {
|
|||||||
rtn = append(rtn, arr[idx+1:]...)
|
rtn = append(rtn, arr[idx+1:]...)
|
||||||
return rtn
|
return rtn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// matches a delimited string with a pattern string
|
||||||
|
// the pattern string can contain "*" to match a single part, or "**" to match the rest of the string
|
||||||
|
// note that "**" may only appear at the end of the string
|
||||||
|
func StarMatchString(pattern string, s string, delimiter string) bool {
|
||||||
|
patternParts := strings.Split(pattern, delimiter)
|
||||||
|
stringParts := strings.Split(s, delimiter)
|
||||||
|
pLen, sLen := len(patternParts), len(stringParts)
|
||||||
|
|
||||||
|
for i := 0; i < pLen; i++ {
|
||||||
|
if patternParts[i] == "**" {
|
||||||
|
// '**' must be at the end to be valid
|
||||||
|
return i == pLen-1
|
||||||
|
}
|
||||||
|
if i >= sLen {
|
||||||
|
// If string is exhausted but pattern is not
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if patternParts[i] != "*" && patternParts[i] != stringParts[i] {
|
||||||
|
// If current parts don't match and pattern part is not '*'
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if both pattern and string are fully matched
|
||||||
|
return pLen == sLen
|
||||||
|
}
|
||||||
|
|||||||
+41
-79
@@ -23,12 +23,6 @@ const OpenAIPacketStr = "openai"
|
|||||||
const OpenAICloudReqStr = "openai-cloudreq"
|
const OpenAICloudReqStr = "openai-cloudreq"
|
||||||
const PacketEOFStr = "EOF"
|
const PacketEOFStr = "EOF"
|
||||||
|
|
||||||
type OpenAIUsageType struct {
|
|
||||||
PromptTokens int `json:"prompt_tokens,omitempty"`
|
|
||||||
CompletionTokens int `json:"completion_tokens,omitempty"`
|
|
||||||
TotalTokens int `json:"total_tokens,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OpenAICmdInfoPacketOutputType struct {
|
type OpenAICmdInfoPacketOutputType struct {
|
||||||
Model string `json:"model,omitempty"`
|
Model string `json:"model,omitempty"`
|
||||||
Created int64 `json:"created,omitempty"`
|
Created int64 `json:"created,omitempty"`
|
||||||
@@ -37,19 +31,8 @@ type OpenAICmdInfoPacketOutputType struct {
|
|||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenAIPacketType struct {
|
func MakeOpenAIPacket() *wshrpc.OpenAIPacketType {
|
||||||
Type string `json:"type"`
|
return &wshrpc.OpenAIPacketType{Type: OpenAIPacketStr}
|
||||||
Model string `json:"model,omitempty"`
|
|
||||||
Created int64 `json:"created,omitempty"`
|
|
||||||
FinishReason string `json:"finish_reason,omitempty"`
|
|
||||||
Usage *OpenAIUsageType `json:"usage,omitempty"`
|
|
||||||
Index int `json:"index,omitempty"`
|
|
||||||
Text string `json:"text,omitempty"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeOpenAIPacket() *OpenAIPacketType {
|
|
||||||
return &OpenAIPacketType{Type: OpenAIPacketStr}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenAICmdInfoChatMessage struct {
|
type OpenAICmdInfoChatMessage struct {
|
||||||
@@ -60,27 +43,12 @@ type OpenAICmdInfoChatMessage struct {
|
|||||||
UserEngineeredQuery string `json:"userengineeredquery,omitempty"`
|
UserEngineeredQuery string `json:"userengineeredquery,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenAIPromptMessageType struct {
|
|
||||||
Role string `json:"role"`
|
|
||||||
Content string `json:"content"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OpenAICloudReqPacketType struct {
|
type OpenAICloudReqPacketType struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
ClientId string `json:"clientid"`
|
ClientId string `json:"clientid"`
|
||||||
Prompt []OpenAIPromptMessageType `json:"prompt"`
|
Prompt []wshrpc.OpenAIPromptMessageType `json:"prompt"`
|
||||||
MaxTokens int `json:"maxtokens,omitempty"`
|
MaxTokens int `json:"maxtokens,omitempty"`
|
||||||
MaxChoices int `json:"maxchoices,omitempty"`
|
MaxChoices int `json:"maxchoices,omitempty"`
|
||||||
}
|
|
||||||
|
|
||||||
type OpenAIOptsType struct {
|
|
||||||
Model string `json:"model"`
|
|
||||||
APIToken string `json:"apitoken"`
|
|
||||||
BaseURL string `json:"baseurl,omitempty"`
|
|
||||||
MaxTokens int `json:"maxtokens,omitempty"`
|
|
||||||
MaxChoices int `json:"maxchoices,omitempty"`
|
|
||||||
Timeout int `json:"timeout,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeOpenAICloudReqPacket() *OpenAICloudReqPacketType {
|
func MakeOpenAICloudReqPacket() *OpenAICloudReqPacketType {
|
||||||
@@ -89,12 +57,6 @@ func MakeOpenAICloudReqPacket() *OpenAICloudReqPacketType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenAiStreamRequest struct {
|
|
||||||
ClientId string `json:"clientid,omitempty"`
|
|
||||||
Opts *OpenAIOptsType `json:"opts"`
|
|
||||||
Prompt []OpenAIPromptMessageType `json:"prompt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetWSEndpoint() string {
|
func GetWSEndpoint() string {
|
||||||
return PCloudWSEndpoint
|
return PCloudWSEndpoint
|
||||||
if !wavebase.IsDevMode() {
|
if !wavebase.IsDevMode() {
|
||||||
@@ -116,18 +78,18 @@ const PCloudWSEndpointVarName = "PCLOUD_WS_ENDPOINT"
|
|||||||
|
|
||||||
const CloudWebsocketConnectTimeout = 1 * time.Minute
|
const CloudWebsocketConnectTimeout = 1 * time.Minute
|
||||||
|
|
||||||
func convertUsage(resp openaiapi.ChatCompletionResponse) *OpenAIUsageType {
|
func convertUsage(resp openaiapi.ChatCompletionResponse) *wshrpc.OpenAIUsageType {
|
||||||
if resp.Usage.TotalTokens == 0 {
|
if resp.Usage.TotalTokens == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &OpenAIUsageType{
|
return &wshrpc.OpenAIUsageType{
|
||||||
PromptTokens: resp.Usage.PromptTokens,
|
PromptTokens: resp.Usage.PromptTokens,
|
||||||
CompletionTokens: resp.Usage.CompletionTokens,
|
CompletionTokens: resp.Usage.CompletionTokens,
|
||||||
TotalTokens: resp.Usage.TotalTokens,
|
TotalTokens: resp.Usage.TotalTokens,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertPrompt(prompt []OpenAIPromptMessageType) []openaiapi.ChatCompletionMessage {
|
func ConvertPrompt(prompt []wshrpc.OpenAIPromptMessageType) []openaiapi.ChatCompletionMessage {
|
||||||
var rtn []openaiapi.ChatCompletionMessage
|
var rtn []openaiapi.ChatCompletionMessage
|
||||||
for _, p := range prompt {
|
for _, p := range prompt {
|
||||||
msg := openaiapi.ChatCompletionMessage{Role: p.Role, Content: p.Content, Name: p.Name}
|
msg := openaiapi.ChatCompletionMessage{Role: p.Role, Content: p.Content, Name: p.Name}
|
||||||
@@ -136,31 +98,31 @@ func ConvertPrompt(prompt []OpenAIPromptMessageType) []openaiapi.ChatCompletionM
|
|||||||
return rtn
|
return rtn
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunCloudCompletionStream(ctx context.Context, request OpenAiStreamRequest) chan wshrpc.RespOrErrorUnion[OpenAIPacketType] {
|
func RunCloudCompletionStream(ctx context.Context, request wshrpc.OpenAiStreamRequest) chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType] {
|
||||||
rtn := make(chan wshrpc.RespOrErrorUnion[OpenAIPacketType])
|
rtn := make(chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType])
|
||||||
go func() {
|
go func() {
|
||||||
log.Printf("start: %v", request)
|
log.Printf("start: %v", request)
|
||||||
defer close(rtn)
|
defer close(rtn)
|
||||||
if request.Opts == nil {
|
if request.Opts == nil {
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("no openai opts found")}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("no openai opts found")}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
websocketContext, dialCancelFn := context.WithTimeout(context.Background(), CloudWebsocketConnectTimeout)
|
websocketContext, dialCancelFn := context.WithTimeout(context.Background(), CloudWebsocketConnectTimeout)
|
||||||
defer dialCancelFn()
|
defer dialCancelFn()
|
||||||
conn, _, err := websocket.DefaultDialer.DialContext(websocketContext, GetWSEndpoint(), nil)
|
conn, _, err := websocket.DefaultDialer.DialContext(websocketContext, GetWSEndpoint(), nil)
|
||||||
|
if err == context.DeadlineExceeded {
|
||||||
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, timed out connecting to cloud server: %v", err)}
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket connect error: %v", err)}
|
||||||
|
return
|
||||||
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
err = conn.Close()
|
err = conn.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("unable to close openai channel: %v", err)}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("unable to close openai channel: %v", err)}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err == context.DeadlineExceeded {
|
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, timed out connecting to cloud server: %v", err)}
|
|
||||||
return
|
|
||||||
} else if err != nil {
|
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket connect error: %v", err)}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
reqPk := MakeOpenAICloudReqPacket()
|
reqPk := MakeOpenAICloudReqPacket()
|
||||||
reqPk.ClientId = request.ClientId
|
reqPk.ClientId = request.ClientId
|
||||||
reqPk.Prompt = request.Prompt
|
reqPk.Prompt = request.Prompt
|
||||||
@@ -168,12 +130,12 @@ func RunCloudCompletionStream(ctx context.Context, request OpenAiStreamRequest)
|
|||||||
reqPk.MaxChoices = request.Opts.MaxChoices
|
reqPk.MaxChoices = request.Opts.MaxChoices
|
||||||
configMessageBuf, err := json.Marshal(reqPk)
|
configMessageBuf, err := json.Marshal(reqPk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, packet marshal error: %v", err)}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, packet marshal error: %v", err)}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = conn.WriteMessage(websocket.TextMessage, configMessageBuf)
|
err = conn.WriteMessage(websocket.TextMessage, configMessageBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket write config error: %v", err)}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket write config error: %v", err)}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
@@ -184,14 +146,14 @@ func RunCloudCompletionStream(ctx context.Context, request OpenAiStreamRequest)
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("err received: %v", err)
|
log.Printf("err received: %v", err)
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket error reading message: %v", err)}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket error reading message: %v", err)}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
var streamResp *OpenAIPacketType
|
var streamResp *wshrpc.OpenAIPacketType
|
||||||
err = json.Unmarshal(socketMessage, &streamResp)
|
err = json.Unmarshal(socketMessage, &streamResp)
|
||||||
log.Printf("ai resp: %v", streamResp)
|
log.Printf("ai resp: %v", streamResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket response json decode error: %v", err)}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket response json decode error: %v", err)}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if streamResp.Error == PacketEOFStr {
|
if streamResp.Error == PacketEOFStr {
|
||||||
@@ -199,30 +161,30 @@ func RunCloudCompletionStream(ctx context.Context, request OpenAiStreamRequest)
|
|||||||
break
|
break
|
||||||
} else if streamResp.Error != "" {
|
} else if streamResp.Error != "" {
|
||||||
// use error from server directly
|
// use error from server directly
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("%v", streamResp.Error)}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("%v", streamResp.Error)}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Response: *streamResp}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Response: *streamResp}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return rtn
|
return rtn
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunLocalCompletionStream(ctx context.Context, request OpenAiStreamRequest) chan wshrpc.RespOrErrorUnion[OpenAIPacketType] {
|
func RunLocalCompletionStream(ctx context.Context, request wshrpc.OpenAiStreamRequest) chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType] {
|
||||||
rtn := make(chan wshrpc.RespOrErrorUnion[OpenAIPacketType])
|
rtn := make(chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType])
|
||||||
go func() {
|
go func() {
|
||||||
log.Printf("start2: %v", request)
|
log.Printf("start2: %v", request)
|
||||||
defer close(rtn)
|
defer close(rtn)
|
||||||
if request.Opts == nil {
|
if request.Opts == nil {
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("no openai opts found")}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("no openai opts found")}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if request.Opts.Model == "" {
|
if request.Opts.Model == "" {
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("no openai model specified")}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("no openai model specified")}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if request.Opts.BaseURL == "" && request.Opts.APIToken == "" {
|
if request.Opts.BaseURL == "" && request.Opts.APIToken == "" {
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("no api token")}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("no api token")}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clientConfig := openaiapi.DefaultConfig(request.Opts.APIToken)
|
clientConfig := openaiapi.DefaultConfig(request.Opts.APIToken)
|
||||||
@@ -241,7 +203,7 @@ func RunLocalCompletionStream(ctx context.Context, request OpenAiStreamRequest)
|
|||||||
}
|
}
|
||||||
apiResp, err := client.CreateChatCompletionStream(ctx, req)
|
apiResp, err := client.CreateChatCompletionStream(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("error calling openai API: %v", err)}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("error calling openai API: %v", err)}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sentHeader := false
|
sentHeader := false
|
||||||
@@ -253,14 +215,14 @@ func RunLocalCompletionStream(ctx context.Context, request OpenAiStreamRequest)
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("err received2: %v", err)
|
log.Printf("err received2: %v", err)
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket error reading message: %v", err)}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Error: fmt.Errorf("OpenAI request, websocket error reading message: %v", err)}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if streamResp.Model != "" && !sentHeader {
|
if streamResp.Model != "" && !sentHeader {
|
||||||
pk := MakeOpenAIPacket()
|
pk := MakeOpenAIPacket()
|
||||||
pk.Model = streamResp.Model
|
pk.Model = streamResp.Model
|
||||||
pk.Created = streamResp.Created
|
pk.Created = streamResp.Created
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Response: *pk}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Response: *pk}
|
||||||
sentHeader = true
|
sentHeader = true
|
||||||
}
|
}
|
||||||
for _, choice := range streamResp.Choices {
|
for _, choice := range streamResp.Choices {
|
||||||
@@ -268,15 +230,15 @@ func RunLocalCompletionStream(ctx context.Context, request OpenAiStreamRequest)
|
|||||||
pk.Index = choice.Index
|
pk.Index = choice.Index
|
||||||
pk.Text = choice.Delta.Content
|
pk.Text = choice.Delta.Content
|
||||||
pk.FinishReason = string(choice.FinishReason)
|
pk.FinishReason = string(choice.FinishReason)
|
||||||
rtn <- wshrpc.RespOrErrorUnion[OpenAIPacketType]{Response: *pk}
|
rtn <- wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType]{Response: *pk}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return rtn
|
return rtn
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalResponse(resp openaiapi.ChatCompletionResponse) []*OpenAIPacketType {
|
func marshalResponse(resp openaiapi.ChatCompletionResponse) []*wshrpc.OpenAIPacketType {
|
||||||
var rtn []*OpenAIPacketType
|
var rtn []*wshrpc.OpenAIPacketType
|
||||||
headerPk := MakeOpenAIPacket()
|
headerPk := MakeOpenAIPacket()
|
||||||
headerPk.Model = resp.Model
|
headerPk.Model = resp.Model
|
||||||
headerPk.Created = resp.Created
|
headerPk.Created = resp.Created
|
||||||
@@ -292,14 +254,14 @@ func marshalResponse(resp openaiapi.ChatCompletionResponse) []*OpenAIPacketType
|
|||||||
return rtn
|
return rtn
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateErrorPacket(errStr string) *OpenAIPacketType {
|
func CreateErrorPacket(errStr string) *wshrpc.OpenAIPacketType {
|
||||||
errPk := MakeOpenAIPacket()
|
errPk := MakeOpenAIPacket()
|
||||||
errPk.FinishReason = "error"
|
errPk.FinishReason = "error"
|
||||||
errPk.Error = errStr
|
errPk.Error = errStr
|
||||||
return errPk
|
return errPk
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateTextPacket(text string) *OpenAIPacketType {
|
func CreateTextPacket(text string) *wshrpc.OpenAIPacketType {
|
||||||
pk := MakeOpenAIPacket()
|
pk := MakeOpenAIPacket()
|
||||||
pk.Text = text
|
pk.Text = text
|
||||||
return pk
|
return pk
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user