mirror of https://github.com/jetkvm/kvm.git
added rpc calls to pass name config
This commit is contained in:
parent
2c6c148765
commit
6771755b32
2
go.mod
2
go.mod
|
@ -12,6 +12,7 @@ require (
|
||||||
github.com/creack/pty v1.1.23
|
github.com/creack/pty v1.1.23
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/gosimple/slug v1.15.0
|
||||||
github.com/gwatts/rootcerts v0.0.0-20240401182218-3ab9db955caf
|
github.com/gwatts/rootcerts v0.0.0-20240401182218-3ab9db955caf
|
||||||
github.com/hanwen/go-fuse/v2 v2.5.1
|
github.com/hanwen/go-fuse/v2 v2.5.1
|
||||||
github.com/hashicorp/go-envparse v0.1.0
|
github.com/hashicorp/go-envparse v0.1.0
|
||||||
|
@ -46,6 +47,7 @@ require (
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/gosimple/unidecode v1.0.1 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.17.11 // indirect
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -50,6 +50,10 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo=
|
||||||
|
github.com/gosimple/slug v1.15.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
|
||||||
|
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
|
||||||
|
github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
|
||||||
github.com/gwatts/rootcerts v0.0.0-20240401182218-3ab9db955caf h1:JO6ISZIvEUitto5zjQ3/VEnDM5rPbqIFuOhS0U0ByeA=
|
github.com/gwatts/rootcerts v0.0.0-20240401182218-3ab9db955caf h1:JO6ISZIvEUitto5zjQ3/VEnDM5rPbqIFuOhS0U0ByeA=
|
||||||
github.com/gwatts/rootcerts v0.0.0-20240401182218-3ab9db955caf/go.mod h1:5Kt9XkWvkGi2OHOq0QsGxebHmhCcqJ8KCbNg/a6+n+g=
|
github.com/gwatts/rootcerts v0.0.0-20240401182218-3ab9db955caf/go.mod h1:5Kt9XkWvkGi2OHOq0QsGxebHmhCcqJ8KCbNg/a6+n+g=
|
||||||
github.com/hanwen/go-fuse/v2 v2.5.1 h1:OQBE8zVemSocRxA4OaFJbjJ5hlpCmIWbGr7r0M4uoQQ=
|
github.com/hanwen/go-fuse/v2 v2.5.1 h1:OQBE8zVemSocRxA4OaFJbjJ5hlpCmIWbGr7r0M4uoQQ=
|
||||||
|
|
32
jsonrpc.go
32
jsonrpc.go
|
@ -13,6 +13,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gosimple/slug"
|
||||||
"github.com/pion/webrtc/v4"
|
"github.com/pion/webrtc/v4"
|
||||||
"go.bug.st/serial"
|
"go.bug.st/serial"
|
||||||
)
|
)
|
||||||
|
@ -43,6 +44,11 @@ type BacklightSettings struct {
|
||||||
OffAfter int `json:"off_after"`
|
OffAfter int `json:"off_after"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NameSettings struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
DNS string `json:"dns"`
|
||||||
|
}
|
||||||
|
|
||||||
func writeJSONRPCResponse(response JSONRPCResponse, session *Session) {
|
func writeJSONRPCResponse(response JSONRPCResponse, session *Session) {
|
||||||
responseBytes, err := json.Marshal(response)
|
responseBytes, err := json.Marshal(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -293,6 +299,30 @@ type SSHKeyState struct {
|
||||||
SSHKey string `json:"sshKey"`
|
SSHKey string `json:"sshKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rpcGetNameConfig() (NameConfig, error) {
|
||||||
|
LoadConfig()
|
||||||
|
return config.NameConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func rpcSetNameConfig(deviceName string) (NameConfig, error) {
|
||||||
|
LoadConfig()
|
||||||
|
config.NameConfig = NameConfig{
|
||||||
|
Name: deviceName,
|
||||||
|
DNS: slug.Make(deviceName) + ".local",
|
||||||
|
}
|
||||||
|
|
||||||
|
RestartMDNS()
|
||||||
|
|
||||||
|
err := SaveConfig()
|
||||||
|
if err != nil {
|
||||||
|
return NameConfig{}, fmt.Errorf("failed to save device name: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nameConfig := config.NameConfig
|
||||||
|
log.Printf("[jsonrpc.go:rpcSetNameConfig] device name set to %s, dns name set to %s", nameConfig.Name, nameConfig.DNS)
|
||||||
|
return nameConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
func rpcGetDevModeState() (DevModeState, error) {
|
func rpcGetDevModeState() (DevModeState, error) {
|
||||||
devModeEnabled := false
|
devModeEnabled := false
|
||||||
if _, err := os.Stat(devModeFile); err != nil {
|
if _, err := os.Stat(devModeFile); err != nil {
|
||||||
|
@ -789,6 +819,8 @@ var rpcHandlers = map[string]RPCHandler{
|
||||||
"setDevChannelState": {Func: rpcSetDevChannelState, Params: []string{"enabled"}},
|
"setDevChannelState": {Func: rpcSetDevChannelState, Params: []string{"enabled"}},
|
||||||
"getUpdateStatus": {Func: rpcGetUpdateStatus},
|
"getUpdateStatus": {Func: rpcGetUpdateStatus},
|
||||||
"tryUpdate": {Func: rpcTryUpdate},
|
"tryUpdate": {Func: rpcTryUpdate},
|
||||||
|
"setNameConfig": {Func: rpcSetNameConfig, Params: []string{"deviceName"}},
|
||||||
|
"getNameConfig": {Func: rpcGetNameConfig},
|
||||||
"getDevModeState": {Func: rpcGetDevModeState},
|
"getDevModeState": {Func: rpcGetDevModeState},
|
||||||
"setDevModeState": {Func: rpcSetDevModeState, Params: []string{"enabled"}},
|
"setDevModeState": {Func: rpcSetDevModeState, Params: []string{"enabled"}},
|
||||||
"getSSHKeyState": {Func: rpcGetSSHKeyState},
|
"getSSHKeyState": {Func: rpcGetSSHKeyState},
|
||||||
|
|
12
network.go
12
network.go
|
@ -113,6 +113,13 @@ func checkNetworkState() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RestartMDNS() {
|
||||||
|
err := startMDNS()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func startMDNS() error {
|
func startMDNS() error {
|
||||||
// If server was previously running, stop it
|
// If server was previously running, stop it
|
||||||
if mDNSConn != nil {
|
if mDNSConn != nil {
|
||||||
|
@ -124,7 +131,8 @@ func startMDNS() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a new server
|
// Start a new server
|
||||||
fmt.Printf("Starting mDNS server on jetkvm.local\n")
|
LoadConfig()
|
||||||
|
fmt.Printf("Starting mDNS server on %v\n", config.NameConfig.DNS)
|
||||||
addr4, err := net.ResolveUDPAddr("udp4", mdns.DefaultAddressIPv4)
|
addr4, err := net.ResolveUDPAddr("udp4", mdns.DefaultAddressIPv4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -146,7 +154,7 @@ func startMDNS() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
mDNSConn, err = mdns.Server(ipv4.NewPacketConn(l4), ipv6.NewPacketConn(l6), &mdns.Config{
|
mDNSConn, err = mdns.Server(ipv4.NewPacketConn(l4), ipv6.NewPacketConn(l6), &mdns.Config{
|
||||||
LocalNames: []string{"jetkvm.local"}, //TODO: make it configurable
|
LocalNames: []string{config.NameConfig.DNS},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mDNSConn = nil
|
mDNSConn = nil
|
||||||
|
|
|
@ -23,6 +23,11 @@ const appendStatToMap = <T extends { timestamp: number }>(
|
||||||
export type AvailableSidebarViews = "connection-stats";
|
export type AvailableSidebarViews = "connection-stats";
|
||||||
export type AvailableTerminalTypes = "kvm" | "serial" | "none";
|
export type AvailableTerminalTypes = "kvm" | "serial" | "none";
|
||||||
|
|
||||||
|
export interface NameConfig {
|
||||||
|
name: string;
|
||||||
|
dns: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
sub: string;
|
sub: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
|
import { Button } from "@components/Button";
|
||||||
|
import { InputFieldWithLabel } from "@components/InputField";
|
||||||
import { SettingsPageHeader } from "../components/SettingsPageheader";
|
import { SettingsPageHeader } from "../components/SettingsPageheader";
|
||||||
import { SelectMenuBasic } from "../components/SelectMenuBasic";
|
import { SelectMenuBasic } from "../components/SelectMenuBasic";
|
||||||
import { SettingsItem } from "./devices.$id.settings";
|
import { SettingsItem } from "./devices.$id.settings";
|
||||||
|
import { NameConfig } from "@/hooks/stores";
|
||||||
|
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||||
|
import notifications from "@/notifications";
|
||||||
|
|
||||||
export default function SettingsAppearanceRoute() {
|
export default function SettingsAppearanceRoute() {
|
||||||
const [currentTheme, setCurrentTheme] = useState(() => {
|
const [currentTheme, setCurrentTheme] = useState(() => {
|
||||||
return localStorage.theme || "system";
|
return localStorage.theme || "system";
|
||||||
});
|
});
|
||||||
|
const [nameConfig, setNameConfig] = useState<NameConfig>({
|
||||||
|
name: '',
|
||||||
|
dns: '',
|
||||||
|
});
|
||||||
|
const [send] = useJsonRpc();
|
||||||
|
|
||||||
const handleThemeChange = useCallback((value: string) => {
|
const handleThemeChange = useCallback((value: string) => {
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
|
@ -26,7 +36,26 @@ export default function SettingsAppearanceRoute() {
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
const handleDeviceNameChange = (deviceName: string) => {
|
||||||
|
setNameConfig({... nameConfig, name: deviceName})
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpdateNameConfig = useCallback(() => {
|
||||||
|
send("setNameConfig", { deviceName: nameConfig.name }, resp => {
|
||||||
|
if ("error" in resp) {
|
||||||
|
notifications.error(
|
||||||
|
`Failed to set name config: ${resp.error.data || "Unknown error"}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rNameConfig = resp.result as NameConfig;
|
||||||
|
setNameConfig(rNameConfig);
|
||||||
|
document.title = rNameConfig.name;
|
||||||
|
notifications.success(`Device name set to "${rNameConfig.name}" successfully.\nDNS Name set to "${rNameConfig.dns}"`);
|
||||||
|
});
|
||||||
|
}, [send, nameConfig]);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<SettingsPageHeader
|
<SettingsPageHeader
|
||||||
title="Appearance"
|
title="Appearance"
|
||||||
|
@ -48,6 +77,24 @@ export default function SettingsAppearanceRoute() {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SettingsItem>
|
</SettingsItem>
|
||||||
|
<SettingsItem title="Device Name" description="Set your device name">
|
||||||
|
<InputFieldWithLabel
|
||||||
|
required
|
||||||
|
label=""
|
||||||
|
placeholder="Enter Device Name"
|
||||||
|
description={`DNS Name: ${nameConfig.dns}`}
|
||||||
|
defaultValue={nameConfig.name}
|
||||||
|
onChange={e => handleDeviceNameChange(e.target.value)}
|
||||||
|
/>
|
||||||
|
</SettingsItem>
|
||||||
|
<div className="flex items-center gap-x-2">
|
||||||
|
<Button
|
||||||
|
size="SM"
|
||||||
|
theme="primary"
|
||||||
|
text="Update Device Name"
|
||||||
|
onClick={handleUpdateNameConfig}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue