File Upload Service¶
The File Upload Service allows uploading of files to a directory on the Crossbar.io node via (chunked) HTTP/POSTs.
The file upload service has some issues, and may be removed in a future release. Use at your own risk!
Modern browsers support the HTML5 File API which allows users to select files from their local system to be uploaded by the browser. This service can handle big files (GBs) and when combined with Resumable.js features:
upload one or multiple files
chunked uploading
select or drag & drop to upload
resuming uploads
progress indication via WAMP PubSub events
Configuration¶
To configure a File Upload Service, attach a dictionary element to a path in your Web transport :
attribute |
description |
---|---|
type |
MUST be “upload” (required) |
realm |
The realm to which the service session associated with the resource will attach to. (required) |
role |
The role under which the service session associated with the resource will attach under. (required) |
directory |
The folder for completely uploaded files relative to the .crossbar folder in your crossbar node. (required) |
temp_directory |
A folder to hold incomplete uploads. Each incomplete upload will be a subfolder containing the uploaded file chunks. (required) |
form_fields |
Contains the form field mapping between client POST request and backend (required) |
options.file_types |
A JSON Array of permitted file extension strings including the dots. |
options.file_permissions |
The file access permissions to use for the completely uploaded files. (chmod octal code) |
options.max_file_size |
The maximally allowed file size in bytes to upload. Refers to the file not to the chunks of the file. |
The form_fields
dictionary contains the form field names that the
client uses to upload files. It has the following configuration
parameters:
"form_fields": {
"file_name": "resumableFilename",
"mime_type": "resumableType",
"total_size": "resumableTotalSize",
"chunk_number": "resumableChunkNumber",
"chunk_size": "resumableChunkSize",
"total_chunks": "resumableTotalChunks",
"content": "file",
"on_progress": "on_progress",
"session": "session",
"chunk_extra": "chunk_extra",
"finish_extra": "finish_extra"
}
attribute |
description |
---|---|
file_name |
The name of the form field containing the file name. (The file name is not used for anything in the backend). (required) |
mime_type |
The name of the form field to hold the MIME type of the uploaded file. (required) |
total_size |
The name of the form field to hold the integer representing the size of the file in bytes. (required) |
chunk_number |
The name of the form field to hold the chunk number of the current file chunk. (required) |
chunk_size |
The name of the form field holding the chunk size. (required) |
total_chunks |
The name of the form field holding the total number of chunks for the file to be transfered. Needs to be POSTed with every chunk. (required) |
content |
The name of the form field containing the file content. (required) |
on_progress |
Optional name of the form field containing the URI to publish upload related events to. If an URI is provided, progress events will be published as a file is being uploaded. |
session |
Optional name of the form field containing the WAMP session ID of the session to which publihed progress event should be restricted. If no session ID is provided, progress events can be received by any (authorized) session. |
chunk_extra |
The optional name of the form field to hold a serialized JSON object with custom information that will be sent on every chunk upload completion to any listening client. |
finish_extra |
The optional name of the form field to hold a serialized JSON object with custom information that will be sent on file upload completion to any listening client. |
In the example above the file name is passsed to the backend in a POST multipart formdata field with name=”myFilename”)
<input myFilename="test.csv" myprogress_uri="my.upload.progress.uri" />
File Post processing¶
To trigger post processing of files on the server one solution would be
to create a WAMP client on the server (e.g. a python component using
autobahn-python) which subscribes to the upload topic specified under
the form field name given in on_progress
. This component then checks
the progress payload for the key/value status="finished"
and can
also extract custom additional data sent along from the client in the
propertie with name given by finish_extra
. Upon reception of this
event the component can fire off post processing of the file.
Another solution would be to use the python library watchdog to watch on the upload folder. As long as the specified upload-temp folder and the upload folder reside on the same file system, the crossbar file uploader handles files such that all files are moved into the upload folder which constitutes an atomic file system operation. Thereby no incompletely copied or downloaded files can be picked up by watchdog.
Resumable Uploads¶
To implement resumable uploads crossbar file upload functionality provides a GET response on the same path. The response will either be with
Status 200
which indicates that the file or chunk of file is already pressent in the backend.A response with any other Status means the file/chunk is not yet present in the backend and should be uploaded.
With this service the upload client can check for existence of the chunk in the backend prior to POSTing the chunk. This effectively implements resumable uploads.
The GET response needs to have the same arguments as the POST request above.
Example¶
We have a complete example in the Crossbar.io examples repository repository.
Clone the repo, change to the example folder fileupload
and start
Crossbar.io:
crossbar start
To start Crossbar.io with debug log messages:
crossbar start --loglevel=debug
Open http://localhost:8080 in your browser. Open the JavaScript console
to see file upload progress events when uploading files. Then either
click Select files to upload or drop files to Drop files here to
upload. The uploaded files will appear within the uploaded
subdirectory in the example folder.
The example uses this configuration:
{
"workers": [{
"type": "router",
...
"transports": [{
"type": "web",
...
"paths": {
...
"upload": {
"type": "upload",
"realm": "realm1",
"role": "anonymous",
"directory": "../uploaded",
"temp_directory": "../temp",
"form_fields": {
"file_name": "resumableFilename",
"mime_type": "resumableType",
"total_size": "resumableTotalSize",
"chunk_number": "resumableChunkNumber",
"chunk_size": "resumableChunkSize",
"total_chunks": "resumableTotalChunks",
"content": "file",
"on_progress": "on_progress",
"session": "session",
"chunk_extra": "chunk_extra",
"finish_extra": "finish_extra"
},
"options": {
"max_file_size": 209715200,
"file_permissions": "0644",
"file_types": [".csv", ".txt", ".pdf", ".img"]
}
}
}
}]
}]
}