ipkvm.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/http"
  6. "os"
  7. "os/signal"
  8. "path/filepath"
  9. "strings"
  10. "syscall"
  11. "github.com/gorilla/csrf"
  12. "imuslab.com/dezukvm/dezukvmd/mod/dezukvm"
  13. )
  14. var (
  15. dezukvmManager *dezukvm.DezukVM
  16. listeningServerMux *http.ServeMux
  17. )
  18. func init_ipkvm_mode() error {
  19. listeningServerMux = http.NewServeMux()
  20. //Create a new DezukVM manager
  21. dezukvmManager = dezukvm.NewKvmHostInstance(&dezukvm.RuntimeOptions{
  22. EnableLog: true,
  23. })
  24. // Experimental
  25. connectedUsbKvms, err := dezukvm.ScanConnectedUsbKvmDevices()
  26. if err != nil {
  27. return err
  28. }
  29. for _, dev := range connectedUsbKvms {
  30. err := dezukvmManager.AddUsbKvmDevice(dev)
  31. if err != nil {
  32. return err
  33. }
  34. }
  35. err = dezukvmManager.StartAllUsbKvmDevices()
  36. if err != nil {
  37. return err
  38. }
  39. // ~Experimental
  40. // Handle program exit to close the HID controller
  41. c := make(chan os.Signal, 1)
  42. signal.Notify(c, os.Interrupt, syscall.SIGTERM)
  43. go func() {
  44. <-c
  45. log.Println("Shutting down DezuKVM...")
  46. if dezukvmManager != nil {
  47. dezukvmManager.Close()
  48. }
  49. log.Println("Shutdown complete.")
  50. os.Exit(0)
  51. }()
  52. // Middleware to inject CSRF token into HTML files served from www
  53. listeningServerMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  54. // Only inject for .html files
  55. path := r.URL.Path
  56. if path == "/" {
  57. path = "/index.html"
  58. }
  59. if strings.HasSuffix(path, ".html") {
  60. // Read the HTML file from disk
  61. targetFilePath := filepath.Join("www", filepath.Clean(path))
  62. content, err := os.ReadFile(targetFilePath)
  63. if err != nil {
  64. http.NotFound(w, r)
  65. return
  66. }
  67. htmlContent := string(content)
  68. // Replace CSRF token placeholder
  69. htmlContent = strings.ReplaceAll(htmlContent, "{{.csrfToken}}", csrf.Token(r))
  70. w.Header().Set("Content-Type", "text/html")
  71. w.Write([]byte(htmlContent))
  72. return
  73. }
  74. // Fallback to static file server for non-HTML files
  75. http.FileServer(http.Dir("www")).ServeHTTP(w, r)
  76. })
  77. // Register DezukVM related APIs
  78. register_ipkvm_apis(listeningServerMux)
  79. csrfMiddleware := csrf.Protect(
  80. []byte(nodeUUID),
  81. csrf.CookieName("dezukvm-csrf"),
  82. csrf.Secure(false),
  83. csrf.Path("/"),
  84. csrf.SameSite(csrf.SameSiteLaxMode),
  85. )
  86. err = http.ListenAndServe(":9000", csrfMiddleware(listeningServerMux))
  87. return err
  88. }
  89. func register_ipkvm_apis(mux *http.ServeMux) {
  90. mux.HandleFunc("/api/v1/stream/{uuid}/video", func(w http.ResponseWriter, r *http.Request) {
  91. instanceUUID := r.PathValue("uuid")
  92. fmt.Println("Requested video stream for instance UUID:", instanceUUID)
  93. dezukvmManager.HandleVideoStreams(w, r, instanceUUID)
  94. })
  95. mux.HandleFunc("/api/v1/stream/{uuid}/audio", func(w http.ResponseWriter, r *http.Request) {
  96. instanceUUID := r.PathValue("uuid")
  97. dezukvmManager.HandleAudioStreams(w, r, instanceUUID)
  98. })
  99. mux.HandleFunc("/api/v1/hid/{uuid}/events", func(w http.ResponseWriter, r *http.Request) {
  100. instanceUUID := r.PathValue("uuid")
  101. dezukvmManager.HandleHIDEvents(w, r, instanceUUID)
  102. })
  103. mux.HandleFunc("/api/v1/instances", func(w http.ResponseWriter, r *http.Request) {
  104. if r.Method == http.MethodGet {
  105. dezukvmManager.HandleListInstances(w, r)
  106. } else {
  107. http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
  108. }
  109. })
  110. }