filesync
Keeping every user's shared files in the object store.
A session mounts its user's shared files at Desktop/files. With more than
one node, the store holds the copy every node works from. A session starts
without waiting for the files: the node's copy catches up in the background
as the session comes up (pull_later), and a launch that opens one file of
the directory fetches that file alone first (pull_file). What a session
changed is sent when it stops and every few minutes while it runs (sync).
Files are written whole and moved into place, so a running session never
sees a half-written one, and never through a symbolic link: a user's link
in the directory, which a session can make, is not followed (_place).
Each file is the object files/<user>/<path>, encrypted under the user's
key when the cluster has one (filecrypt). A node remembers the entity
tag, size, and time of every file as of its last sync, which tells a file
changed here from one changed elsewhere. The last writer wins; when both
sides changed a file, this node's version is kept beside the store's under a
.conflict-<node> name. Files larger than MAX_BYTES stay on their node,
and a file this node cannot decrypt is left as it is on both sides.
attributelogger= logging.getLogger(__name__)attributeMAX_BYTES= 512 * 1024 * 1024funcenabled() -> boolWhether shared files are synced: files_sync on, or auto with a second node in the cluster.
Returns
boolfunc_manifest_path(username) -> strReturn where this node remembers a user's last sync.
paramusernamestrReturns
strfunc_local_files(root) -> dict[str, tuple[int, int]]Return the size and modification time of every regular file under root by relative path.
paramrootstrReturns
dict[str, tuple[int, int]]func_place(root, name) -> str | NoneReturn where the shared file name goes under root, or None when the path leaves the directory or crosses a link.
The directory is a session's to write, so a link in it may point anywhere; a file is placed only where every directory on its way is a real one under the root, and never over a link.
paramrootstrparamnamestrReturns
str | Nonefunc_write(target, data, tag) -> dict[str, Any]Write a file whole beside its place and move it there, and return its manifest entry.
paramtargetstrparamdatabytesparamtagstrReturns
dict[str, typing.Any]func_pull_file(username, root, name) -> boolFetch one of a user's shared files from the store unless this node's copy is current; return whether it is here.
paramusernamestrparamrootstrparamnamestrReturns
boolfunc_sync(username, root, send) -> NoneBring root and the store's copy of a user's shared files together.
paramusernamestrOwner of the files.
paramrootstrThe user's shared files directory on this node.
paramsendboolAlso send what changed here; a pull before a launch sends nothing.
Returns
Nonefunc_run(username, root, send) -> NoneSync in a thread and log, rather than raise, what goes wrong.
paramusernamestrparamrootstrparamsendboolReturns
Nonefuncpull(username, root) -> NoneBring a user's shared files on this node up to date, taking what the store has and sending nothing.
paramusernamestrparamrootstrReturns
Nonefuncpull_later(username, root) -> NoneBring a user's shared files up to date in the background, as a session starts over them.
paramusernamestrparamrootstrReturns
Nonefuncpull_file(username, root, name) -> boolFetch the one shared file a launch opens, and say whether it is on this node.
paramusernamestrOwner of the files.
paramrootstrThe user's shared files directory on this node.
paramnamestrThe file's path under the directory.
Returns
boolfuncforget(username) -> NoneRemove a deleted user's shared files from the store, and the key they were encrypted under.
paramusernamestrReturns
Nonefuncsync(username, root) -> NoneSend what changed in a user's shared files here and take what changed elsewhere.
paramusernamestrparamrootstrReturns
Nonefuncpush_later(username, root) -> NoneSync a user's shared files in the background, as when a session stops.
paramusernamestrparamrootstrReturns
None