Theme
Events and when they fire Preview
The Connector defines eighteen events. They are not the Syncplify Server events. Syncplify Server scripts run inside a protocol session and can see connections, authentication attempts, shares and SITE commands; the Connector sits below all of that and sees only file system operations arriving over the tunnel, so its events are file system events and nothing else.
The Connector is not where a login happens
There is no OnAuthPassword here, and there cannot be. Authentication happens on the Head, in the cloud, before the Connector is ever asked to do anything. See How the pieces fit together. If you need to react to a sign in, that is a Portal concern, not a script.
The catalog
The name column is what the console shows you. The id is what EventHandler() returns and what appears in the log.
| Name in the console | id | Fires |
|---|---|---|
| Before a file is uploaded | before.upload | A file is opened for writing |
| After a file is uploaded | after.upload | That file is closed |
| Before a file is downloaded | before.download | A file is opened for reading |
| After a file is downloaded | after.download | That file is closed |
| Before a file is deleted | before.delete | |
| After a file is deleted | after.delete | |
| Before a folder is deleted | before.deleteDir | Covers both removing an empty folder and removing a tree |
| After a folder is deleted | after.deleteDir | |
| Before a rename or move | before.rename | |
| After a rename or move | after.rename | |
| Before a folder is created | before.makeDir | Covers creating one folder and creating a whole branch |
| After a folder is created | after.makeDir | |
| Before a folder is listed | before.listDir | |
| After a folder is listed | after.listDir | |
| Before a transfer to another storage | before.transfer | This Connector is about to copy or move a file into another of its own virtual file systems on the Head's behalf: a cross storage copy or move in the web client, or a server side SFTP copy |
| After a transfer to another storage | after.transfer | That transfer finished and was verified |
| Filter a folder listing | dirList.filter | Between reading a listing and sending it |
| When a tunnel disconnects | session.disconnect | A link to a Head dropped |
What context each event carries
Every handler can read the context through the Ctx* functions and the Session object. What is populated depends on the event.
| Event | CtxRelPath() | CtxRelTargetPath() | CtxVFSName(), CtxUsername() | GetCurrentVFS() |
|---|---|---|---|---|
before.upload, before.download | The file | empty | set | live VFS |
after.upload, after.download | The file, as it was named at open | empty | set | live VFS |
before.delete, after.delete | The file | empty | set | live VFS |
before.deleteDir, after.deleteDir | The folder | empty | set | live VFS |
before.rename, after.rename | The source path | The destination path | set | live VFS |
before.makeDir, after.makeDir | The folder | empty | set | live VFS |
before.listDir, after.listDir | The folder | empty | set | live VFS |
before.transfer, after.transfer | The source file | The destination path, in the other virtual file system | set, plus CtxTargetVFSName() | live source VFS |
dirList.filter | The folder | empty | set | live VFS |
session.disconnect | empty | empty | empty | null |
session.disconnect carries no context at all
It tells you a tunnel dropped, and nothing else. There is no path, no username, no virtual file system name and no VFS object; GetCurrentVFS() returns null. It follows that a handler scoped to one virtual file system never fires on this event, because there is no VFS name to match against. Only handlers scoped to Everything see it. Use it for cleanup that needs no context, and nothing more.
Upload and download complete at close
The after upload and download events fire when the file closes, not when it opens, because only then is the content complete. A script bound to after.upload can read the finished file; one bound to before.upload cannot, because there is nothing there yet.
Two consequences worth knowing:
- If the tunnel drops mid transfer, the handle is discarded and
after.uploadnever fires. An after handler is not a guarantee that something arrived; it is a report that something finished. - A file opened for reading and then closed without a single byte being read still produces
before.downloadandafter.download. The events describe handles, not bytes.
Before is a gate, after is a witness
A before handler runs synchronously, in front of the operation, and its result decides whether the operation happens at all. Refuse by exiting non zero, or by throwing:
js
if (CtxRelPath().indexOf("/quarantine/") === 0) {
Log.Warn("refused write into quarantine: " + CtxRelPath());
Exit(1);
}An after handler runs when the operation has already committed. Nothing it does can undo it. Its errors are logged and never reach the user.
Permissions are checked before your script, not after
The Connector authorizes every operation against the user's permissionsfirst, and only then calls the before handler. A script never sees an operation the user was not already entitled to perform. Scripts add policy on top of permissions; they do not replace them, and you cannot use one to grant access that permissions deny.
Ordering when several handlers share an event
Handlers on the same event run in ascending priority: 10 before 20. On a before event the first handler that refuses stops the chain, and later handlers do not run. HandlerPriority() tells a script the priority it was invoked at, which is occasionally useful when one script is bound several times.
The full order of a folder listing
The listing seams are the only place where more than one event touches a single operation, so the order is worth stating exactly:
before.listDirruns and may refuse the whole listing.- The Connector reads the folder from the virtual file system.
dirList.filterruns and collects patterns to hide.- The filtered listing is sent to the user.
after.listDirruns.
Filtering a listing
Inside a dirList.filter handler, every call to Session.RemoveFromDirList() adds one pattern. Patterns from all matching handlers are collected together, then applied in one pass.
js
Session.RemoveFromDirList("*.tmp");
Session.RemoveFromDirList("*.part");
Session.RemoveFromDirList(".DS_Store");
Session.RemoveFromDirList("[Tt]humbs.db");| Detail | Behavior |
|---|---|
| Matched against | The entry's name only, never the full path |
| Syntax | *, ? and [range]. There is no **, and * matches any character including a dot |
| Case | Sensitive. *.TMP does not hide notes.tmp |
| Bad pattern | Silently skipped, the rest still apply |
| Script fails or times out | The listing ships with whatever patterns had accumulated. A failing filter never blocks a listing |
| Run in the background | Ignored here. A filter handler is always synchronous, because the answer is needed before the listing is sent |
A listing filter is a display filter, not a permission
Hiding a name removes it from what the user is shown. It does not stop them opening it. A user who knows the exact name, and holds permission on it, still gets the file. If something must be unreachable, do not grant it: see Permissions.
Scope
A handler is bound either to Everything or to one virtual file system.
Start scoped. A handler bound to Everything runs on every operation performed by every user on that machine, including the ones you were not thinking about when you wrote it, and including whatever new virtual file system somebody adds next month.
Remember that session.disconnect has no VFS name, so a scoped handler never sees it.
Related
- Event handlers is the console page: the fields, the fail modes, the buttons.
- The event context is what your code reads once an event fires.
Transfers to another storage
before.transfer and after.transfer fire when the Head asks this Connector to copy or move a file between two of its own virtual file systems: a cross storage copy or move in the web client, a drag between two mounts, or a server side copy from an SFTP client. They fire on the source virtual file system's handlers. CtxRelPath() is the source file, CtxRelTargetPath() is where it lands, and CtxTargetVFSName() names the virtual file system it lands in; GetCurrentVFS() is the source.
A before handler may refuse the transfer exactly like any other before event. The after event fires once the destination has been written and verified, so a handler can act on the finished copy through GetVFSByName(CtxTargetVFSName()).
Two things do not fire these events:
- A transfer a script runs itself with
CopyToVFSorMoveToVFS. Those bypass the tunnel, so a handler can never trigger itself by moving a file. - A transfer relayed through the Head between two different Connectors. Each side of that sees an ordinary download or upload, and gets those events instead.
Transfers submitted by a script through SubmitTransfer (copies, moves and syncs alike) run on the Head as the automation user and are real data movements, so they fire here like anyone else's; a sync's deletes fire the delete events too. A handler that reacts to them by submitting more transfers should check CtxUsername() first, or it will keep triggering on its own work.