terminal

package
v0.0.0-...-d25dbbd Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package terminal provides the core abstractions for interactive terminal sessions.

A terminal session lets a human (or automation) interact with any resource that exposes a CLI: servers (SSH), containers (Docker exec), databases (mysql / psql / redis-cli), or cloud CLIs (aws / gcloud / az).

Supported connectors (current):

  • SSHConnector — SSH PTY for registered managed servers
  • SFTPClient — REST file operations over SSH transport

Index

Constants

View Source
const (
	SessionStateAttached = "attached"
	SessionStateDetached = "detached"
)

Variables

This section is empty.

Functions

func AttachResumable

func AttachResumable(
	id string,
	userID string,
	resourceType string,
	resourceID string,
	sessionType string,
	conn *websocket.Conn,
) error

AttachResumable binds an existing resumable session to a websocket connection.

func AuthMethodFromConfig

func AuthMethodFromConfig(cfg ConnectorConfig) (cryptossh.AuthMethod, error)

AuthMethodFromConfig builds the SSH auth method from a ConnectorConfig. Exported so operational tools (e.g. ExecuteSSHCommand in servers package) can reuse it.

func Close

func Close(id string)

Close removes the session from the registry and closes the underlying terminal session.

func CloseOwned

func CloseOwned(id string, userID string) error

CloseOwned removes and closes a session only when it belongs to the given user.

func Detach

func Detach(id string)

Detach keeps the session alive but removes any currently attached websocket.

func DialSSH

func DialSSH(ctx context.Context, cfg ConnectorConfig) (*cryptossh.Client, error)

DialSSH establishes an SSH client connection for the given config. The caller is responsible for calling client.Close() when done. A 15-second connection timeout is applied.

func ExecuteSSHCommand

func ExecuteSSHCommand(ctx context.Context, cfg ConnectorConfig, command string, timeout time.Duration) (string, error)

ExecuteSSHCommand runs a one-shot command on a remote server via SSH and returns the combined stdout+stderr output. If timeout <= 0, a 20-second default is applied.

func HostKeyCallback

func HostKeyCallback() (cryptossh.HostKeyCallback, error)

HostKeyCallback resolves the SSH host-key verification policy shared by interactive terminal sessions and one-shot SSH command execution.

func Register

func Register(id string, sess Session)

Register adds a session to the registry. The session is automatically closed after sessionIdleTimeout of inactivity.

func RegisterDetailed

func RegisterDetailed(
	id string,
	sess Session,
	userID string,
	resourceType string,
	resourceID string,
	sessionType string,
)

RegisterDetailed adds a session plus metadata to the registry. The session is automatically closed after sessionIdleTimeout of inactivity.

func RegisterResumableDetailed

func RegisterResumableDetailed(
	id string,
	sess Session,
	userID string,
	resourceType string,
	resourceID string,
	sessionType string,
)

RegisterResumableDetailed adds a session plus metadata and starts a background read loop so the session can survive temporary websocket detaches.

func RunSSHSession

func RunSSHSession(ctx context.Context, client *cryptossh.Client, command string, timeout time.Duration) (string, error)

RunSSHSession runs a single command on an already-established SSH client, reusing the connection without a new dial. Each call opens + closes one lightweight session (channel). If timeout <= 0, a 20-second default is used.

func RunSSHSessionStreaming

func RunSSHSessionStreaming(ctx context.Context, client *cryptossh.Client, command string, timeout time.Duration, onOutput func(string)) (string, error)

RunSSHSessionStreaming runs a command and streams stdout/stderr lines to onOutput while also returning the combined output after the command exits.

func ShellQuote

func ShellQuote(value string) string

ShellQuote wraps a value in single quotes, escaping any embedded single quotes.

func StartIdleMonitor

func StartIdleMonitor()

StartIdleMonitor starts the background idle-session janitor. Safe to call multiple times.

func StopIdleMonitor

func StopIdleMonitor()

StopIdleMonitor stops the background idle-session janitor and closes all currently tracked sessions. Safe to call multiple times.

func Touch

func Touch(id string)

Touch updates the last-activity timestamp, resetting the idle timer. Should be called for every message received on the WebSocket.

func Unregister

func Unregister(id string)

Unregister removes the session from the registry (called on WebSocket close). It does NOT close the Session itself; the caller is responsible for that.

func UpdateWorkspace

func UpdateWorkspace(id string, userID string, snapshot TerminalWorkspaceSnapshot) error

UpdateWorkspace updates the stored workspace snapshot for a session owned by the given user.

func WrapCommandWithEnv

func WrapCommandWithEnv(command string, env map[string]string) string

Types

type ConnectError

type ConnectError struct {
	Category ConnectErrorCategory
	Message  string
	Cause    error
}

ConnectError is returned by Connector.Connect: it carries a machine-readable category alongside the human-readable message so callers can render actionable UI feedback.

func NewConnectError

func NewConnectError(cat ConnectErrorCategory, msg string, cause error) *ConnectError

NewConnectError creates a ConnectError with the given category and message.

func (*ConnectError) Error

func (e *ConnectError) Error() string

func (*ConnectError) Unwrap

func (e *ConnectError) Unwrap() error

type ConnectErrorCategory

type ConnectErrorCategory string

ConnectErrorCategory classifies the reason a connection attempt failed. Frontend and API consumers use this to display specific, actionable messages.

const (
	// ErrCatAuthFailed — credentials were rejected by the remote server.
	ErrCatAuthFailed ConnectErrorCategory = "auth_failed"
	// ErrCatNetworkUnreachable — TCP dial timed out or host is unreachable.
	ErrCatNetworkUnreachable ConnectErrorCategory = "network_unreachable"
	// ErrCatConnectionRefused — remote port actively refused the connection.
	ErrCatConnectionRefused ConnectErrorCategory = "connection_refused"
	// ErrCatCredentialInvalid — local credential config error (bad key format, unsupported auth type).
	ErrCatCredentialInvalid ConnectErrorCategory = "credential_invalid" // #nosec G101 -- symbolic error category, not a credential
	// ErrCatSessionFailed — SSH handshake succeeded but PTY/shell setup failed.
	ErrCatSessionFailed ConnectErrorCategory = "session_failed"
	// ErrCatServerDisconnected — server closed the connection unexpectedly.
	ErrCatServerDisconnected ConnectErrorCategory = "server_disconnected"
)

type Connector

type Connector interface {
	Connect(ctx context.Context, cfg ConnectorConfig) (Session, error)
}

Connector creates a Session for a given transport configuration. Implementations must be safe for concurrent use.

ConnectorConfig is transport-level input. Application services are expected to map domain-specific access models into it before calling Connect.

type ConnectorConfig

type ConnectorConfig struct {
	// Host is the target hostname or IP address.
	Host string
	// Port is the target TCP port (e.g. 22 for SSH).
	Port int
	// User is the login username.
	User string
	// AuthType identifies the credential kind: AuthMethodPassword or AuthMethodPrivateKey.
	AuthType CredAuthType
	// Secret is the decrypted credential value (password or PEM private key).
	Secret string
	// Shell overrides the login shell (empty = server default).
	Shell string
}

ConnectorConfig carries the transport parameters required to open a terminal connection. For SSH-backed connectors (SSHConnector, SFTPClient) this maps to SSH session inputs.

type CredAuthType

type CredAuthType string

CredAuthType identifies the authentication method used to connect to a server.

const (
	// AuthMethodPassword authenticates using a username/password pair.
	AuthMethodPassword CredAuthType = "password"
	// AuthMethodPrivateKey authenticates using an SSH private key (PEM).
	AuthMethodPrivateKey CredAuthType = "private_key"
)

type DirEntry

type DirEntry struct {
	Name       string    `json:"name"`
	Type       string    `json:"type"` // "file" | "dir" | "symlink"
	Size       int64     `json:"size"`
	Mode       string    `json:"mode"`
	ModifiedAt time.Time `json:"modified_at"`
}

DirEntry is a single file or directory entry returned by ListDir.

type FileAttrs

type FileAttrs struct {
	Path       string    `json:"path"`
	Type       string    `json:"type"`
	Mode       string    `json:"mode"`
	Owner      int       `json:"owner"`
	Group      int       `json:"group"`
	OwnerName  string    `json:"owner_name"`
	GroupName  string    `json:"group_name"`
	Size       int64     `json:"size"`
	AccessedAt time.Time `json:"accessed_at"`
	ModifiedAt time.Time `json:"modified_at"`
	CreatedAt  time.Time `json:"created_at"`
}

FileAttrs is full file/dir metadata for property panel editing.

type SFTPClient

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

SFTPClient wraps an SFTP session opened over a dedicated SSH connection. It is short-lived: open it, perform one or more operations, then Close.

func NewSFTPClient

func NewSFTPClient(ctx context.Context, cfg ConnectorConfig) (*SFTPClient, error)

NewSFTPClient dials SSH and opens an SFTP subsystem session. The caller must call Close when done.

func (*SFTPClient) Chmod

func (c *SFTPClient) Chmod(filePath string, mode os.FileMode) error

Chmod updates remote file mode.

func (*SFTPClient) ChmodRecursive

func (c *SFTPClient) ChmodRecursive(filePath string, mode os.FileMode) error

ChmodRecursive updates mode for the path and all children when path is a directory.

func (*SFTPClient) Chown

func (c *SFTPClient) Chown(filePath string, uid, gid int) error

Chown updates remote uid/gid.

func (*SFTPClient) ChownByName

func (c *SFTPClient) ChownByName(filePath, ownerName, groupName string) error

ChownByName updates remote owner/group using principal names (or numeric string).

func (*SFTPClient) Close

func (c *SFTPClient) Close() error

Close releases SFTP and SSH connections.

func (*SFTPClient) Copy

func (c *SFTPClient) Copy(source, target string, onProgress func(copied, total int64)) (int64, error)

Copy recursively copies file/dir from source to target. onProgress is called with copied and total bytes for files.

func (*SFTPClient) Delete

func (c *SFTPClient) Delete(filePath string) error

Delete removes a file or an empty directory.

func (*SFTPClient) Download

func (c *SFTPClient) Download(remotePath string, dst io.Writer) error

Download streams the remote file to dst (e.g. http.ResponseWriter).

func (*SFTPClient) ListDir

func (c *SFTPClient) ListDir(dirPath string) ([]DirEntry, error)

ListDir returns all entries (including dot-files) in the given remote path.

func (*SFTPClient) Mkdir

func (c *SFTPClient) Mkdir(dirPath string) error

Mkdir creates the directory at path (does not create intermediate directories).

func (*SFTPClient) MkdirAll

func (c *SFTPClient) MkdirAll(target string) error

MkdirAll creates a directory tree on the remote server.

func (*SFTPClient) ReadFile

func (c *SFTPClient) ReadFile(filePath string, maxBytes int64) (string, error)

ReadFile reads up to maxBytes of a remote file and returns it as a string.

func (*SFTPClient) Rename

func (c *SFTPClient) Rename(from, to string) error

Rename moves/renames from→to.

func (*SFTPClient) SearchFiles

func (c *SFTPClient) SearchFiles(basePath, query string) ([]SearchResult, error)

SearchFiles recursively walks basePath and returns entries whose names contain query (case-insensitive). Returns at most searchMaxResults results.

func (*SFTPClient) Stat

func (c *SFTPClient) Stat(filePath string) (FileAttrs, error)

Stat returns full metadata for a file or directory.

func (c *SFTPClient) Symlink(target, linkPath string) error

Symlink creates a symbolic link from linkPath -> target.

func (*SFTPClient) Upload

func (c *SFTPClient) Upload(remotePath string, src io.Reader) error

Upload writes src to remotePath. The total read from src must not exceed sftpMaxUploadBytes (50 MB); excess bytes cause an error without data corruption because the remote file is only committed on success.

func (*SFTPClient) WriteFile

func (c *SFTPClient) WriteFile(filePath string, content string) error

WriteFile writes content to a remote file, creating or truncating it.

type SSHConnector

type SSHConnector struct{}

SSHConnector establishes SSH PTY sessions to remote servers. Credentials are never stored; they are consumed once during Connect and held only for the duration of the session in-memory.

func (*SSHConnector) Connect

func (c *SSHConnector) Connect(ctx context.Context, cfg ConnectorConfig) (Session, error)

Connect opens an SSH connection and returns a Session backed by a remote PTY.

type SearchResult

type SearchResult struct {
	Path       string    `json:"path"`
	Name       string    `json:"name"`
	Type       string    `json:"type"`
	Size       int64     `json:"size"`
	Mode       string    `json:"mode"`
	ModifiedAt time.Time `json:"modified_at"`
}

SearchResult is a single match returned by SearchFiles.

type Session

type Session interface {
	// Write sends bytes to the remote stdin (keyboard input).
	Write(p []byte) (n int, err error)
	// Read receives bytes from the remote stdout/stderr (terminal output).
	Read(p []byte) (n int, err error)
	// Resize changes the remote PTY dimensions.
	Resize(rows, cols uint16) error
	// Close terminates the session and frees all resources.
	Close() error
}

Session is the common interface for streaming terminal connectors. It bridges a remote PTY with a WebSocket: callers Write stdin bytes and Read stdout/stderr bytes. Control messages (resize, close) are handled out-of-band by the WebSocket route handler.

SFTPClient does NOT implement Session — it is a stateless REST service.

func FindResumableForAttach

func FindResumableForAttach(
	id string,
	userID string,
	resourceType string,
	resourceID string,
	sessionType string,
) (Session, error)

FindResumableForAttach validates that an existing resumable session can be attached.

type SessionSummary

type SessionSummary struct {
	ID           string                    `json:"id"`
	UserID       string                    `json:"user_id"`
	ResourceType string                    `json:"resource_type"`
	ResourceID   string                    `json:"resource_id"`
	SessionType  string                    `json:"session_type"`
	State        string                    `json:"state"`
	StartedAt    time.Time                 `json:"started_at"`
	LastActiveAt time.Time                 `json:"last_active_at"`
	Workspace    TerminalWorkspaceSnapshot `json:"workspace"`
}

func ListSummariesByUser

func ListSummariesByUser(userID string) []SessionSummary

ListSummariesByUser returns active session summaries for the given user, ordered by most recent activity first.

type TerminalWorkspaceSnapshot

type TerminalWorkspaceSnapshot struct {
	ActiveServerID string   `json:"active_server_id,omitempty"`
	SidePanel      string   `json:"side_panel,omitempty"`
	FilePath       string   `json:"file_path,omitempty"`
	LockedRoot     string   `json:"locked_root,omitempty"`
	SplitRatio     *float64 `json:"split_ratio,omitempty"`
}

Jump to

Keyboard shortcuts

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