mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
Expose config path to frontend (#404)
* added config api path * addressed feedback * initial change for http file server * removed old handle config func * added user keybind config path * fixed logs
This commit is contained in:
parent
77ea45392a
commit
5258a67a78
@ -36,6 +36,7 @@ import { Cmd } from "./cmd";
|
|||||||
import { GlobalCommandRunner } from "./global";
|
import { GlobalCommandRunner } from "./global";
|
||||||
import { clearMonoFontCache, getMonoFontSize } from "@/util/textmeasure";
|
import { clearMonoFontCache, getMonoFontSize } from "@/util/textmeasure";
|
||||||
import type { TermWrap } from "@/plugins/terminal/term";
|
import type { TermWrap } from "@/plugins/terminal/term";
|
||||||
|
import * as util from "@/util/util";
|
||||||
|
|
||||||
type SWLinePtr = {
|
type SWLinePtr = {
|
||||||
line: LineType;
|
line: LineType;
|
||||||
@ -143,6 +144,8 @@ class Model {
|
|||||||
});
|
});
|
||||||
this.ws.reconnect();
|
this.ws.reconnect();
|
||||||
this.keybindManager = new KeybindManager();
|
this.keybindManager = new KeybindManager();
|
||||||
|
this.readConfigKeybindings();
|
||||||
|
this.initSystemKeybindings();
|
||||||
this.inputModel = new InputModel(this);
|
this.inputModel = new InputModel(this);
|
||||||
this.pluginsModel = new PluginsModel(this);
|
this.pluginsModel = new PluginsModel(this);
|
||||||
this.bookmarksModel = new BookmarksModel(this);
|
this.bookmarksModel = new BookmarksModel(this);
|
||||||
@ -171,13 +174,6 @@ class Model {
|
|||||||
}
|
}
|
||||||
return fontSize;
|
return fontSize;
|
||||||
});
|
});
|
||||||
this.keybindManager.registerKeybinding("system", "electron", "any", (waveEvent) => {
|
|
||||||
if (this.keybindManager.checkKeyPressed(waveEvent, "system:toggleDeveloperTools")) {
|
|
||||||
getApi().toggleDeveloperTools();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
getApi().onTCmd(this.onTCmd.bind(this));
|
getApi().onTCmd(this.onTCmd.bind(this));
|
||||||
getApi().onICmd(this.onICmd.bind(this));
|
getApi().onICmd(this.onICmd.bind(this));
|
||||||
getApi().onLCmd(this.onLCmd.bind(this));
|
getApi().onLCmd(this.onLCmd.bind(this));
|
||||||
@ -208,6 +204,31 @@ class Model {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readConfigKeybindings() {
|
||||||
|
const url = new URL(this.getBaseHostPort() + "/config/keybindings.json");
|
||||||
|
let prtn = fetch(url, { method: "get", body: null, headers: this.getFetchHeaders() });
|
||||||
|
prtn.then((resp) => {
|
||||||
|
if (resp.status == 404) {
|
||||||
|
return [];
|
||||||
|
} else if (!resp.ok) {
|
||||||
|
util.handleNotOkResp(resp, url);
|
||||||
|
}
|
||||||
|
return resp.json();
|
||||||
|
}).then((userKeybindings) => {
|
||||||
|
this.keybindManager.setUserKeybindings(userKeybindings);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initSystemKeybindings() {
|
||||||
|
this.keybindManager.registerKeybinding("system", "electron", "any", (waveEvent) => {
|
||||||
|
if (this.keybindManager.checkKeyPressed(waveEvent, "system:toggleDeveloperTools")) {
|
||||||
|
getApi().toggleDeveloperTools();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static getInstance(): Model {
|
static getInstance(): Model {
|
||||||
if (!(window as any).GlobalModel) {
|
if (!(window as any).GlobalModel) {
|
||||||
(window as any).GlobalModel = new Model();
|
(window as any).GlobalModel = new Model();
|
||||||
@ -1298,7 +1319,7 @@ class Model {
|
|||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
console.log(
|
console.log(
|
||||||
"CMD",
|
"CMD"
|
||||||
pk.metacmd + (pk.metasubcmd != null ? ":" + pk.metasubcmd : ""),
|
pk.metacmd + (pk.metasubcmd != null ? ":" + pk.metasubcmd : ""),
|
||||||
pk.args,
|
pk.args,
|
||||||
pk.kwargs,
|
pk.kwargs,
|
||||||
@ -1526,7 +1547,7 @@ class Model {
|
|||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
badResponseStr = sprintf(
|
badResponseStr = sprintf(
|
||||||
"Bad fetch response for /api/read-file: %d %s",
|
"Bad fetch response for /apiread-file: %d %s",
|
||||||
resp.status,
|
resp.status,
|
||||||
resp.statusText
|
resp.statusText
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import * as mobx from "mobx";
|
||||||
import * as electron from "electron";
|
import * as electron from "electron";
|
||||||
import { parse } from "node:path";
|
import { parse } from "node:path";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import keybindings from "../../assets/keybindings.json";
|
import defaultKeybindingsFile from "../../assets/keybindings.json";
|
||||||
|
const defaultKeybindings: KeybindConfig = defaultKeybindingsFile;
|
||||||
|
|
||||||
type KeyPressDecl = {
|
type KeyPressDecl = {
|
||||||
mods: {
|
mods: {
|
||||||
@ -22,6 +24,7 @@ const KeyTypeKey = "key";
|
|||||||
const KeyTypeCode = "code";
|
const KeyTypeCode = "code";
|
||||||
|
|
||||||
type KeybindCallback = (event: WaveKeyboardEvent) => boolean;
|
type KeybindCallback = (event: WaveKeyboardEvent) => boolean;
|
||||||
|
type KeybindConfig = Array<{ command: string; keys: Array<string> }>;
|
||||||
|
|
||||||
type Keybind = {
|
type Keybind = {
|
||||||
domain: string;
|
domain: string;
|
||||||
@ -36,6 +39,66 @@ class KeybindManager {
|
|||||||
levelMap: Map<string, Array<Keybind>>;
|
levelMap: Map<string, Array<Keybind>>;
|
||||||
levelArray: Array<string>;
|
levelArray: Array<string>;
|
||||||
keyDescriptionsMap: Map<string, Array<string>>;
|
keyDescriptionsMap: Map<string, Array<string>>;
|
||||||
|
userKeybindings: KeybindConfig;
|
||||||
|
userKeybindingError: OV<string>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.levelMap = new Map();
|
||||||
|
this.domainCallbacks = new Map();
|
||||||
|
this.levelArray = KeybindLevels;
|
||||||
|
for (let index = 0; index < this.levelArray.length; index++) {
|
||||||
|
let curLevel = this.levelArray[index];
|
||||||
|
this.levelMap.set(curLevel, new Array<Keybind>());
|
||||||
|
}
|
||||||
|
this.userKeybindingError = mobx.observable.box(null, {
|
||||||
|
name: "keyutil-userKeybindingError",
|
||||||
|
});
|
||||||
|
this.initKeyDescriptionsMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
initKeyDescriptionsMap() {
|
||||||
|
mobx.action(() => {
|
||||||
|
this.userKeybindingError.set(null);
|
||||||
|
})();
|
||||||
|
let newKeyDescriptions = new Map();
|
||||||
|
for (let index = 0; index < defaultKeybindings.length; index++) {
|
||||||
|
let curKeybind = defaultKeybindings[index];
|
||||||
|
newKeyDescriptions.set(curKeybind.command, curKeybind.keys);
|
||||||
|
}
|
||||||
|
let curUserCommand = "";
|
||||||
|
if (this.userKeybindings != null && this.userKeybindings instanceof Array) {
|
||||||
|
try {
|
||||||
|
console.log("setting user keybindings");
|
||||||
|
for (let index = 0; index < this.userKeybindings.length; index++) {
|
||||||
|
let curKeybind = this.userKeybindings[index];
|
||||||
|
if (curKeybind == null) {
|
||||||
|
throw new Error("keybind entry is null");
|
||||||
|
}
|
||||||
|
curUserCommand = curKeybind.command;
|
||||||
|
if (typeof curKeybind.command != "string") {
|
||||||
|
throw new Error("invalid keybind command");
|
||||||
|
}
|
||||||
|
if (curKeybind.keys == null || !(curKeybind.keys instanceof Array)) {
|
||||||
|
throw new Error("invalid keybind keys");
|
||||||
|
}
|
||||||
|
for (let key of curKeybind.keys) {
|
||||||
|
if (typeof key != "string") {
|
||||||
|
throw new Error("invalid keybind key");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newKeyDescriptions.set(curKeybind.command, curKeybind.keys);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
let userError = `${curUserCommand} is invalid: error: ${e}`;
|
||||||
|
console.log(userError);
|
||||||
|
mobx.action(() => {
|
||||||
|
this.userKeybindingError.set(userError);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.keyDescriptionsMap = newKeyDescriptions;
|
||||||
|
console.log("key desc map:", this.keyDescriptionsMap);
|
||||||
|
}
|
||||||
|
|
||||||
processLevel(nativeEvent: any, event: WaveKeyboardEvent, keybindsArray: Array<Keybind>): boolean {
|
processLevel(nativeEvent: any, event: WaveKeyboardEvent, keybindsArray: Array<Keybind>): boolean {
|
||||||
// iterate through keybinds in backwards order
|
// iterate through keybinds in backwards order
|
||||||
@ -196,50 +259,11 @@ class KeybindManager {
|
|||||||
this.domainCallbacks.set(domain, callback);
|
this.domainCallbacks.set(domain, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
setUserKeybindings(userKeybindings) {
|
||||||
this.levelMap = new Map();
|
this.userKeybindings = userKeybindings;
|
||||||
this.domainCallbacks = new Map();
|
|
||||||
this.levelArray = KeybindLevels;
|
|
||||||
for (let index = 0; index < this.levelArray.length; index++) {
|
|
||||||
let curLevel = this.levelArray[index];
|
|
||||||
this.levelMap.set(curLevel, new Array<Keybind>());
|
|
||||||
}
|
|
||||||
this.initKeyDescriptionsMap();
|
this.initKeyDescriptionsMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
initKeyDescriptionsMap() {
|
|
||||||
this.keyDescriptionsMap = new Map();
|
|
||||||
for (let index = 0; index < keybindings.length; index++) {
|
|
||||||
let curKeybind = keybindings[index];
|
|
||||||
this.keyDescriptionsMap.set(curKeybind.command, curKeybind.keys);
|
|
||||||
}
|
|
||||||
let error = false;
|
|
||||||
let numberedTabKeybinds = [];
|
|
||||||
for (let index = 1; index <= 9; index++) {
|
|
||||||
let curKeybind = this.keyDescriptionsMap.get("app:selectTab-" + index);
|
|
||||||
if (curKeybind == null) {
|
|
||||||
error = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
numberedTabKeybinds = numberedTabKeybinds.concat(curKeybind);
|
|
||||||
}
|
|
||||||
if (!error) {
|
|
||||||
this.keyDescriptionsMap.set("app:selectNumberedTab", numberedTabKeybinds);
|
|
||||||
}
|
|
||||||
let numberedWorkspaceKeybinds = [];
|
|
||||||
for (let index = 1; index <= 9; index++) {
|
|
||||||
let curKeybind = this.keyDescriptionsMap.get("app:selectTab-" + index);
|
|
||||||
if (curKeybind == null) {
|
|
||||||
error = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
numberedWorkspaceKeybinds = numberedWorkspaceKeybinds.concat(curKeybind);
|
|
||||||
}
|
|
||||||
if (!error) {
|
|
||||||
this.keyDescriptionsMap.set("app:selectNumberedTab", numberedWorkspaceKeybinds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkKeyPressed(event: WaveKeyboardEvent, keyDescription: string): boolean {
|
checkKeyPressed(event: WaveKeyboardEvent, keyDescription: string): boolean {
|
||||||
if (keyDescription == "any") {
|
if (keyDescription == "any") {
|
||||||
return true;
|
return true;
|
||||||
|
@ -398,6 +398,7 @@ function fireAndForget(f: () => Promise<any>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
handleNotOkResp,
|
||||||
handleJsonFetchResponse,
|
handleJsonFetchResponse,
|
||||||
base64ToString,
|
base64ToString,
|
||||||
stringToBase64,
|
stringToBase64,
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -676,6 +677,24 @@ func HandleRunCommand(w http.ResponseWriter, r *http.Request) {
|
|||||||
WriteJsonSuccess(w, update)
|
WriteJsonSuccess(w, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AuthKeyMiddleWare(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
reqAuthKey := r.Header.Get("X-AuthKey")
|
||||||
|
w.Header().Set(CacheControlHeaderKey, CacheControlHeaderNoCache)
|
||||||
|
if reqAuthKey == "" {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte("no x-authkey header"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if reqAuthKey != GlobalAuthKey {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte("x-authkey header is invalid"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func AuthKeyWrap(fn WebFnType) WebFnType {
|
func AuthKeyWrap(fn WebFnType) WebFnType {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
reqAuthKey := r.Header.Get("X-AuthKey")
|
reqAuthKey := r.Header.Get("X-AuthKey")
|
||||||
@ -904,6 +923,10 @@ func main() {
|
|||||||
gr.HandleFunc("/api/log-active-state", AuthKeyWrap(HandleLogActiveState))
|
gr.HandleFunc("/api/log-active-state", AuthKeyWrap(HandleLogActiveState))
|
||||||
gr.HandleFunc("/api/read-file", AuthKeyWrap(HandleReadFile))
|
gr.HandleFunc("/api/read-file", AuthKeyWrap(HandleReadFile))
|
||||||
gr.HandleFunc("/api/write-file", AuthKeyWrap(HandleWriteFile)).Methods("POST")
|
gr.HandleFunc("/api/write-file", AuthKeyWrap(HandleWriteFile)).Methods("POST")
|
||||||
|
configPath := path.Join(scbase.GetWaveHomeDir(), "config") + "/"
|
||||||
|
log.Printf("[wave] config path: %q\n", configPath)
|
||||||
|
gr.PathPrefix("/config/").Handler(AuthKeyMiddleWare(http.StripPrefix("/config/", http.FileServer(http.Dir(configPath)))))
|
||||||
|
|
||||||
serverAddr := MainServerAddr
|
serverAddr := MainServerAddr
|
||||||
if scbase.IsDevMode() {
|
if scbase.IsDevMode() {
|
||||||
serverAddr = MainServerDevAddr
|
serverAddr = MainServerDevAddr
|
||||||
|
Loading…
Reference in New Issue
Block a user