Initial commit.
This commit is contained in:
commit
9d440e71c1
|
@ -0,0 +1 @@
|
|||
/kvmswitcher
|
|
@ -0,0 +1,22 @@
|
|||
[globals]
|
||||
listen = ":5051"
|
||||
|
||||
[[targets]]
|
||||
id = "host"
|
||||
commands = [
|
||||
"sudo virsh detach-device win11 --file ~/.config/kvmswitcher/keyboard.xml --current",
|
||||
"sudo virsh detach-device win11 --file ~/.config/kvmswitcher/mouse.xml --current",
|
||||
"sudo ddcutil setvcp 0x60 --display 1 0x0f",
|
||||
"sleep 0.5",
|
||||
"sudo chvt 1",
|
||||
"sleep 0.5",
|
||||
"sudo chvt 5",
|
||||
]
|
||||
|
||||
[[targets]]
|
||||
id = "guest"
|
||||
commands = [
|
||||
"sudo virsh attach-device win11 --file ~/.config/kvmswitcher/keyboard.xml --current",
|
||||
"sudo virsh attach-device win11 --file ~/.config/kvmswitcher/mouse.xml --current",
|
||||
"sudo ddcutil setvcp 0x60 --display 1 0x12",
|
||||
]
|
|
@ -0,0 +1,5 @@
|
|||
module gitea.elkins.co/Networking/kvmswitcher
|
||||
|
||||
go 1.19
|
||||
|
||||
require github.com/BurntSushi/toml v1.2.0
|
|
@ -0,0 +1,2 @@
|
|||
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
|
||||
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
|
@ -0,0 +1,25 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
type TargetId string
|
||||
type Command string
|
||||
type Target struct {
|
||||
Id TargetId
|
||||
Commands []Command
|
||||
}
|
||||
type Targets []Target
|
||||
|
||||
type T struct {
|
||||
Globals struct {
|
||||
Listen *string
|
||||
}
|
||||
Targets
|
||||
}
|
||||
|
||||
func Read(f string) (t T, err error) {
|
||||
_, err = toml.DecodeFile(f, &t)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=Switch kvm devices based on configured REST endpoint
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=kvmswitcher
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
|
@ -0,0 +1,88 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
|
||||
"gitea.elkins.co/Networking/kvmswitcher/internal/config"
|
||||
)
|
||||
|
||||
var (
|
||||
confFile = flag.String("config",
|
||||
path.Join(os.Getenv("HOME"), ".config", "kvmswitcher", "config.toml"),
|
||||
"Path to the configuration file",
|
||||
)
|
||||
listen = flag.String("listen", ":5001", "Address and port to listen on")
|
||||
targets config.Targets
|
||||
)
|
||||
|
||||
func targetIds(t config.Targets) []config.TargetId {
|
||||
x := make([]config.TargetId, len(t))
|
||||
for i := range t {
|
||||
x[i] = t[i].Id
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.SetOutput(os.Stderr)
|
||||
flag.Parse()
|
||||
|
||||
c, err := config.Read(*confFile)
|
||||
if err != nil {
|
||||
log.Println("Could not read config file: ", err)
|
||||
}
|
||||
|
||||
targets = c.Targets
|
||||
if c.Globals.Listen != nil {
|
||||
listen = c.Globals.Listen
|
||||
}
|
||||
|
||||
log.Printf("configured hosts: %v\n", targetIds(targets))
|
||||
log.Printf("listening on %s\n", *listen)
|
||||
http.HandleFunc("/to/", doSwitch)
|
||||
http.ListenAndServe(*listen, nil)
|
||||
}
|
||||
|
||||
func doSwitch(w http.ResponseWriter, r *http.Request) {
|
||||
ct, _ := regexp.Compile("^/to/")
|
||||
u := config.TargetId(ct.ReplaceAllString(r.URL.String(), ""))
|
||||
if u == config.TargetId(r.URL.String()) {
|
||||
fmt.Fprintf(w, "Malformed request: %s\n", u)
|
||||
return
|
||||
}
|
||||
var t *config.Target
|
||||
for i := range targets {
|
||||
if targets[i].Id == config.TargetId(u) {
|
||||
t = &targets[i]
|
||||
}
|
||||
}
|
||||
if t == nil {
|
||||
fmt.Fprintf(w, "Invalid Target: %s\n", u)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "Switching to %s\n", u)
|
||||
out, err := runCommands(t.Commands)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "ERROR:\n%s", err)
|
||||
}
|
||||
fmt.Fprintf(w, "OUTPUT:\n%s", out)
|
||||
}
|
||||
|
||||
func runCommands(cmds []config.Command) (out string, err error) {
|
||||
for _, c := range cmds {
|
||||
o, err := exec.Command("/bin/sh", "-c", string(c)).Output()
|
||||
if err != nil {
|
||||
return out, fmt.Errorf("Error executing %s: %s\n", c, err)
|
||||
}
|
||||
out = out + string(o)
|
||||
}
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue