JSS File-System Extensions

A JSS file-system extension is a set of Javascript functions that define the behaviour of the files and folders, within a folder of the CompleteFTP virtual file-system.

CompleteFTP's virtual file-system is available via the system.getFile(path) method. This method returns objects of the File class. The fact that an object is returned, does not imply that a file exists on that path; this may be checked using the exists() method.

Developing a JSS file-system extension

General instructions on writing CompleteFTP JSS extensions may be found here. Remember that file-system extensions are linked to the file-system via a folder-type, so an entry for the file-system extension being developed must be present in the folder-type tab, before a folder of that type may be added to the virtual file-system. It's created automatically but it's important to understand this linkage. Once a folder-type has been created the file-system extension may be tested by creating a folder of that type in the virtual file-system, and then listing that folder using a client such as FileZilla.

At a minimum, a JSS file-system extension must implement a function called getFileInfos(), which returns a file-listing. For example, this code will generate a listing containing three files (file1.txt, file2.txt and file3.txt):

var files = {
	"file1.txt" : "File 1",
	"file2.txt" : "File 2",
	"file3.txt" : "File 3"
};

function getFileInfos(path) {
	var fileInfos = [];
	for (var fileName in files)
		fileInfos.push({ 
			name: fileName, 
			isDirectory: false, 
			length: files[fileName].length 
		});
	return fileInfos;
}

getFileInfos() returns an array of objects. Each object in the array describes one file: its name (name), whether or not it's a directory (isDirectory) and its length (length). The path argument specifies the path of the subdirectory to be listed, relative to the directory that this file-system extension is handling. In this case it may be ignored, since no subdirectories are returned in the listing.

Add the script above into the CompleteFTP Manager.

Then create the folder with the newly created folder and set the login user as owner of that folder.

Then login with FileZilla as that user.

The listing of files will then be generated.

The capability of downloading the 'files' may be added as follows:

function read(path) {
	if (files[path])
		return { text: files[path] };
	else
		throw "No such file: " + path;
}

Here the path argument becomes important since it specifies which file is to be read. The object returned, implicitly defines the type of the contents. Here, the object has a property named text. Any of the following may be returned:

Return value: Used when...
{ file: '/folder/file.dat' } the file being downloaded is at another location in the virtual file-system.
{ text: 'some text' } the content of the 'file' being downloaded is text.
{ base64: 'c29tZSB0ZXh0' } the content of the file is binary. It will be converted to binary before sending to the client.

Uploading may be implemented as follows:

function onWriteBegin(session, node, path) {
	return { type: "text" };
}

function write(path, data) {
	files[path] = data;
}

The method, onWriteBegin(), is called when uploading of the file commences. It instructs CompleteFTP on what to do with the incoming file. In this case, we're expecting text to be uploaded. The write() method is called when the upload has completed. Here we simply store it in the files object.

onWriteBegin() may also return a type of 'file' and 'base64'. If 'file' is returned, then a second property, path, must also be returned, which defines the path in the virtual file-system where the incoming file should be stored (e.g. { type: 'file', path: '/mydir/myfile.dat' }. In this case, the content of the file is not buffered in memory, but is streamed straight to the disk so that very large files can be handled. If a binary file is expected, then 'base64' may be returned, in which case a base-64 encode string is passed to the write() method.

For File system extension example, please check here.

There are a number of other functions that may be implemented to add other capabilities, such as file deletion and folder creation. The section below is the full list of interfaces.

Full details of JSS APIs

Full details are provided in the JSS API Reference.

Folder listing

// Return a directory listing as an array of objects.  The objects may have the following fields:
//   name - string,
//   isFolder - boolean,
//   length - number (optional),
//   modifiedTime - Date  (optional),
//   createdTime - Date  (optional),
function getFileInfos(path, session, node)

File reading

// Read the file at the given path.  Return one of the following:
//   { file: 'path-of-file' }, 
//   { text: 'text-content' } or
//   { base64: 'base64-encoded-bytes' }
function read(path, session, node)

// Release any used resources at the end of a read operation (optional)
function onReadEnd(path, session, node)

File writing

// Instructs CompleteFTP what to do with the file that's being written.  Return one of the following:
//   { type: 'file', path: 'path-of-file' },
//   { type: 'text' } or
//   { type: 'base64' }
// If type is 'text' or 'base64' and it is returned, then the content will be passed to the write function once 
// the content has been streamed to the server.
function onWriteBegin(path, session, node)

// Called when a file has finished streaming to the server.  
// If the onWriteBegin method specified the type as 'text' then the second argument, data, is the 
// text and the third argument, length, is the number of characters.  If the type is 'base64' then
// data is base64-encoded bytes and length is the number of bytes prior to encoding.  If the type
// is 'file' then data is null and length is the size of the file.
function write(path, data, length, session, node)

File attributes

// Indicate whether or not the file-length is known (only used for HTTP requests)
function isFileLengthKnown(path, session, node)

// Return the file-length in bytes of the file at the given path.  If this method is not provided 
// then getFileInfos is called to get the file-length.
function getFileLength(path, session, node)

// Return the time when the file at the given path was last modified.  If this method is not 
// provided then getFileInfos is called to get the timestamp.
function getModifiedTime(path, session, node)

// Set the time that indicates when the file at the given path was last modified.
function setModifiedTime(path, session, node)

// Return a string that canonically defines the given virtual file-system path from the point of 
// view of this adapter (e.g. a Windows adapter returns the Windows path)
function getAdapterFilePath(path, session, node)

Existence/deletion/creation

// Indicate whether or not a file exists.  Return true or false.
function fileExists(path, session, node)

// Delete the file at the given path.  No return value required.
function deleteFile(path, session, node)

// Indicate whether or not a file exists.  Return true or false.
function directoryExists(path, session, node)

// Delete the directory at the given path.  No return value required.
function deleteDirectory(path, session, node)

// Create a directory at the given path
function createDirectory(path, session, node)

Rename/move/copy

// Move/rename the file at fromPath to toPath.  No return value required.
function moveFile(fromPath, toPath, session, fromNode, toNode)

// Copy the file at fromPath to toPath.  No return value required.
function copyFile(fromPath, toPath, session, fromNode, toNode)

Inheritance

// Return the type of file-system adapter to inherit functionality from - "windows" or "default".
function getBaseType()

// Return the Windows path of the file/folder at the given virtual file-system path.
function getWindowsPath(path, session, node)