Documentation
¶
Overview ¶
event.go implements Server-Sent Events (SSE) streaming for real-time instance log and status updates, and manages the event dispatcher goroutine.
instance.go manages the lifecycle of nodepass child-process instances: starting, stopping, monitoring, URL generation, and configuration updates.
Package master implements the nodepass management plane. It exposes a REST API and an MCP (Model Context Protocol) JSON-RPC endpoint for creating, configuring, starting, and monitoring tunnel instances. Each instance runs as a child process with its own client or server configuration.
mcp.go implements the Model Context Protocol (MCP) HTTP endpoint for the Master API. It routes JSON-RPC 2.0 requests to the appropriate handler and provides tool schema definitions, tool execution logic, and shared response/error writers used by all MCP sub-handlers.
openapi.go embeds the Swagger UI HTML template and serves the OpenAPI spec for the master REST API documentation endpoint.
periodic.go runs background maintenance tasks for the master: periodic state backup, instance cleanup (removing stopped/errored instances), and scheduled instance restarts.
rest.go implements the REST API handlers for the Master: CRUD operations on tunnel instances, system info, TCP latency probing, and the OpenAPI spec endpoint.
state.go handles persistence of master state: saving and loading the instance registry to/from disk using GOB serialization for crash recovery.
sysinfo.go collects system information (OS, CPU, memory, uptime) and master metadata for the /info REST endpoint and MCP tools.
types.go defines all shared data structures for the master package: Master, Instance, Meta, Peer, log writer, event, system info, MCP, and REST types.
util.go provides shared HTTP helpers (CORS headers, JSON writer, error responder) and ID generators used across the master REST and MCP handlers.
Index ¶
- Constants
- func GenerateAPIKey() string
- func GenerateID() string
- func GenerateMID() string
- func HTTPError(w http.ResponseWriter, message string, statusCode int)
- func SetCorsHeaders(w http.ResponseWriter)
- func WriteJSON(w http.ResponseWriter, statusCode int, data any)
- type Instance
- type InstanceEvent
- type InstanceLogWriter
- type MCPRequest
- type MCPResponse
- type MCPToolCallParams
- type Master
- func (m *Master) EnhanceURL(instanceURL string, instanceType string) string
- func (m *Master) FindInstance(id string) (*Instance, bool)
- func (m *Master) GenerateConfigURL(instance *Instance) string
- func (m *Master) GenerateOpenAPISpec() string
- func (m *Master) GetMasterInfo() map[string]any
- func (m *Master) HandleDeleteInstance(w http.ResponseWriter, id string, instance *Instance)
- func (m *Master) HandleGetInstance(w http.ResponseWriter, instance *Instance)
- func (m *Master) HandleInfo(w http.ResponseWriter, r *http.Request)
- func (m *Master) HandleInstanceDetail(w http.ResponseWriter, r *http.Request)
- func (m *Master) HandleInstances(w http.ResponseWriter, r *http.Request)
- func (m *Master) HandleMCP(w http.ResponseWriter, r *http.Request)
- func (m *Master) HandleMCPInitialize(w http.ResponseWriter, req MCPRequest)
- func (m *Master) HandleMCPToolsCall(w http.ResponseWriter, req MCPRequest)
- func (m *Master) HandleMCPToolsList(w http.ResponseWriter, req MCPRequest)
- func (m *Master) HandleOpenAPISpec(w http.ResponseWriter, r *http.Request)
- func (m *Master) HandlePatchInstance(w http.ResponseWriter, r *http.Request, id string, instance *Instance)
- func (m *Master) HandlePutInstance(w http.ResponseWriter, r *http.Request, id string, instance *Instance)
- func (m *Master) HandleSSE(w http.ResponseWriter, r *http.Request)
- func (m *Master) HandleSwaggerUI(w http.ResponseWriter, r *http.Request)
- func (m *Master) HandleTCPing(w http.ResponseWriter, r *http.Request)
- func (m *Master) LoadState()
- func (m *Master) MasterShutdown(ctx context.Context) error
- func (m *Master) MonitorInstance(instance *Instance, cmd *exec.Cmd)
- func (m *Master) PerformPeriodicBackup()
- func (m *Master) PerformPeriodicCleanup()
- func (m *Master) PerformPeriodicRestart()
- func (m *Master) PerformTCPing(target string) *TCPingResult
- func (m *Master) ProcessInstanceAction(instance *Instance, action string)
- func (m *Master) ReGenerateAPIKey(instance *Instance)
- func (m *Master) Run()
- func (m *Master) SaveState() error
- func (m *Master) SaveStateToPath(filePath string) error
- func (m *Master) SendSSEEvent(eventType string, instance *Instance, logs ...string)
- func (m *Master) SetInstanceURL(instance *Instance, updates map[string]string) error
- func (m *Master) ShutdownSSEConnections()
- func (m *Master) StartEventDispatcher()
- func (m *Master) StartInstance(instance *Instance)
- func (m *Master) StartPeriodicTasks()
- func (m *Master) StopInstance(instance *Instance)
- func (m *Master) WriteMCPError(w http.ResponseWriter, id any, code int, message string, data any)
- func (m *Master) WriteMCPResponse(w http.ResponseWriter, id any, result any)
- type Meta
- type Peer
- type SystemInfo
- type TCPingResult
Constants ¶
const ( // DefaultAPIPath is the default base path for REST API endpoints (/api). // Can be overridden via the URL path parameter when starting the master. DefaultAPIPath = "/api" // OpenAPIVersion is the REST API version suffix (v1), appended to the API prefix // to form the full API path (e.g., /api/v1/instances). OpenAPIVersion = "v1" // NextMCPVersion is the URL path suffix for the MCP JSON-RPC 2.0 endpoint (v2), // typically served at /api/v2 for future protocol upgrades. NextMCPVersion = "v2" // MCPVersion is the Model Context Protocol version advertised to clients in the // "initialize" handshake response, following the format YYYY-MM-DD. MCPVersion = "2025-11-25" // StateFilePath is the relative directory name where the master state file is stored // within the binary's directory (gob/). StateFilePath = "gob" // StateFileName is the filename of the master's persisted instance registry // using GOB serialization (nodepass.gob). StateFileName = "nodepass.gob" // ExportFileName is the filename for exported instance configurations in JSON format // (nodepass.json), used by export_instances and import_instances MCP tools. ExportFileName = "nodepass.json" // SSERetryTime is the retry interval in milliseconds (3000ms = 3s) sent to SSE clients // in the "retry:" field, instructing them to reconnect if the connection is lost. SSERetryTime = 3000 // APIKeyID is a special instance ID (****) reserved for storing the master's API key // and Master ID. It's not a real instance and is not included in instance lists. APIKeyID = "********" // PingSemLimit is the maximum number of concurrent TCP ping operations (10), // enforced via a semaphore to prevent resource exhaustion on high-load systems. PingSemLimit = 10 // BaseDuration is the base wait time (100ms) used for delays between operations: // - Between stopping and restarting instances during restart action // - Between auto-starting instances during state load // - In GetLinuxSysInfo for CPU usage delta calculation BaseDuration = 100 * time.Millisecond // GracefulTimeout is the maximum time (5s) allowed for graceful process shutdown // (SIGTERM/SIGINT) before sending SIGKILL force termination. GracefulTimeout = 5 * time.Second // MaxValueLen is the maximum length (256 characters) for string fields in the API, // including instance aliases, peer information, tag keys/values, and master alias, // to prevent unbounded memory usage from malicious or misconfigured clients. MaxValueLen = 256 )
Master API path, version, and operational constants.
const SwaggerUIHTML = `` /* 528-byte string literal not displayed */
SwaggerUIHTML is the HTML template for embedding Swagger UI in the API documentation endpoint. The %s placeholder is replaced with the JSON-formatted OpenAPI specification generated by GenerateOpenAPISpec(). This allows the master to serve interactive API documentation at the /docs endpoint, enabling users to explore and test the REST API directly from their browsers. The template includes links to the Swagger UI CSS and JS from a CDN, and initializes the UI with the provided OpenAPI spec on page load.
Variables ¶
This section is empty.
Functions ¶
func GenerateAPIKey ¶
func GenerateAPIKey() string
GenerateAPIKey generates a random 32-character hexadecimal API key for authentication.
Reads 16 random bytes from crypto/rand and encodes them as hexadecimal, producing a 32-character alphanumeric string. This API key is used in the X-API-Key HTTP header to authenticate requests to protected endpoints. The key is persisted in the master's instance registry for crash recovery.
func GenerateID ¶
func GenerateID() string
GenerateID generates a random 8-character hexadecimal ID for instances.
Reads 4 random bytes from crypto/rand and encodes them as hexadecimal, producing an 8-character alphanumeric string. Used to generate unique identifiers for new instances when they are created via the API.
func GenerateMID ¶
func GenerateMID() string
GenerateMID generates a random 16-character hexadecimal Master ID.
Reads 8 random bytes from crypto/rand and encodes them as hexadecimal, producing a 16-character alphanumeric string. The Master ID uniquely identifies a nodepass master instance across the network and is persisted in the state file.
func HTTPError ¶
func HTTPError(w http.ResponseWriter, message string, statusCode int)
HTTPError writes an HTTP error response with the given message and status code.
Sets CORS headers and Content-Type to application/json, then writes the status code. The error message is encoded as a JSON object with an "error" key, for example: {"error": "Invalid request body"}. This ensures consistent error formatting across all API endpoints.
Parameters:
- w: The HTTP response writer
- message: Human-readable error message
- statusCode: HTTP status code (e.g., 400, 401, 404, 500)
func SetCorsHeaders ¶
func SetCorsHeaders(w http.ResponseWriter)
SetCorsHeaders sets HTTP CORS headers to allow cross-origin requests from any origin.
Adds the following CORS headers to the response:
- Access-Control-Allow-Origin: * (allow all origins)
- Access-Control-Allow-Methods: GET, PATCH, POST, PUT, DELETE, OPTIONS
- Access-Control-Allow-Headers: Content-Type, Authorization, X-API-Key, Cache-Control
This enables browser-based clients to make cross-origin requests to the API.
func WriteJSON ¶
func WriteJSON(w http.ResponseWriter, statusCode int, data any)
WriteJSON writes data as JSON response with the given status code and CORS headers.
Sets CORS headers and Content-Type to application/json, writes the status code, and encodes the provided data as JSON. This is the standard response writer for successful API operations returning structured data (instances, info, etc.). The data can be any type that json.Encoder can marshal (structs, slices, maps).
Parameters:
- w: The HTTP response writer
- statusCode: HTTP status code (e.g., 200, 201, 204)
- data: The data structure to encode as JSON
Types ¶
type Instance ¶
type Instance struct {
ID string `json:"id"`
Alias string `json:"alias"`
Type string `json:"type"`
Status string `json:"status"`
URL string `json:"url"`
Config string `json:"config"`
Restart bool `json:"restart"`
Meta Meta `json:"meta"`
Mode int32 `json:"mode"`
Ping int32 `json:"ping"`
Pool int32 `json:"pool"`
TCPS int32 `json:"tcps"`
UDPS int32 `json:"udps"`
TCPRX uint64 `json:"tcprx"`
TCPTX uint64 `json:"tcptx"`
UDPRX uint64 `json:"udprx"`
UDPTX uint64 `json:"udptx"`
// contains filtered or unexported fields
}
Instance represents a single managed tunnel (client or server). It is serialised to/from the state file and returned by the REST/MCP APIs. Runtime-only fields (Cmd, Stopped, CancelFunc) are not persisted.
Exported fields are serialized to JSON and GOB for API responses and state persistence. Metrics (Mode, Ping, Pool, TCPS/UDPS, TCPRX/TCPTX/UDPRX/UDPTX) are updated from CHECK_POINT events parsed from instance log output. Traffic counters (TCPRX, etc.) are delta-based, calculated from base values and reset values to allow counters to wrap. Status can be "running", "stopped", or "error". Restart flag controls auto-restart behavior. Config is a complete URL with all parameters filled in from master defaults and instance settings, sent to clients for configuration. Runtime fields are re-initialized on load:
- cmd: The child process handle
- stopped: Channel signaling instance shutdown
- deleted: Flag indicating the instance is marked for removal
- cancelFunc: Function to cancel the process context
- lastCheckPoint: Timestamp of last CHECK_POINT event (for heartbeat detection)
type InstanceEvent ¶
type InstanceEvent struct {
Type string `json:"type"`
Time time.Time `json:"time"`
Instance *Instance `json:"instance"`
Logs string `json:"logs"`
}
InstanceEvent is the payload sent over the SSE stream when an instance status, metric, or log line changes.
Type categorizes the event: "initial" (initial state on SSE connection), "create" (new instance), "update" (status/metric change), "delete" (instance removed), "log" (new log line), or "shutdown" (master shutting down). Time records when the event occurred. Instance is the current state snapshot at the time of the event. Logs contains a single log line if Type is "log"; for other types, it is empty. These events are JSON-serialized and sent to all connected SSE subscribers in real-time.
type InstanceLogWriter ¶
type InstanceLogWriter struct {
InstanceID string
Instance *Instance
Target io.Writer
Master *Master
CheckPoint *regexp.Regexp
}
InstanceLogWriter is an io.Writer that captures child-process log output, updates instance metric fields from CHECK_POINT events, and tees output to the underlying Target writer (usually os.Stdout).
Implements the io.Writer interface to be used as stdout/stderr for child processes. Each Write call scans for CHECK_POINT log lines (format: CHECK_POINT|MODE=...|PING=...|...) and extracts metrics into the instance. Non-CHECK_POINT lines are logged with the instance ID appended. Error lines ("Server error:", "Client error:") update instance status to "error". All updates trigger SSE events to notify subscribers. The Target writer allows logs to be simultaneously written to stdout or a file for debugging.
func NewInstanceLogWriter ¶
func NewInstanceLogWriter(instanceID string, instance *Instance, target io.Writer, master *Master) *InstanceLogWriter
NewInstanceLogWriter creates a new InstanceLogWriter that parses instance output logs and extracts metrics and status information for real-time monitoring.
The log writer processes child process output, looking for CHECK_POINT events containing instance metrics (mode, ping, pool size, connection stats). These metrics are extracted via regex and updated in the instance state. All output is simultaneously written to the target (usually stdout for logging purposes). The instance status is automatically updated from error to running when a CHECK_POINT is received.
Parameters:
- instanceID: Unique identifier for the instance (for logging)
- instance: Pointer to the Instance being monitored
- target: io.Writer to receive all output (stdout, file, etc.)
- master: Reference to the Master for sending SSE events and accessing the instance registry
Returns a new InstanceLogWriter configured with the CHECK_POINT regex pattern.
func (*InstanceLogWriter) Write ¶
func (w *InstanceLogWriter) Write(p []byte) (n int, err error)
Write processes instance log output, extracting metrics from CHECK_POINT events and forwarding logs to the target writer.
Scans incoming log lines for CHECK_POINT events containing metrics like mode, ping latency, connection pool size, and traffic statistics. When a CHECK_POINT is found, the instance fields are updated with parsed values. Traffic counters account for resets by subtracting base and reset values. The instance status is automatically updated to "running" if it was in "error" state. Lines containing "Server error:" or "Client error:" mark the instance as errored. Non-CHECK_POINT lines are logged with the instance ID appended. All events trigger SSE broadcasts to subscribers.
Parameters:
- p: Byte slice containing the log data to process
Returns the number of bytes processed (always len(p)) and any scanning errors.
type MCPRequest ¶
type MCPRequest struct {
JSONRPC string `json:"jsonrpc"`
ID any `json:"id,omitempty"`
Method string `json:"method"`
Params json.RawMessage `json:"params,omitempty"`
}
MCPRequest is the JSON-RPC 2.0 request envelope for the MCP API.
JSONRPC must be "2.0" (validated by HandleMCP). ID is an optional request identifier (can be a string, number, or omitted for notifications). Method specifies the RPC method to call (e.g., "initialize", "tools/list", "tools/call"). Params contains the method parameters as raw JSON (decoded into specific types by each handler). Used by Claude and other MCP clients to request tool execution on the master.
type MCPResponse ¶
type MCPResponse struct {
JSONRPC string `json:"jsonrpc"`
ID any `json:"id,omitempty"`
Result any `json:"result,omitempty"`
Error *struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data,omitempty"`
} `json:"error,omitempty"`
}
MCPResponse is the JSON-RPC 2.0 response envelope. Exactly one of Result or Error is populated.
JSONRPC is always "2.0". ID echoes the request ID (omitted for notifications). Result contains the method's return value if successful; Error is populated if the call failed. Standard error codes follow JSON-RPC 2.0 spec:
- -32700: Parse error
- -32600: Invalid Request
- -32601: Method not found
- -32602: Invalid params
- -32603: Internal error
Data is optional context for the error (e.g., field name that failed validation).
type MCPToolCallParams ¶
type MCPToolCallParams struct {
Name string `json:"name"`
Arguments map[string]any `json:"arguments,omitempty"`
}
MCPToolCallParams contains the parameters for an MCP tool call request.
Name is the name of the tool to execute (e.g., "create_instance", "control_instance"). Arguments is a map of parameter names to values, with types determined by the tool's input schema. Unknown or invalid argument types are handled gracefully by the handlers (type assertions with defaults or error returns). Decoded from the MCPRequest.Params field by HandleMCPToolsCall.
type Master ¶
type Master struct {
common.Common
MID string // unique master instance identifier
Alias string // human-readable name
Prefix string // URL prefix for all API routes
Version string // build version string
Hostname string // public hostname used in generated configs
LogLevel string // current log level ("debug", "info", etc.)
CrtPath string // path to TLS certificate for mTLS
KeyPath string // path to TLS private key for mTLS
Instances sync.Map // id → *Instance for all managed tunnels
Server *http.Server // HTTP/HTTPS API server
MTLSConfig *tls.Config // mTLS config for the management interface
MasterURL *url.URL // URL advertised to clients for self-registration
StatePath string // filesystem path for persistent state file
StateMu sync.Mutex // guards state file I/O
Subscribers sync.Map // SSE subscribers: id → http.ResponseWriter
NotifyChannel chan *InstanceEvent // inbound instance status events
TCPingSem chan struct{} // semaphore limiting concurrent TCPing operations
StartTime time.Time // when this Master instance started
PeriodicDone chan struct{} // closed when background periodic tasks finish
}
Master is the management-plane controller. It embeds common.Common for shared networking utilities and maintains a registry of running tunnel Instances. It exposes HTTP endpoints for REST and MCP management.
The Master manages the lifecycle of tunnel instances, provides REST and MCP APIs, persists state to disk, broadcasts events via SSE, and performs periodic maintenance. All instances are stored in a thread-safe sync.Map for concurrent access. The Master can be configured with mTLS for secure communication with clients. State is persisted using GOB serialization to allow recovery from crashes. Background tasks run periodically to backup state, clean up duplicates, and restart failed instances.
func NewMaster ¶
func NewMaster(parsedURL *url.URL, tlsCode string, tlsConfig *tls.Config, logger *common.Logger, version string) (*Master, error)
NewMaster constructs and returns a Master from a parsed URL, TLS config, logger, and binary version string. It resolves the listen address, derives the API prefix and MID hostname, loads persisted state, and starts the SSE event dispatcher goroutine.
The URL is parsed to extract the host and port for listening, and optionally uses the TLS ServerName for the public hostname. The path becomes the API prefix (defaulting to /api if not specified). The master binary's directory is used to locate the state file. A notification channel and semaphore are initialized for event broadcasting and TCP ping operations. The master startup time is recorded for uptime calculations.
Parameters:
- parsedURL: The parsed URL containing host, port, path, and query parameters
- tlsCode: TLS mode code ("0" for none, "1" for self-signed, "2" for custom certs)
- tlsConfig: Optional TLS configuration for HTTPS
- logger: Logger instance for error and info messages
- version: Build/binary version string
Returns a new Master instance or an error if address resolution fails.
func (*Master) EnhanceURL ¶
EnhanceURL adds master configuration parameters to an instance URL. It parses the URL, updates query parameters based on master settings and instance type, and returns the enhanced URL string.
If the master has LogLevel configured and the URL doesn't already specify "log", adds the master's log level to the query. For server instances with TLS enabled (tlsCode != "0"), adds the TLS mode. If TLS mode is "2" (custom certs), adds the certificate and key file paths if not already specified. This allows master-wide configuration to be injected into instance URLs while respecting explicit URL parameters. Server instances also receive the default pool backend if none is configured.
Parameters:
- instanceURL: The instance URL to enhance (scheme://[user@]host:port/path?query)
- instanceType: The instance type ("server" or "client")
Returns the enhanced URL string, or the original URL if parsing fails.
func (*Master) FindInstance ¶
FindInstance retrieves an instance from the master's instance map by ID. Returns the instance and a boolean indicating whether it was found.
Performs a thread-safe lookup in the Instances sync.Map. The returned instance pointer should not be modified directly; use the update methods and re-store the instance in the map to ensure changes are persisted.
Parameters:
- id: The unique instance identifier
Returns the instance pointer (if found) and a boolean (true if found, false otherwise).
func (*Master) GenerateConfigURL ¶
GenerateConfigURL generates a full configuration URL for an instance. It parses the URL, updates query parameters based on master settings and instance type, and returns the enhanced URL string.
Similar to EnhanceURL, but also adds sensible default parameters for clients and servers if not already specified. For clients, includes DNS TTL, SNI, load balancing strategy, pool size, mode, source IP, read timeout, rate limit, connection slots, PROXY protocol, blocked protocols, and TCP/UDP enable/disable flags. Servers get DNS TTL, load balancing, max pool size, mode, pool backend, source IP, timeouts, rate limits, and protocol settings. Master-level TLS and log settings are also applied. This ensures every instance has a complete, runnable configuration derived from master defaults and explicit instance parameters.
Parameters:
- instance: The instance to generate config for
Returns the full configuration URL string.
func (*Master) GenerateOpenAPISpec ¶
GenerateOpenAPISpec generates an OpenAPI 3.1.1 specification for the master's REST API.
Dynamically constructs a complete OpenAPI specification document that describes all REST endpoints, request/response schemas, authentication method (API key), and server information. The spec is embedded with the current API version and server base URL (derived from the master's configuration). This enables API documentation, client SDK generation, and interactive testing via Swagger UI. The specification includes detailed path definitions, request bodies, response schemas, and security requirements.
Returns a JSON-formatted OpenAPI 3.1.1 specification as a string.
func (*Master) GetMasterInfo ¶
GetMasterInfo returns comprehensive system and master instance information including CPU, memory, network, disk, and OS metrics. On Linux, it collects detailed system metrics.
Returns a map with master metadata (MID, alias, version, hostname, TLS config) and system metrics. Basic metrics (OS, architecture, CPU count, uptime) are always included. On Linux, calls GetLinuxSysInfo to populate detailed metrics:
- CPU: Percentage utilization (0-100)
- Memory: Total and used in bytes
- Swap: Total and used in bytes
- Network: RX/TX bytes (excluding loopback and container interfaces)
- Disk: Read/write bytes (excluding loop, RAM, and DM devices)
- System uptime in seconds
On non-Linux systems, these metrics default to 0 or -1.
Returns a map[string]any suitable for JSON serialization.
func (*Master) HandleDeleteInstance ¶
func (m *Master) HandleDeleteInstance(w http.ResponseWriter, id string, instance *Instance)
HandleDeleteInstance removes an instance from the master, stops it if running, and notifies subscribers.
Forbidden for the API key instance (403 Forbidden). Marks the instance as deleted, stops it if running (this suppresses further log events), removes it from the registry, and persists the new state. Responds with 204 No Content. An SSE "delete" event is sent to notify subscribers of the removal.
func (*Master) HandleGetInstance ¶
func (m *Master) HandleGetInstance(w http.ResponseWriter, instance *Instance)
HandleGetInstance retrieves and returns the details of a specific instance.
Returns the instance as a JSON object with all current state (status, metrics, config). Status 200 on success.
func (*Master) HandleInfo ¶
func (m *Master) HandleInfo(w http.ResponseWriter, r *http.Request)
HandleInfo handles REST API requests for retrieving and updating master information and alias.
GET: Returns master information from GetMasterInfo() including system stats, version, uptime, TLS configuration, and the master's alias/name. POST: Updates the master's alias from a JSON request {"alias": "new name"}. The alias is stored in the API key instance as well for persistence. Max length is 256 chars. Returns updated master info on success.
Other HTTP methods receive 405 Method Not Allowed.
func (*Master) HandleInstanceDetail ¶
func (m *Master) HandleInstanceDetail(w http.ResponseWriter, r *http.Request)
HandleInstanceDetail dispatches REST API requests for individual instance operations. Supports GET (retrieve), PATCH (update), PUT (replace URL), and DELETE (remove) operations.
Extracts the instance ID from the URL path. Returns 400 if missing, 404 if not found. Routes to the appropriate handler based on HTTP method:
- GET: Returns the instance details
- PATCH: Updates alias, actions, restart policy, and metadata
- PUT: Replaces the entire URL configuration
- DELETE: Removes the instance
Other HTTP methods receive 405 Method Not Allowed.
func (*Master) HandleInstances ¶
func (m *Master) HandleInstances(w http.ResponseWriter, r *http.Request)
HandleInstances handles REST API requests for listing and creating instances. GET returns all instances, POST creates a new instance.
GET: Returns a JSON array of all instances (including the special API key instance). POST: Creates a new instance from a JSON request body containing "url" and optional "alias". The URL is parsed to extract the instance type (scheme). Invalid URLs or types result in 400 Bad Request. A unique ID is generated; conflicts are rejected with 409 Conflict. The instance is started asynchronously. Restart policy defaults to true (auto-restart). The instance registry and state file are updated. An SSE "create" event is sent.
Request body format for POST:
{"url": "client://localhost:8080/target.com:443", "alias": "optional label"}
Other HTTP methods receive 405 Method Not Allowed.
func (*Master) HandleMCP ¶
func (m *Master) HandleMCP(w http.ResponseWriter, r *http.Request)
HandleMCP is the single HTTP entry point for all MCP JSON-RPC 2.0 requests. It validates the envelope and dispatches to the appropriate method handler.
Only accepts POST requests. Decodes the JSON-RPC 2.0 request envelope and validates that the jsonrpc field is "2.0". Routes to handlers based on the method field:
- "initialize": Performs the MCP handshake
- "tools/list": Returns available tools and their input schemas
- "tools/call": Executes a tool and returns the result
Unknown methods receive a -32601 Method Not Found error. Parse errors receive -32700. All responses are JSON-RPC 2.0 compatible with either a result or error field.
func (*Master) HandleMCPInitialize ¶
func (m *Master) HandleMCPInitialize(w http.ResponseWriter, req MCPRequest)
HandleMCPInitialize responds to the MCP "initialize" handshake with server capabilities and version information.
Returns a JSON-RPC response with the MCP protocol version, server name ("Master"), server version (binary version), and advertised capabilities (tools). This allows MCP clients to discover what features the master supports and negotiate compatibility.
func (*Master) HandleMCPToolsCall ¶
func (m *Master) HandleMCPToolsCall(w http.ResponseWriter, req MCPRequest)
HandleMCPToolsCall executes an MCP tool request and returns the tool execution result.
Decodes the tool call parameters (name and arguments) and dispatches to the appropriate handler for one of 18 available tools. Each tool handler validates required parameters, performs the requested operation, and returns a result with a content field (human-readable text) and optional data fields (structured results like instances or config). Errors are returned as JSON-RPC error responses with code -32602 (Invalid params) and a descriptive message.
Tool categories:
- Instance queries: list_instances, get_instance, get_instance_config
- Instance CRUD: create_instance, update_instance, control_instance, delete_instance
- Configuration: set_instance_{basic,security,connection,network,protocol,traffic,advanced}
- Data operations: export_instances, import_instances
- Network testing: tcping_target
- Master operations: get_master_info, update_master_info
func (*Master) HandleMCPToolsList ¶
func (m *Master) HandleMCPToolsList(w http.ResponseWriter, req MCPRequest)
HandleMCPToolsList returns the list of available MCP tools with their input schemas and descriptions.
Defines the schema for all instance and master management tools. Returns 18 tools grouped by function:
- list/get: Instance queries (list_instances, get_instance)
- create: Instance creation (create_instance)
- update: Instance metadata updates (update_instance)
- control: Instance lifecycle (control_instance)
- set_instance_*: Configuration setters for basic, security, connection, network, protocol, traffic, advanced
- config: Retrieve structured configuration (get_instance_config)
- delete: Remove instance (delete_instance)
- export/import: Backup/restore (export_instances, import_instances)
- tcping: Network testing (tcping_target)
- master: Master info operations (get_master_info, update_master_info)
Each tool includes a description and input schema (JSON Schema) with required fields. Common parameters like id, type, tunnel_port, etc. are defined once and reused.
func (*Master) HandleOpenAPISpec ¶
func (m *Master) HandleOpenAPISpec(w http.ResponseWriter, r *http.Request)
HandleOpenAPISpec serves the OpenAPI specification for the master's REST API.
Returns the OpenAPI 3.1.1 specification as JSON (generated by GenerateOpenAPISpec). This is a public endpoint (no API key required) that documents all REST API operations. Clients can use this spec to auto-generate SDK code or for API documentation.
func (*Master) HandlePatchInstance ¶
func (m *Master) HandlePatchInstance(w http.ResponseWriter, r *http.Request, id string, instance *Instance)
HandlePatchInstance partially updates instance configuration including alias, actions, restart policy, and metadata.
For the API key instance (APIKeyID), only the "restart" action (regenerate key) is allowed. For regular instances, supports:
- "alias": Updates the human-readable name (max 256 chars)
- "action": Executes one of {start, stop, restart, reset}
- reset: Clears traffic counters and base values
- "restart": Sets the auto-restart flag (boolean)
- "meta": Updates peer linkage (SID, type, alias) and tags (key-value pairs)
- Peer fields and tag keys/values are validated (max 256 chars each)
- Detects duplicate tag keys and rejects with 400
Changes trigger state persistence and SSE "update" events. Request body is JSON with optional fields; invalid JSON is silently ignored.
func (*Master) HandlePutInstance ¶
func (m *Master) HandlePutInstance(w http.ResponseWriter, r *http.Request, id string, instance *Instance)
HandlePutInstance replaces the instance URL configuration and restarts the instance with new settings.
Forbidden for the API key instance (403 Forbidden). Expects JSON with a "url" field. The URL must have a valid scheme (client or server); otherwise, returns 400. If the enhanced URL matches the existing URL, returns 409 Conflict. Stops the instance if running, replaces the URL, regenerates the config, and restarts it. The new configuration is persisted and an SSE "update" event is sent.
Request body format:
{"url": "server://0.0.0.0:8080/target.com:443"}
func (*Master) HandleSSE ¶
func (m *Master) HandleSSE(w http.ResponseWriter, r *http.Request)
HandleSSE handles Server-Sent Events connections for real-time instance updates. It registers the client as a subscriber and sends initial state followed by continuous updates.
Sets up SSE headers (text/event-stream, no-cache) and generates a unique subscriber ID. Creates a buffered event channel that is registered in the Subscribers map. Sends a retry hint (SSERetryTime ms) and all current instance states as "initial" events. Then enters a loop listening for new events from the channel or context cancellation. When the client disconnects or the context is cancelled, the channel is cleaned up. All events are marshalled to JSON and formatted as SSE messages (event: instance).
Only accepts GET requests; other methods receive a 405 Method Not Allowed response. On connection loss, the goroutine that monitors the context notifies the channel close.
func (*Master) HandleSwaggerUI ¶
func (m *Master) HandleSwaggerUI(w http.ResponseWriter, r *http.Request)
HandleSwaggerUI serves the Swagger UI interface for exploring the master's REST API.
Returns an HTML page embedding the Swagger UI (from CDN) with the OpenAPI spec injected. This is a public endpoint that allows users to interactively test API endpoints through a web browser. The Swagger UI allows sending test requests and viewing responses.
func (*Master) HandleTCPing ¶
func (m *Master) HandleTCPing(w http.ResponseWriter, r *http.Request)
HandleTCPing handles REST API requests for TCP connectivity testing to a target address.
Only accepts GET requests; other methods return 405. Requires a "target" query parameter (host:port format); returns 400 if missing. Delegates to PerformTCPing for the actual test and returns the result as JSON (includes success status and latency in milliseconds).
func (*Master) LoadState ¶
func (m *Master) LoadState()
LoadState loads the master state from disk, initializes instances, and optionally auto-starts them. It cleans up any temporary files and handles state file deserialization.
First cleans up any leftover temporary files (*.tmp) from previous failed saves. If the state file does not exist, returns silently (no instances to restore). Otherwise, opens the state file and decodes instances using GOB format. For each loaded instance, the "stopped" channel is re-initialized (since channels cannot be serialized). Non-API-key instances are set to "stopped" status. Missing configuration URLs are regenerated based on current master settings. If an instance has the Restart flag set, it is automatically started with a brief delay between starts. A summary log message reports how many instances were loaded.
func (*Master) MasterShutdown ¶
MasterShutdown tears down all master resources: closes SSE connections, stops all child-process instances, closes the notify channel, persists state, and shuts down the HTTP server — all bounded by ctx.
Performs an ordered shutdown: first notifies all SSE subscribers, then gracefully stops each running instance in parallel using StopInstance. The notify channel is closed to stop the event dispatcher. The instance registry is persisted to disk (GOB format) for crash recovery. Finally, the HTTP server is shut down with the given context deadline. Any errors during persistence or server shutdown are logged but do not prevent continuation of the shutdown sequence.
Parameters:
- ctx: Context with timeout controlling the maximum shutdown duration
Returns an error from the underlying CommonShutdown if the shutdown fails.
func (*Master) MonitorInstance ¶
MonitorInstance continuously monitors an instance process and updates its status. It listens for process exit, context cancellation, and periodic checkpoints to detect unresponsive states.
Waits for the process to exit via cmd.Wait(). If the process exits normally or with error, the instance status is updated (to "stopped" on success or "error" on failure). If the instance.stopped channel is closed (by StopInstance), this function returns. Periodically checks if a CHECK_POINT event has been received; if not within 3 times the report interval, marks the instance as "error" (indicating unresponsiveness). Status changes are persisted via SendSSEEvent to notify subscribers.
Parameters:
- instance: The instance to monitor
- cmd: The exec.Cmd for the child process
func (*Master) PerformPeriodicBackup ¶
func (m *Master) PerformPeriodicBackup()
PerformPeriodicBackup creates a backup of the current master state to disk.
Saves a copy of the instance registry to a backup file (StatePath + ".backup") using the same GOB format as the main state file. This provides a recovery point in case the primary state file becomes corrupted. Errors are logged but do not prevent other periodic tasks from continuing. The backup runs at regular intervals (common.ReloadInterval) to ensure recent data can be recovered.
func (*Master) PerformPeriodicCleanup ¶
func (m *Master) PerformPeriodicCleanup()
PerformPeriodicCleanup performs housekeeping tasks on managed instances, cleaning up redundant entries.
Identifies duplicate instances (same ID but different entries in the registry, which can occur due to race conditions or bugs). For instances with duplicates, keeps the one in "running" status and removes the others. Stopped duplicates are shut down gracefully before removal. This ensures the instance registry remains consistent and prevents stale entries from accumulating. Runs periodically to maintain registry health.
func (*Master) PerformPeriodicRestart ¶
func (m *Master) PerformPeriodicRestart()
PerformPeriodicRestart automatically restarts instances that have encountered errors during operation.
Scans the instance registry for instances in "error" status (not deleted). For each errored instance, stops it gracefully, waits BaseDuration (100ms), and restarts it. This self-healing mechanism helps instances recover from transient failures without manual intervention. Runs periodically as part of the maintenance loop.
func (*Master) PerformTCPing ¶
func (m *Master) PerformTCPing(target string) *TCPingResult
PerformTCPing performs a TCP connection test to a target address and returns connectivity and latency information.
Acquires a semaphore (max PingSemLimit concurrent pings) with a 1-second timeout. Returns "too many requests" error if the semaphore is full. Measures the time to establish a TCP connection to the target with a timeout of ReportInterval. Records whether the connection succeeded, the latency in milliseconds, and any error message. Useful for verifying network connectivity to remote endpoints.
Parameters:
- target: Target address in "host:port" format
Returns a TCPingResult containing success status, latency (ms), and optional error.
func (*Master) ProcessInstanceAction ¶
ProcessInstanceAction executes the specified action (start/stop/restart) on an instance. It validates the instance state and calls the corresponding method to perform the action.
Routes actions to the appropriate handler methods in a non-blocking manner (using goroutines for stop/start/restart operations). Validates that the instance can perform the action (e.g., only starts if stopped, only stops if not stopped). The restart action is asynchronous: stops the instance, waits BaseDuration, then starts it again.
Parameters:
- instance: The instance to control
- action: One of "start", "stop", or "restart"
func (*Master) ReGenerateAPIKey ¶
ReGenerateAPIKey generates a new API key and notifies all SSE clients.
Generates a new 32-character hexadecimal API key and updates the API key instance. Prints the new key to stdout for visibility. Persists the new key to the state file and gracefully shuts down all SSE connections, forcing clients to reconnect with the new key. This effectively invalidates all existing API keys, requiring clients to restart and authenticate with the new key.
Parameters:
- instance: The API key instance (usually the special APIKeyID entry)
func (*Master) Run ¶
func (m *Master) Run()
Run starts the master: loads or generates the API key, registers HTTP routes (both API-key-protected and public), starts the HTTP(S) server and periodic background tasks, and blocks until SIGINT/SIGTERM, then gracefully shuts down.
Creates or loads the API key and Master ID (MID) from the instance registry. If no API key exists, one is generated and persisted. Protected endpoints require the X-API-Key header; public endpoints (OpenAPI spec and docs) are accessible without authentication. All HTTP responses include CORS headers. The HTTP server is started in a separate goroutine (using TLS if configured). Background tasks run concurrently for periodic maintenance. The function blocks until receiving SIGINT or SIGTERM, then initiates graceful shutdown with a timeout.
func (*Master) SaveState ¶
SaveState saves the current master state to disk using GOB serialization.
Delegates to SaveStateToPath using the master's configured state file path. This is a convenience wrapper that centralizes state file management.
func (*Master) SaveStateToPath ¶
SaveStateToPath saves the master state to a specific file path with atomic write semantics. It uses a temporary file to ensure data integrity during the save operation.
Extracts all instances from the sync.Map and encodes them using GOB format. If the instance map is empty, removes the state file (if it exists). Otherwise, creates the directory structure if needed, writes to a temporary file first, then atomically renames it to the target path. This prevents corruption if the process crashes during write. All errors (mkdir, temp creation, encoding, file operations) are wrapped with context. The StateMu mutex ensures exclusive access during the save operation.
Parameters:
- filePath: Full path where the state file should be saved
Returns an error if any step of the save process fails.
func (*Master) SendSSEEvent ¶
SendSSEEvent sends an event to the notification channel for broadcasting to all SSE subscribers. It includes the event type, instance state, and optional log messages.
Constructs an InstanceEvent with the given type and timestamp. If a log message is provided, it is included in the event (only the first log message is used). The event is sent to the NotifyChannel in a non-blocking manner (drops events if the channel buffer is full). This allows the event dispatcher to fan-out the event to all connected SSE subscribers. Common event types are "create", "update", "delete", "log", "initial", and "shutdown".
Parameters:
- eventType: Type of event (e.g., "create", "update", "delete", "log")
- instance: The instance associated with the event
- logs: Optional log message(s); only the first is used
func (*Master) SetInstanceURL ¶
SetInstanceURL updates an instance's URL configuration with the provided parameters, stops the running instance if necessary, and restarts it with the new configuration.
Parses the instance's current URL and applies updates to the URL components or query parameters. Supports updating "type" (scheme), "pool" (query type), "password" (auth), "tunnel_address", "tunnel_port", "target_address", "target_port", "targets" (path), and any query parameters. Query parameter values are replaced or deleted (if empty). Validates that the type is "client" or "server". Returns an error if no changes are detected. Stops the instance if running, replaces the URL, regenerates the config, and restarts. The new state is persisted asynchronously and an SSE update event is sent.
Parameters:
- instance: The instance to update
- updates: Map of field names to new values
Returns an error if the URL is invalid, type is invalid, or no changes detected.
func (*Master) ShutdownSSEConnections ¶
func (m *Master) ShutdownSSEConnections()
ShutdownSSEConnections gracefully closes all active SSE subscriber connections and notifies them of the master shutdown event.
Iterates over all registered SSE subscribers and sends a "shutdown" event to each in parallel (using WaitGroup). Each subscriber receives a final event before its channel is closed. Attempts to send are non-blocking; if the channel buffer is full, the shutdown notification is silently dropped. This ensures that even unresponsive clients don't block the master shutdown process. The function waits for all notifications to complete before returning.
func (*Master) StartEventDispatcher ¶
func (m *Master) StartEventDispatcher()
StartEventDispatcher starts the event dispatcher goroutine that broadcasts instance events from the notification channel to all active SSE subscribers.
Runs indefinitely (until NotifyChannel is closed), receiving events from the notification channel and fanning them out to all subscribers. Each event is sent to every subscriber's event channel using a non-blocking select (drops events if a subscriber's channel is full, indicating a slow client). This pattern decouples event senders from receivers and ensures fast event producers are not blocked by slow subscribers. The dispatcher should be started as a goroutine during master initialization.
func (*Master) StartInstance ¶
StartInstance starts a nodepass instance as a subprocess, capturing its output and managing its lifecycle. It validates the instance state and initializes metric tracking.
Checks that the instance is in "stopped" status before starting. Saves the current traffic counters as base values for delta calculations. Forks a child process running the nodepass binary with the instance URL as the argument. The child's stdout and stderr are attached to an InstanceLogWriter that parses metrics and forwards logs. A context.WithCancel is used to allow graceful termination. On startup success, the instance status is set to "running" and MonitorInstance is started in a goroutine. On failure, the status is set to "error". The instance is stored back in the registry and an SSE update event is sent to all subscribers.
Parameters:
- instance: The instance to start (must be in stopped status)
func (*Master) StartPeriodicTasks ¶
func (m *Master) StartPeriodicTasks()
StartPeriodicTasks starts the periodic maintenance tasks loop for backup, cleanup, and restart operations.
Runs indefinitely at an interval defined by common.ReloadInterval. On each tick, executes:
- PerformPeriodicBackup: Saves a backup copy of the state file
- PerformPeriodicCleanup: Removes duplicate instances, keeping the one in "running" status
- PerformPeriodicRestart: Restarts instances that are in "error" status
Returns when the PeriodicDone channel is closed (signaling master shutdown). This function should be started as a goroutine during master initialization.
func (*Master) StopInstance ¶
StopInstance gracefully stops an instance process with force kill timeout. It checks the instance status, sends termination signals, waits for process exit, and updates the instance status accordingly.
If already stopped, returns immediately. Closes the instance.stopped channel to signal MonitorInstance to return. Sends SIGTERM (or SIGINT on Windows) to the process and cancels the context to initiate graceful shutdown. Waits for the process to exit within GracefulTimeout (5s); if timeout expires, sends SIGKILL. Resets all metric counters (ping, pool, TCP/UDP connection counts) to 0. A new stopped channel is allocated for potential future restarts. The instance state is persisted and an SSE update event is sent to subscribers.
Parameters:
- instance: The instance to stop
func (*Master) WriteMCPError ¶
WriteMCPError writes a JSON-RPC 2.0 error response to w using the given error code, message, and optional extra data.
Constructs an error response envelope with JSONRPC="2.0", the request ID, and an error object containing code, message, and optional data. Standard JSON-RPC error codes:
- -32700: Parse error
- -32600: Invalid Request
- -32601: Method not found
- -32602: Invalid params
- -32603: Internal error
Sets Content-Type to application/json and HTTP 200 status (per JSON-RPC spec). Encodes the response as JSON.
Parameters:
- w: The HTTP response writer
- id: The request ID (can be nil for parse errors)
- code: JSON-RPC error code
- message: Human-readable error message
- data: Optional additional error context (can be nil)
func (*Master) WriteMCPResponse ¶
func (m *Master) WriteMCPResponse(w http.ResponseWriter, id any, result any)
WriteMCPResponse writes a JSON-RPC 2.0 success response to w.
Constructs a response envelope with JSONRPC="2.0", the request ID, and the result. Sets Content-Type to application/json and HTTP 200 status. Encodes the response as JSON.
Parameters:
- w: The HTTP response writer
- id: The request ID (can be string, number, or null)
- result: The result data to return
type Meta ¶
Meta carries optional peer-linkage and free-form tag metadata for an Instance.
Peer allows associating an instance with its remote counterpart (the server paired with a client instance, or vice versa) for coordination and management. The peer reference is bidirectional but manually managed (updating one instance doesn't auto-update the other). Tags are arbitrary key-value pairs for user-defined metadata (max 256 chars each). Both fields are serialized to JSON and persisted in the state file.
type Peer ¶
Peer identifies the paired remote endpoint (server for a client instance, or client for a server instance) registered in the same Master.
SID is the Service/Instance ID of the peer instance. Type identifies the peer's type ("client" or "server"), and Alias is a human-readable name for the peer (replicated from the peer instance for convenience). These fields are optional and user-managed.
type SystemInfo ¶
type SystemInfo struct {
CPU int `json:"cpu"`
MemTotal uint64 `json:"mem_total"`
MemUsed uint64 `json:"mem_used"`
SwapTotal uint64 `json:"swap_total"`
SwapUsed uint64 `json:"swap_used"`
NetRX uint64 `json:"netrx"`
NetTX uint64 `json:"nettx"`
DiskR uint64 `json:"diskr"`
DiskW uint64 `json:"diskw"`
SysUp uint64 `json:"sysup"`
}
SystemInfo holds system resource metrics including CPU, memory, disk, and network statistics.
Collected by GetLinuxSysInfo from /proc filesystem on Linux systems. CPU is a percentage (0-100) calculated from /proc/stat over a 100ms sample period. MemTotal and MemUsed are in bytes from /proc/meminfo. SwapTotal/SwapUsed are swap statistics. NetRX/NetTX are bytes transmitted/received on physical network interfaces (excluding virtual interfaces). DiskR/DiskW are bytes read/written to physical disks (excluding virtual block devices). SysUp is system uptime in seconds from /proc/uptime. Fields are populated only on Linux; on other platforms, they default to 0 or -1.
func GetLinuxSysInfo ¶
func GetLinuxSysInfo() SystemInfo
GetLinuxSysInfo collects system information from Linux /proc filesystem including CPU usage, memory, swap, network, disk I/O, and system uptime metrics.
Reads from /proc files to gather system metrics:
- /proc/stat: CPU usage (sampled twice 100ms apart for delta calculation)
- /proc/meminfo: Memory total, available, swap total/free
- /proc/net/dev: Network interface statistics (RX/TX bytes), excludes loopback, veth, docker, podman, br-, and virbr interfaces
- /proc/diskstats: Disk read/write sectors; excludes loop, ram, dm-, md devices
- /proc/uptime: System uptime in seconds
Returns a SystemInfo struct with all collected metrics. If any /proc file cannot be read or parsed, those metrics remain at their default values. The function only executes on Linux; on other platforms, it returns a zero-valued SystemInfo struct.
Returns a SystemInfo structure populated with all available system metrics.
type TCPingResult ¶
type TCPingResult struct {
Target string `json:"target"`
Connected bool `json:"connected"`
Latency int64 `json:"latency"`
Error *string `json:"error"`
}
TCPingResult represents the result of a TCP connectivity test including latency and error information.
Target is the address that was tested (host:port). Connected indicates whether the TCP connection succeeded. Latency is the time in milliseconds to establish the connection (0 if connection failed). Error is a pointer to an error message (nil if successful, contains "too many requests" if semaphore full, or the connection error otherwise). Used by the TCPing REST endpoint and MCP tool for network diagnostics.