Documentation
¶
Overview ¶
Package cliclient implements the HTTP client behind `filex client` — the subcommand family that talks to a REMOTE filex server over its public REST API. It deliberately reuses only the wire contracts (no server-side imports) so the same binary can act as a pure API consumer from any machine.
upload.go — recursive (tree) upload on top of the single-file Upload core in api.go. Only existing server verbs are used: `newfolder` to materialize directories (empty ones included) and the streaming multipart `upload` for files. Symlinks are never followed — they are reported and skipped, so a cyclic link can't wedge the walk. Named pipes, sockets and devices are reported and skipped too: opening a pipe nobody writes to never returns (issue #38).
Index ¶
- Constants
- Variables
- func ConversionWrite(ctx context.Context) context.Context
- func DefaultConfigPath() (string, error)
- func DefaultResumeDir() (string, error)
- func IsCaptchaRefusal(err error) bool
- func IsTOTPRequired(err error) bool
- func IsUnauthorized(err error) bool
- func IsVaultCode(err error, code string) bool
- func SaveFileConfig(path string, cfg FileConfig) error
- type APIError
- type AppAction
- type ArchiveCreateOptions
- type ChangeStream
- type Client
- func (c *Client) AccountLanguage(ctx context.Context) (string, error)
- func (c *Client) AllTags(ctx context.Context) ([]TagItem, []byte, error)
- func (c *Client) AppActions(ctx context.Context) ([]AppAction, []byte, error)
- func (c *Client) Changes(ctx context.Context, remote, since string) (cursor string, changed bool, err error)
- func (c *Client) Copy(ctx context.Context, src, dst string) (*Transfer, error)
- func (c *Client) CreateArchive(ctx context.Context, dest string, sources []string, opt ArchiveCreateOptions) (*Op, []byte, error)
- func (c *Client) Download(ctx context.Context, remote string, w io.Writer) (int64, error)
- func (c *Client) DownloadSized(ctx context.Context, remote string, w io.Writer, want int64) (int64, error)
- func (c *Client) E2EAllowed(ctx context.Context, remote, kind string) (answer, reason string, err error)
- func (c *Client) E2ECleanup(ctx context.Context, remote string, versions, trash bool) (*E2ECleanupResult, error)
- func (c *Client) E2EEscrowKey(ctx context.Context) (string, error)
- func (c *Client) EditTags(ctx context.Context, nodeID int64, edit TagEdit) (*FileTags, error)
- func (c *Client) ExtractArchive(ctx context.Context, path, dest, password string, members []string) (*Op, []byte, error)
- func (c *Client) GetOp(ctx context.Context, id int64) (*Op, []byte, error)
- func (c *Client) IsDir(ctx context.Context, remote string) (bool, error)
- func (c *Client) List(ctx context.Context, remote string) (*ListResult, error)
- func (c *Client) ListStats(ctx context.Context, remote string) ([]*Stat, error)
- func (c *Client) Login(ctx context.Context, in LoginRequest) (*LoginResponse, error)
- func (c *Client) Mkdir(ctx context.Context, remote string) ([]byte, error)
- func (c *Client) Move(ctx context.Context, src, dst string) (*Transfer, error)
- func (c *Client) MyShares(ctx context.Context, activeOnly bool, limit, offset int) (*SharePage, error)
- func (c *Client) NodeID(ctx context.Context, remote string) (int64, error)
- func (c *Client) PluginRequests(ctx context.Context, status string) ([]PluginRequest, []byte, error)
- func (c *Client) ReadRange(ctx context.Context, remote string, off, length int64) ([]byte, error)
- func (c *Client) ReadSmall(ctx context.Context, remote string, max int64) ([]byte, error)
- func (c *Client) ReadWhole(ctx context.Context, remote string, limit int64) ([]byte, error)
- func (c *Client) Remove(ctx context.Context, remote string) ([]byte, error)
- func (c *Client) Rename(ctx context.Context, item RemotePath, newName string) error
- func (c *Client) RequestPlugin(ctx context.Context, in PluginRequestInput) (*PluginRequestAnswer, error)
- func (c *Client) RestoreTrash(ctx context.Context, id int64) ([]byte, error)
- func (c *Client) RestoreVersion(ctx context.Context, nodeID, versionID int64) ([]byte, error)
- func (c *Client) RunAction(ctx context.Context, plugin, action string, paths []string, ...) (*Op, []byte, error)
- func (c *Client) Search(ctx context.Context, query, scope string, storageID int64, limit int) (*SearchResult, error)
- func (c *Client) SearchFiltered(ctx context.Context, query, scope string, storageID int64, limit int, ...) (*SearchResult, error)
- func (c *Client) SetTags(ctx context.Context, nodeID int64, items []TagItem) (*FileTags, error)
- func (c *Client) Share(ctx context.Context, remote string, pin bool, expiresDays int) (*ShareResult, error)
- func (c *Client) SizeOf(ctx context.Context, remote string) (int64, error)
- func (c *Client) Space(ctx context.Context, remote string) (*Space, error)
- func (c *Client) StatPath(ctx context.Context, remote string) (*Stat, error)
- func (c *Client) TaggedFiles(ctx context.Context, tag, kind string, limit int) ([]TaggedFile, []byte, error)
- func (c *Client) TagsOf(ctx context.Context, nodeID int64) (*FileTags, error)
- func (c *Client) Trash(ctx context.Context, storageID int64, limit, offset int) (*TrashPage, error)
- func (c *Client) TrashSame(ctx context.Context, items []TrashSameItem) ([]TrashSameAnswer, error)
- func (c *Client) UILocale(ctx context.Context, code string) (map[string]string, error)
- func (c *Client) Unshare(ctx context.Context, id int64) ([]byte, error)
- func (c *Client) Upload(ctx context.Context, localPath, remote string) (RemotePath, []byte, error)
- func (c *Client) UploadTo(ctx context.Context, localPath string, destDir RemotePath, name, expect string) ([]byte, error)
- func (c *Client) UploadTree(ctx context.Context, localDir, remote string, progress TreeProgress) (*TreeReport, error)
- func (c *Client) VaultBreak(ctx context.Context, remote string) error
- func (c *Client) VaultDelete(ctx context.Context, remote, token string, packs []string, indexes []uint64) (int, int, error)
- func (c *Client) VaultIdleMinutes(ctx context.Context) (int, error)
- func (c *Client) VaultList(ctx context.Context, remote, kind, after string, limit int) ([]VaultListItem, string, error)
- func (c *Client) VaultListAll(ctx context.Context, remote, kind string) ([]VaultListItem, error)
- func (c *Client) VaultLock(ctx context.Context, remote, client, label string) (*VaultLock, error)
- func (c *Client) VaultPutIndex(ctx context.Context, remote, token string, gen uint64, file []byte) (uint64, error)
- func (c *Client) VaultPutPack(ctx context.Context, remote, token, id string, pack []byte) error
- func (c *Client) VaultRelease(ctx context.Context, remote, token string) error
- func (c *Client) VaultRenew(ctx context.Context, remote, token string, active bool) (*VaultRenewal, error)
- func (c *Client) VaultState(ctx context.Context, remote string) (*VaultState, error)
- func (c *Client) Versions(ctx context.Context, nodeID int64) (*VersionList, error)
- func (c *Client) WaitOp(ctx context.Context, id int64) (*Op, []byte, error)
- func (c *Client) WriteSmall(ctx context.Context, destDir RemotePath, name string, data []byte, ...) error
- type Conn
- type E2ECleanupResult
- type FileConfig
- type FileTags
- type ListEntry
- type ListResult
- type LoginRequest
- type LoginResponse
- type MyShare
- type Op
- type OpError
- type OpOutput
- type PluginRequest
- type PluginRequestAnswer
- type PluginRequestInput
- type RateLimiter
- type RemotePath
- type SearchHit
- type SearchResult
- type SharePage
- type ShareResult
- type SizeMismatchError
- type Space
- type Stat
- type StreamState
- type TagEdit
- type TagItem
- type TaggedFile
- type Transfer
- type TrashEntry
- type TrashPage
- type TrashSameAnswer
- type TrashSameItem
- type TreeChange
- type TreeError
- type TreeEvent
- type TreeProgress
- type TreeReport
- type VaultError
- type VaultHolder
- type VaultListItem
- type VaultLock
- type VaultLockInfo
- type VaultRenewal
- type VaultState
- type VaultTime
- type Version
- type VersionList
Constants ¶
const ( TagPersonal = "personal" TagTeam = "team" )
Tag kinds.
const ( TreeDir = "dir" // remote directory ensured (created or existing) TreeFile = "file" // file uploaded TreeSymlink = "symlink" // local symlink skipped TreeSpecial = "special" // local named pipe, socket or device skipped TreeErr = "error" // one item failed (walk continues) )
Tree event kinds delivered to a TreeProgress callback.
const ( VaultCodeLocked = "VAULT_LOCKED" VaultCodeLockLost = "VAULT_LOCK_LOST" VaultCodeNotAVault = "NOT_A_VAULT" VaultCodePackExists = "VAULT_PACK_EXISTS" VaultCodeGeneration = "VAULT_GENERATION" VaultCodeBadObject = "VAULT_BAD_OBJECT" VaultCodeKeep = "VAULT_KEEP" VaultCodeVaultPath = "VAULT_PATH" VaultClientCLI = "cli" VaultClientMount = "mount" )
The error codes of the vault API this client acts on.
const DefaultOpPollInterval = 500 * time.Millisecond
DefaultOpPollInterval is how often WaitOp asks about a running op.
const DefaultStagedThreshold = 8 << 20
DefaultStagedThreshold is the size at which the CLI switches from the one-shot multipart POST to the resumable staged protocol. It matches the server's default chunk size, so "large" means the same thing on both ends.
const EnvInsecureSkipTLSVerify = "FILEX_INSECURE_SKIP_TLS_VERIFY"
EnvInsecureSkipTLSVerify says for one run what --insecure-skip-tls-verify says: the desktop app starts its sync engine with it for an account that has the switch on, next to FILEX_URL and FILEX_TOKEN, because the switch is that connection's and an environment is per process.
const InsecureNotice = "This is not safe and not recommended. Apply it only if you know what you are doing. " +
"The server's certificate is not checked, so anybody who can get between you and the server can pose as it: " +
"read and change what crosses, and take your session."
InsecureNotice is what the CLI says wherever the check is turned off: the same fixed sentence as under every such setting on the admin panel (`securityOff.note`), then what this one exposes.
const TrashSameMax = 50
TrashSameMax is how many entries one TrashSame request may name.
const VaultLockHeader = "X-Filex-Vault-Lock"
VaultLockHeader carries the write lock's token on every vault write.
Variables ¶
var ErrActionNeedsInput = errors.New("this action asks for its input in a form")
ErrActionNeedsInput is an action that opens a form in the explorer and was run with no parameters: the server answered the form instead of queueing.
var ErrArchivePassword = errors.New("the archive is encrypted")
ErrArchivePassword is an encrypted archive extracted with no password or a wrong one (401 PASSWORD_REQUIRED / BAD_PASSWORD). Nothing was extracted.
var ErrChangesUnsupported = errors.New("the server cannot report changes")
ErrChangesUnsupported means the server has no `action=changes` (anything before it answers 501): the caller has to walk the tree to find out.
var ErrNoRange = errors.New("cliclient: the server ignored the requested range")
ErrNoRange means the server answered a ranged request with the whole object.
⚠ It is a real error, not a fallback: a caller that asked for bytes [1000,2000) and silently received [0,N) would write the WRONG BYTES into a file at the offset it asked about. Wrong data is worse than a refusal.
var ErrObjectTooLarge = errors.New("the file is larger than it may be")
ErrObjectTooLarge: a whole read stopped at its limit.
var ErrPreconditionFailed = errors.New("the file changed on the server since it was listed")
ErrPreconditionFailed is a conditional upload the server refused because the target is no longer what the caller last saw (HTTP 412, code PRECONDITION_FAILED). Nothing was written.
var ErrTargetExists = errors.New("the target already exists")
ErrTargetExists is a copy or move to a full path whose name is already taken. Nothing was sent: the CLI never replaces, and the server would put the item beside it under another name rather than at the path that was typed.
Functions ¶
func ConversionWrite ¶ added in v0.50.0
ConversionWrite marks every upload made under the returned context as an end-to-end CONVERSION write (`e2e_convert=1`): ciphertext replacing the plaintext it was made from, inside a folder whose key file says a conversion is under way. The server keeps no version of what such a write replaces - and only for a write it has checked is one; anything else is an ordinary overwrite. The flag rides where the server reads it: the multipart form, and the staged commit.
func DefaultConfigPath ¶
DefaultConfigPath returns the CLI config location: $FILEX_CLI_CONFIG when set (tests / unusual homes), otherwise ~/.filex/cli.yaml.
func DefaultResumeDir ¶
DefaultResumeDir is where upload bookmarks live: $FILEX_UPLOAD_STATE when set (tests, unusual homes), otherwise ~/.filex/uploads.
func IsCaptchaRefusal ¶ added in v0.60.0
IsCaptchaRefusal reports whether the server refused a sign-in for its bot check (internal/captcha: 422 / 409 / 503 with a `captcha` field).
func IsTOTPRequired ¶ added in v0.50.0
IsTOTPRequired reports whether err is the server asking for (or refusing) the second factor: an answer whose body carries totp_required.
func IsUnauthorized ¶
IsUnauthorized reports whether err is an APIError with status 401 — the CLI uses it to append the "run `filex client login`" hint.
func IsVaultCode ¶ added in v0.54.0
IsVaultCode reports whether err is a vault API answer with that code.
func SaveFileConfig ¶
func SaveFileConfig(path string, cfg FileConfig) error
SaveFileConfig writes the CLI config with owner-only permissions. The explicit Chmod after the write covers a pre-existing file whose looser mode WriteFile would otherwise keep.
Types ¶
type APIError ¶
type APIError struct {
Status int
// Code is the refusal's code (`error` in the server's envelope,
// internal/apierr), for a program to branch on; "" when it sent none.
Code string
// Message is what to print: the server's sentence in the reader's
// language (`message`), else its `error`, else a clip of the body.
Message string
Body []byte
}
APIError is a non-2xx response mapped to an error. Body keeps the raw payload so callers can inspect extra fields (e.g. totp_required).
type AppAction ¶ added in v0.50.0
type AppAction struct {
Plugin string `json:"plugin"`
ID string `json:"id"`
Label map[string]string `json:"label"`
Applies struct {
Kind string `json:"kind,omitempty"`
Ext []string `json:"ext,omitempty"`
Mime []string `json:"mime,omitempty"`
Multi bool `json:"multi,omitempty"`
} `json:"applies"`
// View names the form the action asks its input in, in the explorer.
View string `json:"view,omitempty"`
}
AppAction is one action an installed app offers the caller (GET /api/files/plugins/actions).
type ArchiveCreateOptions ¶ added in v0.50.0
type ArchiveCreateOptions struct {
Format string // zip | 7z | tar | tar.gz | tar.bz2 | tar.xz | tar.zst (what the server allows)
Password string // zip and 7z only
EncryptNames bool // 7z: encrypt the file names too
Compression int // 0-9; 0 = the server's default
}
ArchiveCreateOptions are the choices of POST /api/files/archive/create. Zero values are the server's defaults (the format from the archive's extension, then the administrator's default).
type ChangeStream ¶
type ChangeStream struct {
Client *Client
// OnChange receives every change frame. Called from the stream's reader
// goroutine; it must not block for long.
OnChange func(TreeChange)
// OnState receives every state transition, with a human-readable detail.
OnState func(state StreamState, detail string)
// OnConnected runs after every successful subscribe — the first one and
// every reconnect. Changes made while the stream was down were not
// announced to anybody; the caller answers this by asking what changed.
OnConnected func()
// (HTTP 401 on the ticket). The stream stops for good: retrying a
// revoked token only fills the server's log.
OnUnauthorized func(error)
// Tunables. Zero values mean the production defaults; tests shrink them.
PingEvery time.Duration // keep-alive + dead-connection detection
AckTimeout time.Duration // how long to wait for `watching`
UnsupportedRetry time.Duration // re-probe a server without the stream
MaxBackoff time.Duration // ceiling of the reconnect backoff
// contains filtered or unexported fields
}
ChangeStream follows the server's change stream for a set of watch roots.
func (*ChangeStream) Run ¶
func (s *ChangeStream) Run(ctx context.Context)
Run keeps the stream up until ctx ends: connect, subscribe, read, and on any failure back off and do it again.
func (*ChangeStream) SetRoots ¶
func (s *ChangeStream) SetRoots(roots []string)
SetRoots replaces the folders being watched. Safe to call at any time; a live connection re-subscribes at once.
func (*ChangeStream) State ¶
func (s *ChangeStream) State() StreamState
State reports the current state ("" before the first attempt).
type Client ¶
type Client struct {
BaseURL string
Token string
HTTP *http.Client
// StagedThreshold is the file size at or above which uploads use the
// resumable staged protocol instead of one multipart POST. 0 means the
// default (DefaultStagedThreshold); a negative value disables the staged
// path, which is how a caller pins the old behaviour.
StagedThreshold int64
// ChunkSize is the part size asked for at `begin`. 0 lets the server
// choose — and the server's answer is binding either way.
ChunkSize int64
// ResumeDir holds the bookmarks that let an interrupted upload continue
// across process restarts. Empty disables persistence: uploads still
// resume within a run, but a restart begins the file again.
ResumeDir string
// DownLimit and UpLimit cap download and upload bodies (bytes per
// second), shared by every transfer of this client. nil = no limit.
DownLimit *RateLimiter
UpLimit *RateLimiter
// OpPollInterval is how often WaitOp asks about a queued operation. 0
// means DefaultOpPollInterval.
OpPollInterval time.Duration
// contains filtered or unexported fields
}
Client is a thin REST client for one filex server. Token may be either a session token minted by /api/auth/login or a durable API token — the server accepts both on the Authorization: Bearer header.
func New ¶
New builds a Client from a resolved Conn. No global timeout is set — uploads/downloads stream arbitrarily large bodies; cancellation is the caller's context (Ctrl-C in the CLI).
func (*Client) AccountLanguage ¶ added in v0.54.0
AccountLanguage is the interface language the signed-in account chose (GET /api/auth/me → user.locale), "" when it chose none. The sync engine's event stream (`filex sync run --json`) speaks it when nobody named a language, the way the server says a notification in the account's language when the request names none.
func (*Client) AllTags ¶ added in v0.50.0
AllTags lists every tag the caller can see, both kinds (GET /api/files/manager/tags/all).
func (*Client) AppActions ¶ added in v0.50.0
AppActions lists the actions the caller may run.
func (*Client) Changes ¶
func (c *Client) Changes(ctx context.Context, remote, since string) (cursor string, changed bool, err error)
Changes asks whether anything under the folder remote changed since the cursor since (empty = never asked; always "changed"), and returns the cursor to send next time. One request, instead of listing the whole tree.
func (*Client) Copy ¶ added in v0.50.0
Copy implements Unix-cp semantics with Move's target rules (no rename short-cut: a copy into its own folder under another name is a copy). A copy into a folder that already holds the name lands beside it as `name-copy.ext`; a copy to a taken full path is refused (ErrTargetExists). Folders are copied whole.
func (*Client) CreateArchive ¶ added in v0.50.0
func (c *Client) CreateArchive(ctx context.Context, dest string, sources []string, opt ArchiveCreateOptions) (*Op, []byte, error)
CreateArchive packs sources (files and folders, `adapter://path`) into a new archive at dest and waits for it. A dest that exists is refused (409 TARGET_EXISTS); nothing is overwritten.
func (*Client) Download ¶
Download streams the remote file into w and returns the byte count.
⚠ Only a body that IS the file is ever copied: a 200, or a 206 answering this request's own `bytes=0-` with the whole object. Servers from v0.20 to v0.42 answered an unranged download of a big file on a slow storage with `202 {"state":"preparing",…}`, and the old check here — anything 2xx is the file — wrote that JSON to disk under the file's name. The sync engine then saw a locally edited file and uploaded the JSON over the real one: 45 files of 70–290 MB on one deployment, unrecoverable from version history.
`bytes=0-` is the request no server version answers with 202 (a Range comes from a client already committed to a body), so the CLI never waits on a server-side copy of a file it reads exactly once anyway. Any other 2xx is still refused, and nothing of it is written.
func (*Client) DownloadSized ¶
func (c *Client) DownloadSized(ctx context.Context, remote string, w io.Writer, want int64) (int64, error)
DownloadSized is Download for a caller that knows how big the file is — the sync engine does, from the listing it planned against. want < 0 means unknown. A body of any other length is a *SizeMismatchError, which on its own would have caught the 202 above: the listing said 151,983,227 bytes and the body was 88.
func (*Client) E2EAllowed ¶ added in v0.51.0
func (c *Client) E2EAllowed(ctx context.Context, remote, kind string) (answer, reason string, err error)
E2EAllowed asks the server whether this account may start encrypting at remote, as kind: "folder" (encrypt the folder where it is), "new_folder" (make a new encrypted folder in it) or "file". answer is "allowed", "request" (an administrator's approval is needed first) or "denied"; reason names the layer that said no (tenant_disabled, policy_off, admins_only, permission, approval_required). A server older than the encryption policy has no such question (404) and answers "allowed": every write it takes is asked on its own anyway.
func (*Client) E2ECleanup ¶ added in v0.50.0
func (c *Client) E2ECleanup(ctx context.Context, remote string, versions, trash bool) (*E2ECleanupResult, error)
E2ECleanup removes what filex still holds from before a folder was encrypted: thumbnails and extracted search text always, and - when asked, by the folder's owner or an administrator - older versions and trash entries.
func (*Client) E2EEscrowKey ¶ added in v0.50.0
E2EEscrowKey is the installation's escrow PUBLIC key (base64 SPKI), as /api/capabilities publishes it to the browser, or "" when escrow is off. A folder made while it is on gets a slot sealed to it, wherever it is made.
func (*Client) EditTags ¶ added in v0.50.0
EditTags applies edit to the file's current tags and saves the result: the read-modify-write the explorer's tag picker does. Names compare without regard to case, as the server's do.
func (*Client) ExtractArchive ¶ added in v0.50.0
func (c *Client) ExtractArchive(ctx context.Context, path, dest, password string, members []string) (*Op, []byte, error)
ExtractArchive unpacks the archive at path into dest (a folder on the same storage; "" = the archive's own folder) and waits for it. members, given, extracts only those entries.
func (*Client) GetOp ¶ added in v0.50.0
GetOp reads one op (GET /api/files/ops/{id}); the answer is the op itself.
func (*Client) IsDir ¶ added in v0.50.0
IsDir reports whether remote is a folder the caller can list (the storage root always is).
func (*Client) List ¶
List returns the directory listing at remote (`adapter://rel`). An empty remote asks the server for its default view — useful only for discovering the Storages slice (adapter names).
func (*Client) Login ¶
func (c *Client) Login(ctx context.Context, in LoginRequest) (*LoginResponse, error)
Login exchanges the credentials for a session token. Call on a token-less Client.
On a multi-tenant server a sign-in whose realm names a tenant with an address of its own is not given a session at the platform's address: the answer is a one-use handoff code for the tenant's address ({"handoff": {origin, code}}). Login follows it - it redeems the code there (POST /api/auth/handoff) and returns that session, with URL set to the tenant's address.
A realm nobody has is answered by the server exactly as a wrong password, and Login reports it as the same error.
func (*Client) Mkdir ¶
Mkdir creates the folder named by the last segment of remote inside its parent (server verb: newfolder).
func (*Client) Move ¶
Move implements Unix-mv semantics. dst may be an existing folder (the item moves into it, keeping its name - a name already taken there gets a free one beside it, as in the web explorer) or the item's full new path:
- in the same folder of the same storage, a rename (the server's rename verb: a taken name is refused with 409 NAME_TAKEN, a case-only rename works);
- anywhere else - another folder, another storage, or both - one queued move that also names the item, so nothing can stop half-way between a move and a rename. A taken target is refused before anything is sent (ErrTargetExists).
A move between two storages is the server's: it streams the bytes across and removes the source once they have arrived.
func (*Client) MyShares ¶ added in v0.50.0
func (c *Client) MyShares(ctx context.Context, activeOnly bool, limit, offset int) (*SharePage, error)
MyShares lists the links the caller created. activeOnly leaves out expired and used-up ones; limit 0 is the server's page (50, at most 500).
func (*Client) NodeID ¶ added in v0.50.0
NodeID is the server's catalogue id of the file or folder at remote - what versions and tags are addressed by.
func (*Client) PluginRequests ¶ added in v0.49.0
func (c *Client) PluginRequests(ctx context.Context, status string) ([]PluginRequest, []byte, error)
PluginRequests lists the requests in one state: pending (""), approved, rejected, expired, superseded or all.
func (*Client) ReadRange ¶
ReadRange fetches [off, off+length) of a remote file.
It returns the bytes actually read, which may be fewer at the end of the object. A server that answers 200 instead of 206 gets ErrNoRange rather than having its whole-object body treated as the window that was asked for.
func (*Client) ReadSmall ¶ added in v0.50.0
ReadSmall downloads a small file whole: a key file, a name sidecar. More than max bytes is an error, not a truncation.
func (*Client) ReadWhole ¶ added in v0.54.0
ReadWhole downloads a file whole, refusing more than limit bytes (an index file: at most 64 MiB).
func (*Client) Remove ¶
Remove sends the item to the server-side trash (server verb: delete — filex soft-deletes into `.filex-trash`, restorable from the panel).
func (*Client) RequestPlugin ¶ added in v0.49.0
func (c *Client) RequestPlugin(ctx context.Context, in PluginRequestInput) (*PluginRequestAnswer, error)
RequestPlugin leaves a plugin install (or upgrade) request.
func (*Client) RestoreTrash ¶ added in v0.50.0
RestoreTrash puts one trash entry back where it was deleted from (POST /api/files/manager/restore). A path that is taken again answers 409 EXISTS and nothing moves.
func (*Client) RestoreVersion ¶ added in v0.50.0
RestoreVersion makes version versionID the file's live content (POST /api/files/versions/restore). The server records the content it replaces as a version first, so a restore can itself be undone.
func (*Client) RunAction ¶ added in v0.50.0
func (c *Client) RunAction(ctx context.Context, plugin, action string, paths []string, params map[string]any) (*Op, []byte, error)
RunAction runs an app's action on paths (`adapter://path`, one storage) with params and waits for its job (POST /api/files/plugins/actions/{plugin}/{action}/run). The final op carries the files the action wrote (Op.Outputs).
params nil sends none: an action that asks for input in a form then answers ErrActionNeedsInput, and its fields are given as params.
func (*Client) Search ¶
func (c *Client) Search(ctx context.Context, query, scope string, storageID int64, limit int) (*SearchResult, error)
Search queries the server-side index. scope is "name", "content" or "all" ("" = server default, all). storageID 0 searches every storage.
func (*Client) SearchFiltered ¶ added in v0.54.0
func (c *Client) SearchFiltered(ctx context.Context, query, scope string, storageID int64, limit int, filters url.Values) (*SearchResult, error)
SearchFiltered is Search with the server's narrowing (type, mime, modified_after, modified_before, min_size, max_size, under, not_under, owner, hidden - docs/SEARCH.md), applied on the server before the limit.
func (*Client) SetTags ¶ added in v0.50.0
SetTags makes the tags the caller can see on the file exactly items (POST /api/files/manager/tags with `items`). Tags the caller cannot see - another person's personal ones - are never touched.
func (*Client) Share ¶
func (c *Client) Share(ctx context.Context, remote string, pin bool, expiresDays int) (*ShareResult, error)
Share mints a public download link for remote. pin=true asks the server to generate an unlock PIN (returned once, in PIN); expiresDays > 0 sets the expiry that many days from now.
func (*Client) SizeOf ¶
SizeOf reads an object's length from a HEAD-shaped request.
It uses a one-byte ranged GET rather than HEAD: the manager endpoint answers HEAD, but a Content-Range header is the only place the TOTAL size appears in a partial response, and this is the same request the read path makes.
func (*Client) Space ¶ added in v0.60.0
Space asks how much room remote has (GET /api/files/manager?action=space); "" asks for the storage list, the storages added up. A server older than the question answers 501, an *APIError like any other refusal.
func (*Client) StatPath ¶
StatPath returns metadata for one path.
⚠ It answers from the PARENT's listing rather than a per-file endpoint, because the manager API has no stat verb: `action=index` on a file 404s. The listing is what the server already computes, so this costs one request and stays correct when a driver reports a size the database has not caught up with.
func (*Client) TaggedFiles ¶ added in v0.50.0
func (c *Client) TaggedFiles(ctx context.Context, tag, kind string, limit int) ([]TaggedFile, []byte, error)
TaggedFiles lists the files carrying tag, newest first (GET /api/files/manager/tagged). kind "" is both kinds.
func (*Client) TagsOf ¶ added in v0.50.0
TagsOf reads the tags on one file (GET /api/files/manager/tags?node_id=).
func (*Client) Trash ¶ added in v0.50.0
Trash lists what the caller may see in the trash, newest first. storageID 0 is every storage; limit 0 is the server's default page (50, at most 500).
func (*Client) TrashSame ¶ added in v0.60.0
func (c *Client) TrashSame(ctx context.Context, items []TrashSameItem) ([]TrashSameAnswer, error)
TrashSame asks whether entries of the caller's trash hold exactly the bytes of a file the caller has (POST /api/files/manager/trash/same, task #259): the sync's discard deletes a held file only when the server still holds a copy. An entry the caller's trash listing does not show answers "not the same". At most TrashSameMax items.
func (*Client) UILocale ¶ added in v0.54.0
UILocale is the strings one language pack adds for code (GET /api/public/ui-locales/{code}): the interface's keys and the server's own `server.*` sentences, merged over every running pack. nil, nil when no running pack carries the language (404).
func (*Client) Unshare ¶ added in v0.50.0
Unshare revokes the link with id: its URL stops working at once.
func (*Client) Upload ¶
Upload streams localPath to the server. remote may be a destination folder (`docs://reports/` — trailing slash or an existing dir) or a full target path (`docs://reports/renamed.pdf`); an existing remote folder wins, otherwise the last segment becomes the uploaded filename. Nothing is ever buffered in memory, and a large file is resumable — see uploadFile.
func (*Client) UploadTo ¶
func (c *Client) UploadTo(ctx context.Context, localPath string, destDir RemotePath, name, expect string) ([]byte, error)
UploadTo sends localPath to destDir/name with no destination probing and an optional overwrite precondition — the call `filex sync` makes.
expect is "" (no precondition), "none" (the target must not exist yet) or "<size>:<last_modified-ms>" (the target must still be exactly what a listing reported). A refusal comes back as ErrPreconditionFailed. An older server ignores the field and writes unconditionally — no worse than before.
⚠ No remoteIsDir probe, unlike Upload: the caller already knows the target is a file path, and the probe is a full listing round-trip in front of every file — on a server behind a CDN proxy (~0.35 s per request, measured) that was a third of the time a one-line edit took to leave the machine.
func (*Client) UploadTree ¶
func (c *Client) UploadTree(ctx context.Context, localDir, remote string, progress TreeProgress) (*TreeReport, error)
UploadTree uploads localDir recursively into remote. Empty local folders are created remotely too. Per-item failures accumulate in the report (a failed mkdir skips its subtree); only pre-flight problems (bad remote path, unreadable root) and context cancellation return a non-nil error. A plain file with -r degrades to a single upload, matching `cp -r` behavior.
func (*Client) VaultBreak ¶ added in v0.54.0
VaultBreak ends someone else's lock (the folder's owner, an administrator).
func (*Client) VaultDelete ¶ added in v0.54.0
func (c *Client) VaultDelete(ctx context.Context, remote, token string, packs []string, indexes []uint64) (int, int, error)
VaultDelete deletes packs (hex ids) and index files (generations) for good. At most 1 000 names per call; a missing one counts as deleted.
func (*Client) VaultIdleMinutes ¶ added in v0.54.0
VaultIdleMinutes is the person's idle time before a write lock ends.
func (*Client) VaultList ¶ added in v0.54.0
func (c *Client) VaultList(ctx context.Context, remote, kind, after string, limit int) ([]VaultListItem, string, error)
VaultList is one page of GET /list; kind is "index" or "pack". next is the cursor of the following page, "" at the end.
func (*Client) VaultListAll ¶ added in v0.54.0
VaultListAll pages through GET /list.
func (*Client) VaultLock ¶ added in v0.54.0
VaultLock takes the write lock. client is "cli" or "mount"; label is a short free text naming this machine. A lock someone else holds is a *VaultError VAULT_LOCKED with the holder.
func (*Client) VaultPutIndex ¶ added in v0.54.0
func (c *Client) VaultPutIndex(ctx context.Context, remote, token string, gen uint64, file []byte) (uint64, error)
VaultPutIndex commits the index file of generation gen (latest + 1, or VAULT_GENERATION with the latest).
func (*Client) VaultPutPack ¶ added in v0.54.0
VaultPutPack stores a pack (created, never replaced: VAULT_PACK_EXISTS). id is 32 lower-case hex digits.
func (*Client) VaultRelease ¶ added in v0.54.0
VaultRelease gives the lock back (whether or not the token still held it).
func (*Client) VaultRenew ¶ added in v0.54.0
func (c *Client) VaultRenew(ctx context.Context, remote, token string, active bool) (*VaultRenewal, error)
VaultRenew is the heartbeat; active says this session is about to write. A lock that ended is a *VaultError VAULT_LOCK_LOST with its reason.
func (*Client) VaultState ¶ added in v0.54.0
VaultState asks for a vault's id, pack size, latest generation and lock.
func (*Client) Versions ¶ added in v0.50.0
Versions lists the recorded versions of the file with catalogue id nodeID (NodeID resolves a path).
func (*Client) WaitOp ¶ added in v0.50.0
WaitOp follows an op until it is finished and returns its final row. An op that did not end `ok` is an *OpError (the row is returned as well). A cancelled ctx stops the waiting, not the op: the server goes on with it.
func (*Client) WriteSmall ¶ added in v0.50.0
func (c *Client) WriteSmall(ctx context.Context, destDir RemotePath, name string, data []byte, expect string) error
WriteSmall uploads data as destDir/name (a key file, a name sidecar), with the overwrite precondition expect ("" none, "none" must not exist).
type Conn ¶
type Conn struct {
URL string
Token string
// Realm is the realm saved with URL in the config file ("" when the
// resolved URL is another server's, or none was saved).
Realm string
// SavedURL is set when the config file holds a session that was NOT used
// because it belongs to another address (this one): the caller says so
// instead of a bare "no token".
SavedURL string
// InsecureSkipTLSVerify: this connection does not check the server's
// certificate (FileConfig.InsecureSkipTLSVerify).
InsecureSkipTLSVerify bool
}
Conn is the resolved server coordinate a client command runs against.
func Resolve ¶
Resolve merges connection settings by precedence:
--url/--token flags > FILEX_URL/FILEX_TOKEN env > config file.
⚠ What the config file holds belongs to the address it was saved with - the session token above all: a --url or FILEX_URL that names another address gets neither the saved token nor the saved realm (sameServer). Sending it there would hand one server's session to another. A token given on purpose (--token, FILEX_TOKEN) goes to whichever address it is given with.
⚠ The same holds for the certificate switch: what one address was allowed says nothing about another, so a --url to a second server checks its certificate unless this run says otherwise (EnvInsecureSkipTLSVerify, or the flag, which the caller applies over this).
getenv is injected so tests don't have to mutate the process env.
type E2ECleanupResult ¶ added in v0.50.0
type E2ECleanupResult struct {
VersionsDeleted int `json:"versions_deleted"`
TrashPurged int `json:"trash_purged"`
ThumbnailsDropped int `json:"thumbnails_dropped"`
IndexCleared int `json:"index_cleared"`
}
E2ECleanupResult is what POST /api/files/e2e/cleanup removed.
type FileConfig ¶
type FileConfig struct {
URL string `yaml:"url"`
Token string `yaml:"token"`
// Realm is the tenant realm the session was signed in to, on a
// multi-tenant server; it belongs to URL and is used again only by a
// login at that address (Resolve). Omitted when empty, so a file without
// one reads the same to an older CLI.
Realm string `yaml:"realm,omitempty"`
// InsecureSkipTLSVerify reaches URL without checking its certificate: a
// filex server with a self-signed or private one. Like the token it belongs
// to URL and goes nowhere else (Resolve). Omitted when off, so a file
// without it reads the same to an older CLI.
InsecureSkipTLSVerify bool `yaml:"insecure_skip_tls_verify,omitempty"`
}
FileConfig is the on-disk shape of ~/.filex/cli.yaml. It carries a bearer token, so SaveFileConfig always writes it owner-only (0600).
func LoadFileConfig ¶
func LoadFileConfig(path string) (FileConfig, error)
LoadFileConfig reads the CLI config. A missing file is not an error — it just yields the zero config so flags/env can still win.
type FileTags ¶ added in v0.50.0
type FileTags struct {
NodeID int64 `json:"node_id"`
Items []TagItem `json:"items"`
CanEditTeam bool `json:"can_edit_team"`
Raw []byte `json:"-"`
}
FileTags is a file's tags as the caller can see them.
type ListEntry ¶
type ListEntry struct {
// ID is the server's catalogue id (versions and tags are addressed by it);
// 0 when the folder was listed straight from the storage, before a scan
// catalogued it.
ID int64 `json:"id,omitempty"`
Path string `json:"path"`
Basename string `json:"basename"`
Type string `json:"type"` // "file" | "dir"
Extension string `json:"extension"`
Size int64 `json:"size"`
MimeType string `json:"mime_type"`
LastModified int64 `json:"last_modified"` // Unix millis; 0 = unknown
// E2E is true on a folder that is an end-to-end encrypted folder (it
// holds a key file).
E2E bool `json:"e2e,omitempty"`
}
ListEntry is one row of a directory listing (server FileNode shape).
type ListResult ¶
type ListResult struct {
Adapter string `json:"adapter"`
Storages []string `json:"storages"`
Dirname string `json:"dirname"`
ReadOnly bool `json:"read_only"`
Files []ListEntry `json:"files"`
// E2ERoot is the encrypted folder the listed folder is in, or at the
// root of (adapter://rel); "" when it is in none.
E2ERoot string `json:"e2e_root,omitempty"`
Raw []byte `json:"-"`
}
ListResult is GET /api/files/manager?action=index.
type LoginRequest ¶ added in v0.50.0
type LoginRequest struct {
// Email is what the person signs in with: an e-mail address, or a user
// name (the server resolves both).
Email string
Password string
// TOTP is the second-factor code, for accounts with TOTP enabled.
TOTP string
// Realm names the tenant on a multi-tenant server (docs/MULTI-TENANCY.md,
// Realms): "" is the tenant the server's address names, else the
// platform's own accounts. Sent only when set; a single-tenant server - or
// an older one - does not read it.
Realm string
}
LoginRequest is what a password sign-in sends to POST /api/auth/login.
type LoginResponse ¶
type LoginResponse struct {
Token string `json:"token"`
// URL is the address the session belongs to: the server signed in to, or -
// when that server handed the sign-in to the tenant's own address - that
// address, which later commands should use.
URL string `json:"-"`
// HandedOff reports that the server answered with a handoff and the session
// was opened at URL, the tenant's own address.
HandedOff bool `json:"-"`
Raw []byte `json:"-"`
}
LoginResponse is the subset of the sign-in answer the CLI needs.
type MyShare ¶ added in v0.50.0
type MyShare struct {
ID int64 `json:"id"`
Token string `json:"token"`
Kind string `json:"kind"` // download | drop
HasPin bool `json:"has_pin"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
MaxDownloads *int `json:"max_downloads,omitempty"`
DownloadCount int `json:"download_count"`
CreatedAt time.Time `json:"created_at"`
} `json:"share"`
}
MyShare is one link the caller created.
type Op ¶ added in v0.50.0
type Op struct {
ID int64 `json:"id"`
Kind string `json:"kind"`
Status string `json:"status"` // pending | running | ok | failed | partial | cancelling | cancelled
Total int `json:"total"`
Done int `json:"done"`
Failed int `json:"failed"`
Error string `json:"error,omitempty"`
Message string `json:"message,omitempty"`
Outputs []OpOutput `json:"outputs,omitempty"`
// ErrorCode / ErrorText are the server's code for a failure and its
// sentence in the reader's language (internal/apierr): the CLI prints the
// sentence; Error is the English detail.
ErrorCode string `json:"error_code,omitempty"`
ErrorText string `json:"error_text,omitempty"`
}
Op is one job of the operations queue, the fields the CLI reads.
type OpError ¶ added in v0.50.0
type OpError struct {
Op *Op
}
OpError is an op that ended any other way than `ok`: failed, partly done or cancelled. Op carries the final row.
type OpOutput ¶ added in v0.50.0
type OpOutput struct {
Path string `json:"path"`
}
OpOutput is a file an app's action wrote (`adapter://path` or a storage-relative path, as the server reports it).
type PluginRequest ¶ added in v0.49.0
type PluginRequest struct {
ID int64 `json:"id"`
Kind string `json:"kind"`
Op string `json:"op"`
Name string `json:"name"`
Version string `json:"version"`
FromVersion string `json:"from_version"`
SHA256 string `json:"sha256"`
Permissions []string `json:"permissions"`
Requester string `json:"requester"`
TokenLabel string `json:"token_label"`
Reason string `json:"reason"`
Status string `json:"status"`
DecisionNote string `json:"decision_note"`
ExpiresAt time.Time `json:"expires_at"`
CreatedAt time.Time `json:"created_at"`
}
PluginRequest is one request as the server answers it.
type PluginRequestAnswer ¶ added in v0.49.0
type PluginRequestAnswer struct {
Request PluginRequest `json:"request"`
Created bool `json:"created"`
Message string `json:"message"`
Raw []byte `json:"-"`
}
PluginRequestAnswer is POST /api/admin/plugin-requests' answer. Created is false when a request for the same source was already waiting (that one is answered).
type PluginRequestInput ¶ added in v0.49.0
type PluginRequestInput struct {
Kind string `json:"kind"`
Op string `json:"op,omitempty"`
Name string `json:"name,omitempty"`
PluginID int64 `json:"plugin_id,omitempty"`
GitHubRepo string `json:"github_repo,omitempty"`
Ref string `json:"ref,omitempty"`
ManifestURL string `json:"manifest_url,omitempty"`
URL string `json:"url,omitempty"`
SHA256 string `json:"sha256,omitempty"`
Source string `json:"source,omitempty"`
Reason string `json:"reason"`
}
PluginRequestInput is a request to leave: the plugin's kind (app | storage), the operation (install | upgrade), where it comes from and why.
type RateLimiter ¶
type RateLimiter struct {
// contains filtered or unexported fields
}
RateLimiter caps a direction of traffic at a number of bytes per second.
One limiter is shared by every transfer of that direction, so the four parallel transfers of a sync run TOGETHER stay under the limit — which is the point: a nine-hour first sync saturated a server's ~18 Mbit line and everyone else using that server slowed down, and `--transfers` only changes how many files move at once, not how fast.
It paces the bodies, never the connection: HTTP/2 health pings and window updates share the connection, and a throttled connection would delay them past the client's own dead-connection timeout.
A token bucket holding one second's worth of bytes; a stream that runs ahead goes into debt and sleeps it off, so concurrent streams share the rate fairly. A nil *RateLimiter never waits.
func NewRateLimiter ¶
func NewRateLimiter(bytesPerSecond int64) *RateLimiter
NewRateLimiter returns a limiter for bytesPerSecond, or nil (no limit) for zero or less.
type RemotePath ¶
RemotePath is a parsed `adapter://relative/path` reference. Adapter is the storage name on the server; Rel is the slash-separated relative path inside it ("" = storage root).
func ParseRemotePath ¶
func ParseRemotePath(raw string) (RemotePath, error)
ParseRemotePath validates and splits an `adapter://rel/path` argument. The adapter prefix is mandatory — a bare relative path is ambiguous when the server hosts several storages. `..` segments are rejected before they ever reach the wire.
func (RemotePath) Base ¶
func (p RemotePath) Base() string
Base returns the last path segment ("" at the storage root).
func (RemotePath) Dir ¶
func (p RemotePath) Dir() RemotePath
Dir returns the parent directory (the storage root stays the root).
func (RemotePath) IsRoot ¶
func (p RemotePath) IsRoot() bool
IsRoot reports whether the path points at the storage root.
func (RemotePath) Join ¶
func (p RemotePath) Join(name string) RemotePath
Join appends one segment to the path.
func (RemotePath) String ¶
func (p RemotePath) String() string
String renders the wire form `adapter://rel` (root: `adapter://`).
type SearchHit ¶
type SearchHit struct {
ID int64 `json:"id"`
StorageID int64 `json:"storage_id"`
Name string `json:"name"`
Path string `json:"path"`
Type string `json:"type"`
Size int64 `json:"size"`
Snippet string `json:"snippet"`
Matched string `json:"matched"` // "name" | "content" | "both"
}
SearchHit is one result row from /api/files/search (node fields plus the v0.2 content-search additions).
type SearchResult ¶
type SearchResult struct {
Results []SearchHit `json:"results"`
// Truncated: more matched than came back. Total is how many matched,
// exact unless Truncated (then a lower bound).
Truncated bool `json:"truncated"`
Total int `json:"total"`
Raw []byte `json:"-"`
}
SearchResult is the /api/files/search envelope.
type SharePage ¶ added in v0.50.0
type SharePage struct {
}
SharePage is one page of the caller's links, newest first.
type ShareResult ¶
type ShareResult struct {
}
ShareResult is the nested `share` object of POST /api/files/share.
type SizeMismatchError ¶
type SizeMismatchError struct {
Remote string
Want int64 // what the listing said
Got int64 // what the server declared or sent
}
SizeMismatchError is a download whose body is not the length the caller's listing reported. When the server DECLARES the other length up front (Content-Length, or the total of a Content-Range) not one byte reaches the writer; a body that only turns out short or long at its end has reached it, and the caller — which writes to a temporary file — throws it away.
func (*SizeMismatchError) Error ¶
func (e *SizeMismatchError) Error() string
type Space ¶ added in v0.60.0
type Space struct {
Total uint64 `json:"total"`
Used uint64 `json:"used"`
Free uint64 `json:"free"`
// Known is false when the server could measure nothing there and the
// account has no quota.
Known bool `json:"known"`
}
Space is the room at a remote path, in bytes: the server's internal/space figures, the ones `df` shows over SFTP, NFS and /dav too.
type StreamState ¶
type StreamState string
StreamState is what the stream can honestly say about itself.
const ( // StreamLive: subscribed; changes arrive as they happen. StreamLive StreamState = "connected" // StreamPolling: the server cannot announce changes (older than the // `watch` subscription, or realtime is switched off). Only the interval // poll finds them. StreamPolling StreamState = "polling" // StreamOffline: the server could not be reached; retrying with backoff. StreamOffline StreamState = "offline" )
type TagEdit ¶ added in v0.50.0
type TagEdit struct {
Add []string
Remove []string
// Kind is the kind an added name gets: TagPersonal (default) or TagTeam.
// A removal with Kind set removes only that kind; "" removes the name in
// either kind.
Kind string
}
TagEdit is one change to a file's tags: names to add (with the kind a new one gets) and names to remove.
type TaggedFile ¶ added in v0.50.0
type TaggedFile struct {
ID int64 `json:"id"`
Storage string `json:"storage"`
Path string `json:"path"`
Name string `json:"name"`
Type string `json:"type"`
Size int64 `json:"size"`
}
TaggedFile is one file carrying a tag.
func (TaggedFile) Location ¶ added in v0.50.0
func (f TaggedFile) Location() string
Location is the file's `adapter://path`.
type Transfer ¶ added in v0.50.0
type Transfer struct {
// Into is true when the target was a folder the item went into under its
// own name. A name already taken there makes the server pick a free one
// beside it (`a-copy.txt`), so To is then where the item WOULD be.
Into bool
// Folder is the folder the item went into.
Folder RemotePath
// To is the item's path: the full path the target named, or Folder joined
// with the item's own name.
To RemotePath
// Op is the queued operation's final row; nil for a rename in place.
Op *Op
// Raw is the server's last answer (the op's final row).
Raw []byte
}
Transfer is what one copy or move did.
type TrashEntry ¶ added in v0.50.0
type TrashEntry struct {
ID int64 `json:"id"`
StorageID int64 `json:"storage_id"`
StorageName string `json:"storage_name,omitempty"`
Path string `json:"path"`
Name string `json:"name"`
Size int64 `json:"size"`
DeletedAt time.Time `json:"deleted_at"`
DeletedByName string `json:"deleted_by_name,omitempty"`
DeletedBySelf bool `json:"deleted_by_self,omitempty"`
Draft bool `json:"draft,omitempty"`
// E2eRoot is the end-to-end encrypted folder the item was deleted from;
// its name may then be ciphertext.
E2eRoot string `json:"e2e_root,omitempty"`
}
TrashEntry is one item in the trash (GET /api/files/manager/trash). ID is the id a restore names.
func (TrashEntry) Location ¶ added in v0.50.0
func (e TrashEntry) Location() string
Location is the entry's original place as `adapter://path`.
type TrashPage ¶ added in v0.50.0
type TrashPage struct {
Entries []TrashEntry `json:"entries"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
Raw []byte `json:"-"`
}
TrashPage is one page of the caller's trash.
type TrashSameAnswer ¶ added in v0.60.0
type TrashSameAnswer struct {
ID int64 `json:"id"`
Same bool `json:"same"`
Checked bool `json:"checked"`
}
TrashSameAnswer is the server's answer about one entry. Checked false: the server did not read it (its budget for the request was spent, or the storage could not be read), and Same is not known.
type TrashSameItem ¶ added in v0.60.0
TrashSameItem asks whether trash entry ID holds exactly the bytes whose sha256 (lower-case hex) is SHA256.
type TreeChange ¶
TreeChange is one `tree_change` frame: something changed at or below Root. Dirs are relative to Root ("" = Root itself). Overflow means too many folders changed to name them — treat the whole root as changed.
type TreeEvent ¶
type TreeEvent struct {
Kind string // TreeDir | TreeFile | TreeSymlink | TreeSpecial | TreeErr
Local string // local path of the item
Remote RemotePath // resolved remote target (zero for symlink/local errors)
Err error // set when Kind == TreeErr
}
TreeEvent is one progress notification from UploadTree.
type TreeProgress ¶
type TreeProgress func(ev TreeEvent)
TreeProgress receives one call per processed item during UploadTree — the CLI streams these as they happen. May be nil.
type TreeReport ¶
type TreeReport struct {
Files int // files uploaded successfully
Dirs int // remote directories ensured (created or pre-existing)
Symlinks []string // local symlinks skipped (never followed)
Special []string // local named pipes, sockets and devices skipped (never opened)
Errors []TreeError // items that failed (upload, mkdir, walk)
}
TreeReport summarizes a finished UploadTree run. Errors are per-item: the walk keeps going past a failed file, and a failed mkdir skips just that subtree.
type VaultError ¶ added in v0.54.0
type VaultError struct {
Status int
Code string
Message string
// Holder, Since and RetryAfter come with VAULT_LOCKED.
Holder *VaultHolder
Since time.Time
RetryAfter int
// Reason comes with VAULT_LOCK_LOST: expired, idle, broken, released, taken.
Reason string
// Latest comes with VAULT_GENERATION.
Latest uint64
}
VaultError is an error answer of the vault API.
func (*VaultError) Error ¶ added in v0.54.0
func (e *VaultError) Error() string
type VaultHolder ¶ added in v0.54.0
type VaultHolder struct {
Name string `json:"name"`
Client string `json:"client"`
Label string `json:"label"`
}
VaultHolder is who holds a vault's write lock.
func (VaultHolder) String ¶ added in v0.54.0
func (h VaultHolder) String() string
String is "Ayşe (web, Firefox, ofis)".
type VaultListItem ¶ added in v0.54.0
type VaultListItem struct {
Generation uint64 `json:"generation"`
ID string `json:"id"`
Size int64 `json:"size"`
MTime VaultTime `json:"mtime"`
}
VaultListItem is one row of GET /list: an index file (Generation) or a pack (ID, 32 lower-case hex digits).
type VaultLock ¶ added in v0.54.0
type VaultLock struct {
Token string `json:"token"`
Generation uint64 `json:"generation"`
LeaseSeconds int `json:"lease_seconds"`
IdleSeconds int `json:"idle_seconds"`
ExpiresAt VaultTime `json:"expires_at"`
}
VaultLock is a taken write lock.
type VaultLockInfo ¶ added in v0.54.0
type VaultLockInfo struct {
Holder VaultHolder `json:"holder"`
Since VaultTime `json:"since"`
ExpiresAt VaultTime `json:"expires_at"`
Mine bool `json:"mine"`
}
VaultLockInfo is `state`'s lock.
type VaultRenewal ¶ added in v0.54.0
type VaultRenewal struct {
ExpiresAt VaultTime `json:"expires_at"`
IdleUntil VaultTime `json:"idle_until"`
}
VaultRenewal is POST /lock/renew.
type VaultState ¶ added in v0.54.0
type VaultState struct {
VaultID string `json:"vault_id"`
PackLog2 int `json:"pack_log2"`
Generation uint64 `json:"generation"`
Lock *VaultLockInfo `json:"lock"`
}
VaultState is GET /state.
type VaultTime ¶ added in v0.54.0
VaultTime is a time the vault API sends: RFC 3339, or milliseconds since 1970 as a number; null is the zero time.
func (*VaultTime) UnmarshalJSON ¶ added in v0.54.0
UnmarshalJSON reads either form.
type Version ¶ added in v0.50.0
type Version struct {
ID int64 `json:"id"`
NodeID int64 `json:"node_id"`
VersionN int `json:"version_n"`
Size int64 `json:"size"`
CreatedAt time.Time `json:"created_at"`
}
Version is one recorded version of a file (GET /api/files/versions).
type VersionList ¶ added in v0.50.0
type VersionList struct {
NodeID int64 `json:"node_id"`
Versions []Version `json:"versions"`
Raw []byte `json:"-"`
}
VersionList is a file's version timeline.