vnc

package
v1.0.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 2, 2026 License: MIT Imports: 17 Imported by: 0

README

VNC Integration with noVNC

This directory contains the VNC integration for pvetui, including an embedded noVNC client.

noVNC Subtree

The noVNC client is vendored via a git subtree rooted at internal/vnc/novnc/ and embedded directly into the compiled binary using Go's embed directive. No extra Git configuration is required when cloning the repository.

Current Source
Updating the Subtree

The preferred workflow is:

make update-novnc

This target runs git subtree pull --prefix=internal/vnc/novnc https://github.com/novnc/noVNC.git master --squash, then executes scripts/prune_novnc.sh to drop development-only assets such as tests, docs, npm tooling, and upstream workflow files.

If you need to update manually:

  1. Run the git subtree pull command above.
  2. Execute ./scripts/prune_novnc.sh to remove non-runtime files.
  3. Stage the cleaned subtree: git add internal/vnc/novnc.
Checking the Embedded Version

Because the subtree history is squashed, pvetui tracks the upstream commit in the merge message. To see the latest synced commit:

git log --oneline --grep="Squashed 'internal/vnc/novnc/'" | head -n 1

For a deeper diff against upstream, split the subtree onto a temporary branch and compare:

git subtree split --prefix=internal/vnc/novnc -b novnc-split
git log -1 novnc-split
# ...perform comparisons...
git branch -D novnc-split
Integration Details

The noVNC client files are embedded directly into the compiled binary using Go's embed directive (//go:embed novnc). This means:

  • Self-Contained: The binary includes all noVNC files and can run without external dependencies
  • No Runtime Filesystem Access: Files are served from memory, not from disk
  • Deployment Simplicity: Only the binary needs to be distributed

The VNC server (internal/vnc/server.go) serves the embedded files using Go's http.FS with the embedded filesystem.

Benefits of Vendoring via Subtree
  1. Zero extra setup: Contributors clone the repository without special flags.
  2. Reproducible builds: All required runtime assets live in-tree and are embedded during compilation.
  3. Controlled footprint: scripts/prune_novnc.sh keeps only the assets needed at runtime.
  4. Straightforward updates: A single Make target manages pulling, pruning, and staging newer upstream versions.
  5. Upstream traceability: Subtree commits retain upstream history in merge messages for auditability.
Testing

Run tests to verify the embedding works correctly:

go test -v ./internal/vnc -run TestNoVNC

Documentation

Overview

Package vnc provides VNC connection services for Proxmox VMs and nodes. This package implements a WebSocket reverse proxy that allows noVNC clients to connect to Proxmox VNC sessions without requiring users to be logged into the Proxmox web interface.

Package vnc provides VNC connection services for Proxmox VMs and nodes.

Package vnc provides VNC session management and concurrent session handling. This package implements a comprehensive session management system that allows multiple concurrent VNC sessions to different targets (VMs, containers, nodes).

The SessionManager handles: - Dynamic port allocation for each VNC session - Session lifecycle management with automatic cleanup - Smart session reuse for the same target - Background monitoring and cleanup of inactive sessions - Thread-safe operations for concurrent access

Example usage:

manager := NewSessionManager(logger)
defer manager.Shutdown()

// Create a new session for a VM
session, err := manager.CreateSession(ctx, "vm", "node1", "100", client)
if err != nil {
	return fmt.Errorf("failed to create VNC session: %w", err)
}

// Session is automatically managed and cleaned up
fmt.Printf("VNC session available at: http://localhost:%d", session.Port)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ProxyConfig

type ProxyConfig struct {
	// VNC proxy details from Proxmox API
	Port     string
	Ticket   string
	Password string

	// Proxmox server details
	ProxmoxHost string
	NodeName    string
	VMID        int
	VMType      string // "qemu" or "lxc"

	// Authentication
	AuthToken string

	// Connection settings
	Timeout time.Duration
}

ProxyConfig holds configuration for the VNC WebSocket proxy.

func CreateNodeProxyConfig

func CreateNodeProxyConfig(client *api.Client, nodeName string) (*ProxyConfig, error)

CreateNodeProxyConfig creates a proxy configuration for a node VNC shell connection.

func CreateNodeProxyConfigWithLogger

func CreateNodeProxyConfigWithLogger(client *api.Client, nodeName string, sharedLogger *logger.Logger) (*ProxyConfig, error)

CreateNodeProxyConfigWithLogger creates a proxy configuration for a node VNC shell connection with shared logger.

func CreateVMProxyConfig

func CreateVMProxyConfig(client *api.Client, vm *api.VM) (*ProxyConfig, error)

CreateVMProxyConfig creates a proxy configuration for a VM VNC connection.

func CreateVMProxyConfigWithLogger

func CreateVMProxyConfigWithLogger(client *api.Client, vm *api.VM, sharedLogger *logger.Logger) (*ProxyConfig, error)

CreateVMProxyConfigWithLogger creates a proxy configuration for a VM VNC connection with shared logger.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server provides an embedded HTTP server for VNC connections.

func NewServer

func NewServer() *Server

NewServer creates a new embedded HTTP server for VNC connections.

func NewServerWithLogger

func NewServerWithLogger(sharedLogger *logger.Logger) *Server

NewServerWithLogger creates a new embedded HTTP server with a shared logger.

func (*Server) GetPort

func (s *Server) GetPort() int

GetPort returns the port the server is running on.

func (*Server) IsRunning

func (s *Server) IsRunning() bool

IsRunning returns whether the server is currently running.

func (*Server) StartNodeVNCServer

func (s *Server) StartNodeVNCServer(client *api.Client, nodeName string) (string, error)

StartNodeVNCServer starts the embedded server for a node VNC shell connection.

func (*Server) StartNodeVNCServerWithSession

func (s *Server) StartNodeVNCServerWithSession(client *api.Client, nodeName string, session SessionNotifier) (string, error)

StartNodeVNCServerWithSession starts the embedded server for a node VNC shell connection with session notifications.

func (*Server) StartVMVNCServer

func (s *Server) StartVMVNCServer(client *api.Client, vm *api.VM) (string, error)

StartVMVNCServer starts the embedded server for a VM VNC connection.

func (*Server) StartVMVNCServerWithSession

func (s *Server) StartVMVNCServerWithSession(client *api.Client, vm *api.VM, session SessionNotifier) (string, error)

StartVMVNCServerWithSession starts the embedded server for a VM VNC connection with session notifications.

func (*Server) Stop

func (s *Server) Stop() error

Stop stops the embedded HTTP server.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides VNC connection management with support for multiple concurrent sessions.

func NewService

func NewService(client *api.Client) *Service

NewService creates a new VNC service with session management capabilities.

func NewServiceWithLogger

func NewServiceWithLogger(client *api.Client, sharedLogger *logger.Logger) *Service

NewServiceWithLogger creates a new VNC service with a shared logger.

func (*Service) CleanupInactiveSessions

func (s *Service) CleanupInactiveSessions(maxAge time.Duration)

CleanupInactiveSessions removes sessions that haven't been accessed recently.

func (*Service) CloseAllSessions

func (s *Service) CloseAllSessions() error

CloseAllSessions closes all active VNC sessions.

func (*Service) CloseSession

func (s *Service) CloseSession(sessionID string) error

CloseSession closes a specific VNC session by ID.

func (*Service) ConnectToNode

func (s *Service) ConnectToNode(nodeName string) error

ConnectToNode opens a VNC shell connection to a node in the user's browser.

func (*Service) ConnectToNodeEmbedded

func (s *Service) ConnectToNodeEmbedded(nodeName string) (string, error)

ConnectToNodeEmbedded opens an embedded VNC shell connection to a node using the built-in noVNC client This method supports multiple concurrent sessions - each node gets its own session.

func (*Service) ConnectToNodeEmbeddedWithClient added in v1.0.14

func (s *Service) ConnectToNodeEmbeddedWithClient(client *api.Client, nodeName string) (string, error)

ConnectToNodeEmbeddedWithClient opens an embedded VNC shell connection to a node using the built-in noVNC client and specific client.

func (*Service) ConnectToVM

func (s *Service) ConnectToVM(vm *api.VM) error

ConnectToVM opens a VNC connection to a VM in the user's browser Note: Validation should be done using GetVMVNCStatus before calling this method.

func (*Service) ConnectToVMEmbedded

func (s *Service) ConnectToVMEmbedded(vm *api.VM) (string, error)

ConnectToVMEmbedded opens an embedded VNC connection to a VM using the built-in noVNC client This method supports multiple concurrent sessions - each VM gets its own session.

func (*Service) ConnectToVMEmbeddedWithClient added in v1.0.14

func (s *Service) ConnectToVMEmbeddedWithClient(client *api.Client, vm *api.VM) (string, error)

ConnectToVMEmbeddedWithClient opens an embedded VNC connection to a VM using the built-in noVNC client and specific client.

func (*Service) GetActiveSessionCount

func (s *Service) GetActiveSessionCount() int

GetActiveSessionCount returns the number of active VNC sessions.

func (*Service) GetEmbeddedServerPort

func (s *Service) GetEmbeddedServerPort() int

GetEmbeddedServerPort returns the port of the first active session (legacy method).

func (*Service) GetNodeVNCStatus

func (s *Service) GetNodeVNCStatus(nodeName string) (bool, string)

GetNodeVNCStatus checks if VNC shell is available for a node.

func (*Service) GetNodeVNCStatusWithClient added in v1.0.14

func (s *Service) GetNodeVNCStatusWithClient(client *api.Client, nodeName string) (bool, string)

GetNodeVNCStatusWithClient checks if VNC shell is available for a node using a specific client.

func (*Service) GetSessionByTarget

func (s *Service) GetSessionByTarget(sessionType SessionType, target string) (*VNCSession, bool)

GetSessionByTarget finds a session by target (VM name or node name).

func (*Service) GetVMVNCStatus

func (s *Service) GetVMVNCStatus(vm *api.VM) (bool, string)

GetVMVNCStatus checks if VNC is available for a VM.

func (*Service) IsEmbeddedServerRunning

func (s *Service) IsEmbeddedServerRunning() bool

IsEmbeddedServerRunning returns whether any embedded VNC servers are running.

func (*Service) ListActiveSessions

func (s *Service) ListActiveSessions() []*VNCSession

ListActiveSessions returns all active VNC sessions.

func (*Service) SetSessionCountCallback

func (s *Service) SetSessionCountCallback(callback func(int))

SetSessionCountCallback registers a callback function that will be called whenever the session count changes. This allows for real-time UI updates.

func (*Service) StopEmbeddedServer

func (s *Service) StopEmbeddedServer() error

StopEmbeddedServer stops all embedded VNC servers (legacy method - now closes all sessions).

func (*Service) UpdateClient

func (s *Service) UpdateClient(client *api.Client)

UpdateClient updates the VNC service's client (used when switching profiles).

type SessionCountCallback

type SessionCountCallback func(count int)

SessionCountCallback is called when the session count changes.

type SessionManager

type SessionManager struct {
	// contains filtered or unexported fields
}

SessionManager manages multiple concurrent VNC sessions with comprehensive lifecycle management, automatic cleanup, and smart session reuse.

The SessionManager provides: - Thread-safe session creation and management - Dynamic port allocation to avoid conflicts - Automatic cleanup of inactive sessions - Session reuse for the same target - Background monitoring and maintenance - Real-time session count notifications via callbacks

All operations are thread-safe and can be called concurrently from multiple goroutines.

func NewSessionManager

func NewSessionManager(client *api.Client) *SessionManager

NewSessionManager creates a new VNC session manager with comprehensive configuration and automatic background maintenance.

The manager will: - Allocate ports dynamically in the range 8080-8180 - Clean up inactive sessions every 5 minutes - Expire sessions after 30 minutes of inactivity - Provide thread-safe concurrent access

The manager must be shut down properly using Shutdown() to clean up background goroutines and active sessions.

func NewSessionManagerWithLogger

func NewSessionManagerWithLogger(client *api.Client, sharedLogger *logger.Logger) *SessionManager

NewSessionManagerWithLogger creates a new VNC session manager with a shared logger.

func (*SessionManager) CleanupInactiveSessions

func (sm *SessionManager) CleanupInactiveSessions(maxAge time.Duration)

CleanupInactiveSessions removes sessions that haven't been accessed recently.

func (*SessionManager) CloseAllSessions

func (sm *SessionManager) CloseAllSessions() error

CloseAllSessions closes all active sessions.

func (*SessionManager) CloseSession

func (sm *SessionManager) CloseSession(sessionID string) error

CloseSession closes a specific session by ID.

func (*SessionManager) CreateNodeSession

func (sm *SessionManager) CreateNodeSession(nodeName string) (*VNCSession, error)

CreateNodeSession creates a new VNC session for a node shell. If a session already exists for the same node, it may be reused.

func (*SessionManager) CreateNodeSessionWithClient added in v1.0.14

func (sm *SessionManager) CreateNodeSessionWithClient(client *api.Client, nodeName string) (*VNCSession, error)

CreateNodeSessionWithClient creates a new VNC session for a node shell using a specific client.

func (*SessionManager) CreateSession

func (sm *SessionManager) CreateSession(ctx context.Context, sessionType SessionType, nodeName, vmid, targetName string) (*VNCSession, error)

CreateSession creates a new VNC session for the specified target using the default client.

func (*SessionManager) CreateSessionWithClient added in v1.0.14

func (sm *SessionManager) CreateSessionWithClient(ctx context.Context, client *api.Client, sessionType SessionType, nodeName, vmid, targetName string) (*VNCSession, error)

CreateSessionWithClient creates a new VNC session for the specified target using a specific client.

func (*SessionManager) CreateVMSession

func (sm *SessionManager) CreateVMSession(vm *api.VM) (*VNCSession, error)

CreateVMSession creates a new VNC session for a VM. If a session already exists for the same VM, it may be reused.

func (*SessionManager) CreateVMSessionWithClient added in v1.0.14

func (sm *SessionManager) CreateVMSessionWithClient(client *api.Client, vm *api.VM) (*VNCSession, error)

CreateVMSessionWithClient creates a new VNC session for a VM using a specific client.

func (*SessionManager) GetSessionByTarget

func (sm *SessionManager) GetSessionByTarget(sessionType SessionType, target string) (*VNCSession, bool)

GetSessionByTarget finds a session by target information.

func (*SessionManager) GetSessionCount

func (sm *SessionManager) GetSessionCount() int

GetSessionCount returns the number of currently active VNC sessions. This is useful for UI display and monitoring purposes.

func (*SessionManager) ListSessions

func (sm *SessionManager) ListSessions() []*VNCSession

ListSessions returns a slice of all currently active VNC sessions. The returned sessions are copies and safe to use without additional locking.

func (*SessionManager) SetSessionCountCallback

func (sm *SessionManager) SetSessionCountCallback(callback SessionCountCallback)

SetSessionCountCallback registers a callback function that will be called whenever the session count changes. This allows for real-time UI updates.

func (*SessionManager) Shutdown

func (sm *SessionManager) Shutdown() error

Shutdown gracefully shuts down the session manager and all active sessions. This should be called when the application is shutting down to ensure proper cleanup of resources.

func (*SessionManager) UpdateClient

func (sm *SessionManager) UpdateClient(client *api.Client)

UpdateClient updates the session manager's client (used when switching profiles).

type SessionNotifier

type SessionNotifier interface {
	OnClientConnected()
	OnClientDisconnected()
	UpdateLastUsed()
}

SessionNotifier interface for notifying session about connection events.

type SessionState

type SessionState int

SessionState represents the current state of a VNC session.

const (
	SessionStateActive       SessionState = iota // Session is active and ready for connections
	SessionStateConnected                        // Client is currently connected
	SessionStateDisconnected                     // Client disconnected, session may be reusable
	SessionStateClosed                           // Session is closed and should be cleaned up
)

type SessionType

type SessionType string

SessionType represents the type of VNC session.

const (
	SessionTypeVM   SessionType = "vm"
	SessionTypeLXC  SessionType = "lxc"
	SessionTypeNode SessionType = "node"
)

type VNCSession

type VNCSession struct {
	// ID is a unique identifier for this session, used for tracking and management
	ID string

	// Target information for the VNC connection
	TargetType SessionType // "vm", "lxc", or "node"
	NodeName   string      // Proxmox node name
	VMID       string      // VM/Container ID (empty for node shells)
	TargetName string      // Display name for the target

	// Network configuration
	Port int    // Local HTTP server port for this session
	URL  string // Full URL to access this session

	// Session lifecycle tracking
	CreatedAt time.Time    // When this session was created
	LastUsed  time.Time    // Last time this session was accessed
	State     SessionState // Current connection state

	// VNC connection details
	ProxyConfig *ProxyConfig // VNC proxy configuration from Proxmox API

	// Server management
	Server *Server // The HTTP server instance for this session
	// contains filtered or unexported fields
}

VNCSession represents an active VNC session with comprehensive metadata and lifecycle management. Each session corresponds to a single VNC connection to a Proxmox target (VM, container, or node shell).

func (*VNCSession) GetConnectionCount

func (s *VNCSession) GetConnectionCount() int

GetConnectionCount returns the number of active connections to this session.

func (*VNCSession) GetTargetKey

func (s *VNCSession) GetTargetKey() string

GetTargetKey returns a unique key identifying the target of this session. Sessions with the same target key can potentially be reused.

func (*VNCSession) IsExpired

func (s *VNCSession) IsExpired(timeout time.Duration) bool

IsExpired checks if this session has been inactive for longer than the specified timeout duration. Expired sessions are candidates for cleanup.

func (*VNCSession) IsReusable

func (s *VNCSession) IsReusable() bool

IsReusable returns true if this session can be reused for new connections.

func (*VNCSession) OnClientConnected

func (s *VNCSession) OnClientConnected()

OnClientConnected is called when a client connects to this session.

func (*VNCSession) OnClientDisconnected

func (s *VNCSession) OnClientDisconnected()

OnClientDisconnected is called when a client disconnects from this session.

func (*VNCSession) Shutdown

func (s *VNCSession) Shutdown() error

Shutdown gracefully shuts down this VNC session, stopping the HTTP server and cleaning up all associated resources.

func (*VNCSession) UpdateLastUsed

func (s *VNCSession) UpdateLastUsed()

UpdateLastUsed updates the last used timestamp for this session. This is called whenever the session is accessed to track activity for cleanup purposes.

type WebSocketProxy

type WebSocketProxy struct {
	// contains filtered or unexported fields
}

WebSocketProxy handles the bidirectional WebSocket proxy between noVNC client and Proxmox VNC websocket endpoint.

func NewWebSocketProxy

func NewWebSocketProxy(config *ProxyConfig) *WebSocketProxy

NewWebSocketProxy creates a new WebSocket proxy with the given configuration.

func NewWebSocketProxyWithSession

func NewWebSocketProxyWithSession(config *ProxyConfig, session SessionNotifier) *WebSocketProxy

NewWebSocketProxyWithSession creates a new WebSocket proxy with session notifications.

func NewWebSocketProxyWithSessionAndLogger

func NewWebSocketProxyWithSessionAndLogger(config *ProxyConfig, session SessionNotifier, sharedLogger *logger.Logger) *WebSocketProxy

NewWebSocketProxyWithSessionAndLogger creates a new WebSocket proxy with session notifications and shared logger.

func (*WebSocketProxy) HandleWebSocketProxy

func (p *WebSocketProxy) HandleWebSocketProxy(w http.ResponseWriter, r *http.Request)

HandleWebSocketProxy handles incoming WebSocket connections from noVNC client and proxies them to the Proxmox VNC websocket endpoint.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL