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 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) 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) 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 Stat
- type StreamState
- type TagEdit
- type TagItem
- type TaggedFile
- type Transfer
- type TrashEntry
- type TrashPage
- 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 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 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
}
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) 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) 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
}
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.
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"`
}
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 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 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.