netfox

package
v0.4.0-beta Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: BSD-3-Clause Imports: 45 Imported by: 1

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNoDialer = errors.New("fishplus: this session cannot be reconnected")

ErrNoDialer is what a reconnect answers when nobody told the connection how to rebuild itself.

View Source
var FishPoolIdleTimeout = 15 * time.Minute

FishPoolIdleTimeout is how long a session is kept alive with nothing attached to it before it is finally closed. Reopening the same site within this window hands back the still-live connection instead of dialling and shaking hands again, so stepping out of a panel and back into it — the "other panel" swap, a quick trip to a local directory and back — costs nothing over a remote link that a fresh connection would have made the user wait for.

View Source
var FishPreferRemoteF4 atomic.Bool

FishPreferRemoteF4 makes a FISH+ connection over SSH try f4 itself as the server first (nativeRemoteCommand, fishplus.Server), falling back to the shell helper on a host without f4 (unxed/f4#1680). Off by default: on a host without f4 it costs one extra connection attempt before the fallback.

Functions

func CloseIdlePool

func CloseIdlePool()

CloseIdlePool closes every FISH+ session the pool is holding onto. f4 calls it once, during application shutdown.

func DialSSH

func DialSSH(host, port, user, pass, keyPath string, timeout int, px netproxy.Settings) (*ssh.Client, error)

DialSSH opens an SSH connection the way every SSH based NetFox backend needs it. When keyPath is set, that key is the only key file offered, and it goes ahead of whatever the ssh-agent carries — this avoids servers that cut the handshake short after a handful of failed public-key attempts (MaxAuthTries) before ever reaching the right key. When keyPath is empty, it is the agent, then the usual private keys from ~/.ssh, then the password. It is shared by the SFTP and the FISH+ backends so that a site behaves identically whichever of them opens it.

func GetProtocols

func GetProtocols() []string

func RegisterProtocol

func RegisterProtocol(h ProtocolHandler)

Types

type FTPVFS

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

func NewFTPVFS

func NewFTPVFS(parent vfs.VFS, host, port, user, pass string, timeout int, options map[string]string, cp string, px netproxy.Settings) (*FTPVFS, error)

func (*FTPVFS) Abs

func (v *FTPVFS) Abs(p string) (string, error)

func (*FTPVFS) Base

func (v *FTPVFS) Base(p string) string

func (*FTPVFS) BookmarkPath

func (v *FTPVFS) BookmarkPath(string) (string, bool)

BookmarkPath implements vfs.BookmarkPathProvider: the folder on the server under the address the session was opened from (bookmark_path.go).

func (*FTPVFS) Clone

func (v *FTPVFS) Clone() vfs.VFS

func (*FTPVFS) Close

func (v *FTPVFS) Close() error

func (*FTPVFS) Create

func (v *FTPVFS) Create(ctx context.Context, p string) (io.WriteCloser, error)

func (*FTPVFS) Dir

func (v *FTPVFS) Dir(p string) string

func (*FTPVFS) GetCapabilities

func (v *FTPVFS) GetCapabilities() vfs.VFSCapabilities

func (*FTPVFS) GetPath

func (v *FTPVFS) GetPath() string

func (*FTPVFS) GetTitle

func (v *FTPVFS) GetTitle() string

func (*FTPVFS) HistoryEntry

func (v *FTPVFS) HistoryEntry() (display, ref string, ok bool)

HistoryEntry and NavigateHistoryEntry implement vfs.HistoryPathProvider (f4#262): an FTP session owns its own folder-history entries instead of its raw remote path (e.g. /root/foo) being recorded as if it were local.

func (*FTPVFS) IsAbs

func (v *FTPVFS) IsAbs(p string) bool

func (*FTPVFS) IsAtRoot

func (v *FTPVFS) IsAtRoot() bool

func (*FTPVFS) Join

func (v *FTPVFS) Join(e ...string) string

func (*FTPVFS) MkDir

func (v *FTPVFS) MkDir(ctx context.Context, p string) error

func (*FTPVFS) NavigateHistoryEntry

func (v *FTPVFS) NavigateHistoryEntry(ref string) bool

func (*FTPVFS) Open

func (v *FTPVFS) Open(ctx context.Context, p string) (vfs.ReadAtCloser, error)

func (*FTPVFS) ParentVFS

func (v *FTPVFS) ParentVFS() vfs.VFS

func (*FTPVFS) ReadDir

func (v *FTPVFS) ReadDir(ctx context.Context, p string, onChunk func([]vfs.VFSItem)) error

func (*FTPVFS) Remove

func (v *FTPVFS) Remove(ctx context.Context, p string) error

func (*FTPVFS) Rename

func (v *FTPVFS) Rename(ctx context.Context, o, n string) error

func (*FTPVFS) Search

func (v *FTPVFS) Search(ctx context.Context, p, pat string) (chan int64, error)

func (*FTPVFS) SessionKey

func (v *FTPVFS) SessionKey() any

func (*FTPVFS) SetAttributes

func (v *FTPVFS) SetAttributes(ctx context.Context, path string, item vfs.VFSItem) error

func (*FTPVFS) SetPath

func (v *FTPVFS) SetPath(p string) error

func (*FTPVFS) Stat

func (v *FTPVFS) Stat(ctx context.Context, p string) (vfs.VFSItem, error)

type FishDialer

type FishDialer func(ctx context.Context) (io.Writer, io.Reader, io.Closer, error)

fishConn keeps one FISH+ session alive for as long as any of the VFS instances built on it is still in use. f4 clones a panel's file system in several places — the "other panel" menu item and the frame snapshot taken for a background task — and every panel closes its own file system when it leaves it. Handing back the same instance, the way the SFTP backend does, would therefore let one panel tear the session down under another, and would make both panels share a single current directory.

Requests from the clones interleave freely: the session serializes them with its own mutex, so each request stays atomic. They do not run in parallel, which for a shell that answers one command at a time is what a second connection could not fix anyway. FishDialer opens a new transport for a session that has to be rebuilt. It returns the two halves of the stream and the closer that ties the remote shell and its connection to the session speaking through them — the same three things NewFishVFSOnStream is handed. Whoever built the connection supplies it, which is what keeps SSH out of this file and lets the tests reconnect to a local shell instead.

A nil dialer means the connection cannot be rebuilt, which is the honest answer for a caller that handed over a pair of streams it has no second copy of.

type FishVFS

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

FishVFS exposes a FISH+ session as an f4 file system. It owns the session and closes it with itself; the transport underneath is whatever stream the caller handed over, which is what lets the tests run it on a local shell instead of on ssh.

func NewFishVFS

func NewFishVFS(parent vfs.VFS, host, port, user, pass, keyPath string, timeout int, px netproxy.Settings) (*FishVFS, error)

NewFishVFS opens a site over SSH. It goes through a dialer rather than through a pair of streams, so the session it hands back is one that can be rebuilt after the connection drops; a site opened any other way would have to be reopened by hand.

func NewFishVFSOnDialer

func NewFishVFSOnDialer(ctx context.Context, parent vfs.VFS, dial FishDialer, title string) (*FishVFS, error)

NewFishVFSOnDialer builds a session the same way and remembers how to build it again, which is what a reconnect needs. The dialer is called once here so that a site that cannot be reached fails at open time rather than at the first request.

func NewFishVFSOnDialers

func NewFishVFSOnDialers(ctx context.Context, parent vfs.VFS, dial FishDialer, opts fishplus.HandshakeOptions, dialAlt FishDialer, optsAlt fishplus.HandshakeOptions, title string) (*FishVFS, error)

NewFishVFSOnDialers is NewFishVFSOnDialer with a fallback: a peer the first (dial, opts) pair cannot bring a helper up on is retried with the second pair. Meant for sites where the shell flavor is not known at open time — a POSIX login shell wins the common case, and a PowerShell peer answers only after the retry. Once the fallback succeeds it is promoted to primary, so every reconnect after the first goes straight to the flavor that actually works. A nil dialAlt means no fallback.

func NewFishVFSOnStream

func NewFishVFSOnStream(ctx context.Context, parent vfs.VFS, stdin io.Writer, stdout io.Reader, closer io.Closer, title string) (*FishVFS, error)

NewFishVFSOnStream completes the handshake on an already established pair of streams and opens the panel in whatever directory the remote shell started in. closer may be nil; when set it is closed together with the session, which is also what makes the remote helper exit.

func NewFishVFSOnStreamWithOptions

func NewFishVFSOnStreamWithOptions(ctx context.Context, parent vfs.VFS, stdin io.Writer, stdout io.Reader, closer io.Closer, title string, opts fishplus.HandshakeOptions) (*FishVFS, error)

NewFishVFSOnStreamWithOptions is the transport-specific variant of NewFishVFSOnStream. Most callers should keep the default line bootstrap; transports such as Android shell_v2 can select the single-line base64 bootstrap without changing the FISH+ filesystem implementation.

func NewFishVFSWithOptions

func NewFishVFSWithOptions(parent vfs.VFS, host, port, user, pass, keyPath string, timeout int, px netproxy.Settings, remoteF4 bool) (*FishVFS, error)

NewFishVFSWithOptions is NewFishVFS with the choice of server made by the caller: with remoteF4 set the peer's f4 (--fish-server) is tried before the shell helper (see FishPreferRemoteF4).

func (*FishVFS) Abs

func (v *FishVFS) Abs(p string) (string, error)

func (*FishVFS) Base

func (v *FishVFS) Base(p string) string

func (*FishVFS) BookmarkPath

func (v *FishVFS) BookmarkPath(string) (string, bool)

BookmarkPath implements vfs.BookmarkPathProvider: the folder on the server under the address the session was opened from (bookmark_path.go).

func (*FishVFS) CachedPanelInfo

func (v *FishVFS) CachedPanelInfo(req vfs.PanelInfoRequest) (vfs.PanelInfoSnapshot, bool)

func (*FishVFS) CanReconnect

func (v *FishVFS) CanReconnect() bool

CanReconnect reports whether this file system can rebuild its session. A site opened from a configuration can; one handed a pair of streams cannot, because there is no second pair. A caller offering the user a choice has to know which it is before it offers one.

func (*FishVFS) Client

func (v *FishVFS) Client() *fishplus.Client

Client exposes the underlying protocol client, mostly so a caller can ask what the remote host turned out to be capable of.

func (*FishVFS) Clone

func (v *FishVFS) Clone() vfs.VFS

Clone returns a second view of the same session, with its own current directory. A second login would cost another authentication and another password prompt, and would buy nothing: the remote shell answers one command at a time either way.

func (*FishVFS) CloneForParent

func (v *FishVFS) CloneForParent(parent vfs.VFS) *FishVFS

CloneForParent returns another view of the same live session attached to a different mount parent. Session pools use it to retain a parentless anchor while every panel still gets the manager instance it was opened from.

func (*FishVFS) Close

func (v *FishVFS) Close() error

Close releases this view. The session itself goes away with its last user, and closing the same view twice is harmless: a panel may well be closed by both its own teardown and the frame that owned it.

func (*FishVFS) CommandRunnerAvailable

func (v *FishVFS) CommandRunnerAvailable() bool

func (*FishVFS) CommandRunnerInfo

func (v *FishVFS) CommandRunnerInfo() vfs.CommandRunnerInfo

CommandRunnerInfo reports the remote shell syntax and the transport's real concurrency limit. A FISH+ connection serializes protocol requests, so advertising more workers would only reorder queued requests locally.

func (*FishVFS) ConnectionInfo

func (v *FishVFS) ConnectionInfo() (host, port, user string, ok bool)

ConnectionInfo implements vfs.ConnectionInfoProvider. A session with no host of its own -- the WSL "wsl" site type (wsl_vfs_windows.go) reaches its distribution through a locally spawned wsl.exe, not a network address -- reports ok=false: it is not a second hop any scp-based server-to-server transfer (internal/fileops/ops.go) could ever reach.

func (*FishVFS) Copy

func (v *FishVFS) Copy(ctx context.Context, o, n string) error

Copy implements vfs.ServerSideCopier.

func (*FishVFS) Create

func (v *FishVFS) Create(ctx context.Context, p string) (io.WriteCloser, error)

Create truncates the file, or creates it, and hands back a handle that streams from the beginning. The handle buffers up to one transfer chunk, so the copier's small writes do not each become a round trip.

func (*FishVFS) Dir

func (v *FishVFS) Dir(p string) string

func (*FishVFS) FindDuplicates

func (v *FishVFS) FindDuplicates(ctx context.Context, dir string, cb func(vfs.DuplicateProgress)) ([][]string, error)

FindDuplicates implements vfs.DuplicateFinder. Only the paths of the files that turned out to be identical cross the network; the reading and the hashing happen where the disk is.

func (*FishVFS) FindFiles

func (v *FishVFS) FindFiles(ctx context.Context, dir string, q vfs.FindQuery) ([]vfs.FoundEntry, error)

FindFiles implements vfs.FileFinder. The remote host walks the tree and, when a content pattern is given, greps the candidates in the same pass, so what crosses the network is one request and one line per hit.

A symlink is reported as found without resolving it: the alternative is a round trip per hit, which would give back what the whole command saves.

func (*FishVFS) FindFilesStream

func (v *FishVFS) FindFilesStream(ctx context.Context, dir string, q vfs.FindQuery, onFound func(vfs.FoundEntry)) error

FindFilesStream keeps the panel session free while a synchronous ffind owns its protocol lock. Job searches already release that lock between polls.

func (*FishVFS) GetCapabilities

func (v *FishVFS) GetCapabilities() vfs.VFSCapabilities

func (*FishVFS) GetPath

func (v *FishVFS) GetPath() string

func (*FishVFS) GetTitle

func (v *FishVFS) GetTitle() string

func (*FishVFS) HistoryEntry

func (v *FishVFS) HistoryEntry() (display, ref string, ok bool)

HistoryEntry and NavigateHistoryEntry implement vfs.HistoryPathProvider (f4#262): a FISH+ session owns its own folder-history entries instead of its raw remote path (e.g. /root/foo) being recorded as if it were local.

func (*FishVFS) IsAbs

func (v *FishVFS) IsAbs(p string) bool

func (*FishVFS) IsAtRoot

func (v *FishVFS) IsAtRoot() bool

func (*FishVFS) Join

func (v *FishVFS) Join(e ...string) string

func (*FishVFS) LineIndex

func (v *FishVFS) LineIndex(ctx context.Context, p string, first, count int64) (vfs.LineIndexResult, error)

LineIndex implements vfs.LineIndexer. A count of zero asks for nothing but the total, which is one remote pass and three numbers on the wire.

func (*FishVFS) MkDir

func (v *FishVFS) MkDir(ctx context.Context, p string) error

func (*FishVFS) NavigateHistoryEntry

func (v *FishVFS) NavigateHistoryEntry(ref string) bool

func (*FishVFS) Open

func (v *FishVFS) Open(ctx context.Context, p string) (vfs.ReadAtCloser, error)

func (*FishVFS) OpenPty

func (v *FishVFS) OpenPty(cols, rows int) (any, error)

func (*FishVFS) PanelInfoKey

func (v *FishVFS) PanelInfoKey(req vfs.PanelInfoRequest) string

func (*FishVFS) PanelTitle

func (v *FishVFS) PanelTitle(path string) string

func (*FishVFS) ParentVFS

func (v *FishVFS) ParentVFS() vfs.VFS

func (*FishVFS) PatchFile

func (v *FishVFS) PatchFile(ctx context.Context, src, dst string, pieces []vfs.PatchPiece) error

PatchFile implements vfs.DeltaWriter. The copying happens on the remote host at local disk speed; only the new bytes cross the network.

func (*FishVFS) PtyAvailable

func (v *FishVFS) PtyAvailable() bool

PtyAvailable distinguishes SSH-backed FISH+ from transports such as Android shell_v2. The concrete FishVFS type has OpenPty for the SSH case, but treating every instance as a remote PTY makes Android navigation send Unix cd commands into f4's local terminal on every path change.

func (*FishVFS) PtyChangeDirCommand

func (v *FishVFS) PtyChangeDirCommand(dir string) []byte

PtyChangeDirCommand implements vfs.PtyShellIntegration. The panel's PTY channel runs the peer's DefaultShell — cmd.exe on a stock OpenSSH-Server-Windows host, whatever the login shell is on a POSIX host. Send syntax the actual PTY shell understands, converting the path from the wire's Cygwin shape (/c/Users/foo) to what the shell wants (C:\Users\foo for cmd, /c/Users/foo unchanged for POSIX).

f4_sync is a stray marker helper.sh's own log filter can strip: cmd keeps it as a rem comment, POSIX carries it as "&& true f4_sync" — not a "#" comment, because stock zsh ships with interactive_comments off and would feed the tail to cd as extra arguments.

func (*FishVFS) PtyInitSequence

func (v *FishVFS) PtyInitSequence() []byte

PtyInitSequence implements vfs.PtyShellIntegration. On a Windows peer it sets cmd's PROMPT so that every prompt cmd draws — every time a command finishes — embeds an OSC 133 D marker. The ANSI parser in terminal_view.go then fires OnBusyChange(false), which is what makes panels_frame return to panels after a cmdline command completes. This is the same trick panels_frame.go uses for the local Windows PTY (see the os.Setenv("PROMPT", ...) around initPTY).

$E is cmd's PROMPT syntax for ESC; $E\ is the OSC ST terminator (\x1b\); $P and $G are the standard current-path-and-'>' pieces. The leading @ suppresses cmd's echo of the prompt-setup line in batch contexts; interactive cmd on ConPTY still echoes it, so the second half of the line is a cls that wipes the cmd banner + copyright + the echoed setup line, leaving the panel-terminal view starting on the first marker-embedded prompt with no visible init noise.

func (*FishVFS) PtyInterrupt

func (v *FishVFS) PtyInterrupt() []byte

PtyInterrupt implements vfs.PtyShellIntegration. cmd.exe over ConPTY and every POSIX shell treat a raw ETX (0x03) as SIGINT / Ctrl+C; no flavor-specific wrapping is needed.

func (*FishVFS) PtyRunCommand

func (v *FishVFS) PtyRunCommand(dir, command string) []byte

PtyRunCommand implements vfs.PtyShellIntegration. Same shell-flavor split as PtyChangeDirCommand: cmd wants "cd /d \"path\" & command", POSIX wants "cd 'path' && command". An empty dir skips the cd.

func (*FishVFS) ReadDir

func (v *FishVFS) ReadDir(ctx context.Context, p string, onChunk func([]vfs.VFSItem)) error

func (*FishVFS) Reconnect

func (v *FishVFS) Reconnect(ctx context.Context) error

Reconnect rebuilds the session behind this file system and points this view at the result. The new shell knows nothing of what the old one was doing: background jobs are gone, and a write or a patch that was in flight cannot be resumed, only reported. What survives is what lives on this side — the path this panel stands in, a read handle, and the credentials the dialer holds.

It is deliberately not called from inside a request. A request that reconnected on its own would turn one failure into a delay of unknown length in the middle of a copy, with no way for the user to say no; the choice belongs to whoever meets ErrBroken and can ask.

Every view of the connection is repointed, not just this one: they all reach the session through the connection, so the panel that asked and the panel next to it are on the same shell afterwards. What each of them keeps is its own current directory, which never depended on the shell that died.

func (*FishVFS) RefreshPanelInfo

func (v *FishVFS) RefreshPanelInfo(ctx context.Context, req vfs.PanelInfoRequest) (vfs.PanelInfoSnapshot, error)

func (*FishVFS) Remove

func (v *FishVFS) Remove(ctx context.Context, p string) error

Remove deletes whatever is at the path. A directory is removed with everything below it by the remote host itself, in one round trip instead of one per entry, which is the main reason a shell based file system is worth having at all.

func (*FishVFS) Rename

func (v *FishVFS) Rename(ctx context.Context, o, n string) error

func (*FishVFS) RunCommand

func (v *FishVFS) RunCommand(ctx context.Context, dir, command string, cb func(line string)) (int, error)

RunCommand implements vfs.CommandRunner. The command runs as a job, so it can read stdin, print for an hour or never end without any of that reaching the request stream the panel is using.

func (*FishVFS) Scan

func (v *FishVFS) Scan(ctx context.Context, basePath string, names []string, cb vfs.ScanCallback) (vfs.OpStats, error)

Scan implements vfs.FastScanner. Counting a tree is one remote job instead of a listing round trip per directory, which is the difference between a directory size dialog that answers and one the user gives up on.

Anything the remote host cannot do falls back to the generic walk, because the caller takes this answer as final: vfs.CalculateStats does not retry a FastScanner that failed.

func (*FishVFS) Search

func (v *FishVFS) Search(ctx context.Context, p, pattern string) (chan int64, error)

Search hands the pattern to the remote host's own grep and returns the byte offset of every match. Only the offsets cross the network, which is what lets a panel search a log it would take an hour to download. A host without the tools answers nil, and the caller falls back to reading the file, exactly as it does with SFTP.

func (*FishVFS) SecondHopPassword

func (v *FishVFS) SecondHopPassword() (string, bool)

SecondHopPassword implements vfs.SecondHopPasswordProvider. It answers on this site's own behalf: a server-to-server transfer that wants to authenticate to this exact host, port and user with a password asks here, and gets one back only when NetFox's "password auth for server-to-server transfers" setting is on and a saved connection matches (see secondHopPassword in s2s_password.go).

func (*FishVFS) SessionKey

func (v *FishVFS) SessionKey() any

SessionKey implements vfs.SessionIdentity. The connection is the identity: a clone shares it, which is exactly the property a caller looking for everything that died with one session needs.

func (*FishVFS) SessionLost

func (v *FishVFS) SessionLost(err error) bool

SessionLost implements vfs.SessionReconnector. Only a session that stopped speaking counts: a file that is not there, a permission that was refused or a cancelled request are failures of the request, and offering to reconnect over any of them would be noise in front of the real message.

func (*FishVFS) SetAttributes

func (v *FishVFS) SetAttributes(ctx context.Context, p string, item vfs.VFSItem) error

SetAttributes applies the permission bits, then the ownership, then the timestamps. A Uid or Gid below zero means "leave that half alone", which is what the copier passes; a zero timestamp is filled in from the other one, the same way the SFTP backend does it, so a file copied onto a FISH+ panel keeps the times it had.

func (*FishVFS) SetPanelInfoProvider

func (v *FishVFS) SetPanelInfoProvider(provider vfs.PanelInfoProvider)

SetPanelInfoProvider attaches transport-specific facts without wrapping the filesystem. Keeping *FishVFS as the mounted concrete type is important to the Android session pool and to callers that inspect protocol features.

func (*FishVFS) SetPanelTitleFormatter

func (v *FishVFS) SetPanelTitleFormatter(formatter func(title, path string) string)

SetPanelTitleFormatter customizes only the path rendered in the panel border. The canonical POSIX path and the session title remain untouched.

func (*FishVFS) SetPath

func (v *FishVFS) SetPath(p string) error

func (*FishVFS) SetPathOptimistic

func (v *FishVFS) SetPathOptimistic(p string) error

SetPathOptimistic only changes this view's client-side path. A panel calls it for a row already known to be a directory, including a cached row, then validates that possibly stale knowledge with its asynchronous ReadDir. FISH+ sends absolute paths with every command and has no server-side cwd, so no protocol request is needed here.

func (*FishVFS) StageSecret

func (v *FishVFS) StageSecret(ctx context.Context, password string) (string, func(context.Context), error)

StageSecret implements vfs.SecondHopSecretStager. The secret travels to this host over the same encrypted FISH+ write channel every ordinary file transfer already uses (Client.Write) -- never as part of a command's own text, never through an environment variable a sibling process could read out of /proc, and never logged -- and lands in a file mktemp created for this call alone, which cleanup removes again once the caller is done.

func (*FishVFS) Stat

func (v *FishVFS) Stat(ctx context.Context, p string) (vfs.VFSItem, error)

Stat reports the link itself rather than its target, so the panel can draw a symlink as one, and only resolves it to answer the IsDir question.

type NetFoxConfig

type NetFoxConfig struct {
	Type     string            `json:"Type"`
	Host     string            `json:"Host"`
	Port     string            `json:"Port"`
	User     string            `json:"User"`
	Pass     string            `json:"Pass"`
	KeyPath  string            `json:"KeyPath,omitempty"`
	Timeout  string            `json:"Timeout,omitempty"`
	Codepage string            `json:"Codepage,omitempty"`
	Options  map[string]string `json:"Options,omitempty"`
	// Path is the folder the connection opens in, like the path of a Far
	// connection (nz256, f4#1894); empty opens where the server puts a new
	// session, the home folder of the user as a rule.
	Path string `json:"Path,omitempty"`

	// Proxy overrides f4's app-wide proxy for this site alone. ProxyMode 0
	// is netproxy.ModeGlobal, so connections saved before this existed —
	// and new ones the user never touched — simply follow the app setting.
	ProxyMode int    `json:"ProxyMode,omitempty"`
	ProxyHost string `json:"ProxyHost,omitempty"`
	ProxyPort string `json:"ProxyPort,omitempty"`
	ProxyUser string `json:"ProxyUser,omitempty"`
	ProxyPass string `json:"ProxyPass,omitempty"`
}

func (NetFoxConfig) Proxy

func (c NetFoxConfig) Proxy() netproxy.Settings

Proxy is the settings this connection dials through: its own when it overrides, the app-wide ones otherwise.

type NetFoxPlugin

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

func (*NetFoxPlugin) Close

func (p *NetFoxPlugin) Close() error

func (*NetFoxPlugin) GetName

func (p *NetFoxPlugin) GetName() string

func (*NetFoxPlugin) Init

func (p *NetFoxPlugin) Init(api vfs.HostAPI) error

type NetFoxVFS

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

func NewNetFoxVFS

func NewNetFoxVFS(dbPath string) *NetFoxVFS

func (*NetFoxVFS) Abs

func (v *NetFoxVFS) Abs(p string) (string, error)

func (*NetFoxVFS) Base

func (v *NetFoxVFS) Base(p string) string

func (*NetFoxVFS) BookmarkPath

func (v *NetFoxVFS) BookmarkPath(cursor string) (string, bool)

BookmarkPath implements vfs.BookmarkPathProvider for the connection manager: a bookmark made with the cursor on a saved connection is the address of that connection, so a connection is bookmarked without being opened; anywhere else in the list it is the manager itself.

func (*NetFoxVFS) Clone

func (v *NetFoxVFS) Clone() vfs.VFS

func (*NetFoxVFS) Close

func (v *NetFoxVFS) Close() error

func (*NetFoxVFS) Create

func (v *NetFoxVFS) Create(ctx context.Context, p string) (io.WriteCloser, error)

func (*NetFoxVFS) Dir

func (v *NetFoxVFS) Dir(p string) string

func (*NetFoxVFS) GetCapabilities

func (v *NetFoxVFS) GetCapabilities() vfs.VFSCapabilities

func (*NetFoxVFS) GetPath

func (v *NetFoxVFS) GetPath() string

func (*NetFoxVFS) HistoryEntry

func (v *NetFoxVFS) HistoryEntry() (display, ref string, ok bool)

HistoryEntry implements vfs.HistoryPathProvider. The root screen is a list of saved connections, not a folder, so it never has anything worth remembering in folder history (f4#262): without this, the bare "net://" GetPath() above fell through to ShouldRecordFolderHistory's "no parent VFS, trust it as a local path" rule and was recorded as a useless entry point with no navigational value.

func (*NetFoxVFS) IsAbs

func (v *NetFoxVFS) IsAbs(p string) bool

func (*NetFoxVFS) IsAtRoot

func (v *NetFoxVFS) IsAtRoot() bool

func (*NetFoxVFS) IsReadOnly

func (v *NetFoxVFS) IsReadOnly() bool

func (*NetFoxVFS) Join

func (v *NetFoxVFS) Join(e ...string) string

func (*NetFoxVFS) MkDir

func (v *NetFoxVFS) MkDir(ctx context.Context, p string) error

func (*NetFoxVFS) NavigateHistoryEntry

func (v *NetFoxVFS) NavigateHistoryEntry(ref string) bool

NavigateHistoryEntry implements vfs.HistoryPathProvider. HistoryEntry above never produces an entry for the root screen, so this is never reached through the normal folder-history flow; it exists only to satisfy the interface and always declines.

func (*NetFoxVFS) Open

func (v *NetFoxVFS) Open(ctx context.Context, p string) (vfs.ReadAtCloser, error)

func (*NetFoxVFS) ParentVFS

func (v *NetFoxVFS) ParentVFS() vfs.VFS

func (*NetFoxVFS) ReadDir

func (v *NetFoxVFS) ReadDir(ctx context.Context, p string, onChunk func([]vfs.VFSItem)) error

func (*NetFoxVFS) Remove

func (v *NetFoxVFS) Remove(ctx context.Context, p string) error

func (*NetFoxVFS) Rename

func (v *NetFoxVFS) Rename(ctx context.Context, old, new string) error

func (*NetFoxVFS) SaveConfig

func (v *NetFoxVFS) SaveConfig(name string, cfg NetFoxConfig) error

func (*NetFoxVFS) Search

func (v *NetFoxVFS) Search(ctx context.Context, p, pat string) (chan int64, error)

func (*NetFoxVFS) SetAttributes

func (v *NetFoxVFS) SetAttributes(ctx context.Context, path string, item vfs.VFSItem) error

func (*NetFoxVFS) SetPath

func (v *NetFoxVFS) SetPath(p string) error

SetPath accepts the spellings of the manager's own root and nothing else. The list has no folders, and a net://<name> address (net_uri.go) must reach the URI provider rather than be swallowed here as a folder the manager is "already in": the panel tries the current file system first.

func (*NetFoxVFS) Stat

func (v *NetFoxVFS) Stat(ctx context.Context, p string) (vfs.VFSItem, error)

type ProtocolHandler

type ProtocolHandler interface {
	Prefix() string
	DefaultPort() string
	BuildExtraUI(cfg *NetFoxConfig, x, y, w, h int) (vtui.UIElement, func())
}

type SFTPVFS

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

func NewSFTPVFS

func NewSFTPVFS(parent vfs.VFS, host, port, user, pass, keyPath string, timeout int, cp string, px netproxy.Settings) (*SFTPVFS, error)

func (*SFTPVFS) Abs

func (v *SFTPVFS) Abs(p string) (string, error)

func (*SFTPVFS) Base

func (v *SFTPVFS) Base(p string) string

func (*SFTPVFS) BookmarkPath

func (v *SFTPVFS) BookmarkPath(string) (string, bool)

BookmarkPath implements vfs.BookmarkPathProvider: the folder on the server under the address the session was opened from (bookmark_path.go).

func (*SFTPVFS) Clone

func (v *SFTPVFS) Clone() vfs.VFS

func (*SFTPVFS) Close

func (v *SFTPVFS) Close() error

func (*SFTPVFS) CommandRunnerInfo

func (*SFTPVFS) CommandRunnerInfo() vfs.CommandRunnerInfo

CommandRunnerInfo describes commands executed in independent SSH sessions. A modest cap avoids opening an unbounded number of channels on servers with conservative MaxSessions settings while still permitting useful parallelism.

func (*SFTPVFS) Create

func (v *SFTPVFS) Create(ctx context.Context, p string) (io.WriteCloser, error)

func (*SFTPVFS) Dir

func (v *SFTPVFS) Dir(p string) string

func (*SFTPVFS) EncodeCommandListANSI

func (v *SFTPVFS) EncodeCommandListANSI(text []byte) ([]byte, error)

EncodeCommandListANSI applies the same configured filename codepage used by this panel. A fresh encoder keeps parallel Apply workers independent.

func (*SFTPVFS) GetCapabilities

func (v *SFTPVFS) GetCapabilities() vfs.VFSCapabilities

func (*SFTPVFS) GetPath

func (v *SFTPVFS) GetPath() string

func (*SFTPVFS) GetTitle

func (v *SFTPVFS) GetTitle() string

func (*SFTPVFS) HistoryEntry

func (v *SFTPVFS) HistoryEntry() (display, ref string, ok bool)

HistoryEntry and NavigateHistoryEntry implement vfs.HistoryPathProvider (f4#262): an SFTP session owns its own folder-history entries instead of its raw remote path (e.g. /root/foo) being recorded as if it were local.

func (*SFTPVFS) IsAbs

func (v *SFTPVFS) IsAbs(p string) bool

func (*SFTPVFS) IsAtRoot

func (v *SFTPVFS) IsAtRoot() bool

func (*SFTPVFS) Join

func (v *SFTPVFS) Join(e ...string) string

func (*SFTPVFS) MkDir

func (v *SFTPVFS) MkDir(ctx context.Context, p string) error

func (*SFTPVFS) NavigateHistoryEntry

func (v *SFTPVFS) NavigateHistoryEntry(ref string) bool

func (*SFTPVFS) Open

func (v *SFTPVFS) Open(ctx context.Context, p string) (vfs.ReadAtCloser, error)

func (*SFTPVFS) OpenPty

func (v *SFTPVFS) OpenPty(cols, rows int) (any, error)

func (*SFTPVFS) OpenWriteAt

func (v *SFTPVFS) OpenWriteAt(ctx context.Context, p string) (vfs.WriterAtCloser, error)

OpenWriteAt makes SFTPVFS a vfs.RandomWriteVFS. This is the backend the interface was written for: a remote file is exactly where re-uploading everything to change ten bytes hurts.

func (*SFTPVFS) ParentVFS

func (v *SFTPVFS) ParentVFS() vfs.VFS

func (*SFTPVFS) ReadDir

func (v *SFTPVFS) ReadDir(ctx context.Context, p string, onChunk func([]vfs.VFSItem)) error
func (v *SFTPVFS) Readlink(ctx context.Context, p string) (string, error)

func (*SFTPVFS) Remove

func (v *SFTPVFS) Remove(ctx context.Context, p string) error

func (*SFTPVFS) Rename

func (v *SFTPVFS) Rename(ctx context.Context, o, n string) error

func (*SFTPVFS) RunCommand

func (v *SFTPVFS) RunCommand(ctx context.Context, dir, command string, cb func(line string)) (int, error)

RunCommand starts a new SSH session rather than borrowing either the SFTP subsystem's channel or the panel's interactive PTY. The current directory is resolved before opening that session, so later panel navigation cannot move a command that is already being dispatched.

func (*SFTPVFS) Search

func (v *SFTPVFS) Search(ctx context.Context, p, pat string) (chan int64, error)

func (*SFTPVFS) SessionKey

func (v *SFTPVFS) SessionKey() any

func (*SFTPVFS) SetAttributes

func (v *SFTPVFS) SetAttributes(ctx context.Context, path string, item vfs.VFSItem) error

func (*SFTPVFS) SetPath

func (v *SFTPVFS) SetPath(p string) error

func (*SFTPVFS) Stat

func (v *SFTPVFS) Stat(ctx context.Context, p string) (vfs.VFSItem, error)

func (*SFTPVFS) SupportsConcurrentCalls

func (*SFTPVFS) SupportsConcurrentCalls() bool

The upstream SFTP client multiplexes independent requests safely over one SSH connection. This lets FUSE serve directory listings, stats, and reads concurrently instead of making a remote mount wait behind one operation.

func (v *SFTPVFS) Symlink(ctx context.Context, target, linkPath string) error

type SSHPty

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

func NewSSHPty

func NewSSHPty(client *ssh.Client) (*SSHPty, error)

func (*SSHPty) Close

func (p *SSHPty) Close() error

func (*SSHPty) IsBusy

func (p *SSHPty) IsBusy() bool

func (*SSHPty) Read

func (p *SSHPty) Read(b []byte) (int, error)

func (*SSHPty) Run

func (p *SSHPty) Run(name string, args ...string) error

func (*SSHPty) SetSize

func (p *SSHPty) SetSize(cols, rows int)

func (*SSHPty) Wait

func (p *SSHPty) Wait() error

func (*SSHPty) Write

func (p *SSHPty) Write(b []byte) (int, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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