- Overview
- Why this package?
- Install
- API
- new Meteor.Files() [Isomorphic]
- Chunk Streaming [Example]
- Force Download [Example]
- Schema [Isomorphic]
- Template Helper
- Force Download [Example]
- Get file subversion [Example]
- Thumbnail Example [Example]
- Video Streaming Example [Example]
- General Methods
- Insert (Upload) File(s) [Client] - Upload file to server
- Collection [Isomorphic]
- findOne() [Isomorphic]
- find() [Isomorphic]
- write() [Server] - Write binary code into FS
- load() [Server] - Upload file from remote host
This package allows to:
- Upload / Read files in Cordova app: Cordva support (Any with support of
FileReader) - Upload file(s) via DDP
- Small files
- Huge files, tested on 100GB (Note Browser will eat 7%-10% RAM of the file size)
- Pause / Resume upload
- Auto-pause when connection to server is interrupted
- Multi-stream async upload (faster than ever)
- Serving files
- Set
publicoption totrueto serve files via your proxy server, like nginx - Set
protectedoption totrueto serve files only to authorized users, or tofunction()to check user's permission - Files CRC check (integrity check)
- Set
- Write file in file system
- Automatically writes uploaded files on FS and special Collection
- You able to specify
path, collection name, schema, chunk size and naming function - Store multiply versions of the file, like revisions, image thumbnails or video in different formats, and etc.
- File streaming from server via HTTP
- Correct
mime-typeandContent-Rangeheaders - Correct
206and416responses
- Correct
- Download uploaded files from server via HTTP
- You able to specify
route - Download huge files via stream
pipe, tested on 100GB - Fast download for small files
- You able to specify
- Store wherever you like
- You may use
Meteor-Filesas temporary storage - After file is uploaded and stored on FS you able to
mvorcpit's content
- You may use
- Support of non-latin (non-Roman) file names
- Subscribe on files you need
cfs is a good package, but buggy cause it's huge monster which combine everything. In Meteor-Files is nothing to broke, it's simply upload/store/retrieve files to/from server.
- You need store to GridFS? - Add it yourself
- You need to check file mime-type or extensions? - Add it yourself
- You need to resize images after upload? - Add it yourself
Easy-peasy kids, yeah?
meteor add ostrio:filesconfig is optional object with next properties:
storagePath{String} - Storage path on file system- Default value:
/assets/app/uploads
- Default value:
collectionName{String} - Collection name- Default value:
MeteorUploadFiles
- Default value:
cacheControl{String} - DefaultCache-Controlheader, by default:public, max-age=31536000, s-maxage=31536000downloadRoute{String} - Server Route used to retrieve files- Default value:
/cdn/storage
- Default value:
schema{Object} - Collection Schema (Not editable for current release)chunkSize{Number} - Upload chunk size- Default value:
272144
- Default value:
namingFunction{Function} - Function which returnsString- Default value:
String.rand
- Default value:
permissions{Number} - FS-permissions (access rights) in octal, like0755or0777- Default value:
0777
- Default value:
integrityCheck{Boolean} - CRC file check- Default value:
true
- Default value:
strict{Boolean} - Strict mode for partial content, if istrueserver will return416response code, whenrangeis not specified- Default value:
false
- Default value:
downloadCallback{Function} - Called right before initiate file download, with next context and only one argumentfileObj:fileObj- see Current schema section below- context:
@request@response@user()@userId
- Notes:
- Function should return {Boolean} value, to abort download - return
false, to allow download - returntrue
- Function should return {Boolean} value, to abort download - return
protected{Boolean|Function} - Iftrue- files will be served only to authorized users, iffunction()- you're able to check visitor's permissions in your own way- Default value:
false - If function -
functioncontext has:@request- On server only@response- On server only@user()@userId
- Default value:
public{Boolean} - Iftrue- files will be stored in folder publicity available for proxy servers, like nginx- Default value:
false - Route:
http://example.com/uploads/:collectionName/:fileName - Note: Collection can not be
publicandprotectedat the same time! - Note:
integrityCheckis not guaranteed! - Note:
playand forcedownloadfeatures is not guaranteed!
- Default value:
onBeforeUpload{Function} - Callback triggered right before upload on client and right after recieving a chunk on server, with no arguments:- Context of the function is {Object}, with:
extension, aliasextmime-type, aliastypesize
- return
trueto continue - return
falseto abort or {String} to abort upload with message
- Context of the function is {Object}, with:
onbeforeunloadMessage{String or Function} - Message shown to user when closing browser's window or tab, while upload in the progress- Default value:
'Upload in a progress... Do you want to abort?'
- Default value:
allowClientCode{Boolean} - Allow to runremove()from clientdebug{Boolean} - Turn on/of debugging and extra logging- Default value:
false
- Default value:
myFiles.cacheControl = 'public, max-age=31536000' # Set 'Cache-Control' header for downloads
myFiles = new Meteor.Files
storagePath: 'assets/app/uploads/myFiles'
collectionName: 'myFiles'
chunkSize: 256*128
permissions: 0o777
allowClientCode: true
onbeforeunloadMessage: ->
i18n.get '_app.abortUpload' # See 'ostrio:i18n' package
fileObject = myFiles.findOne 'recordId'
if Meteor.isClient
myFiles.collection.subscribe "MeteorFileSubs", postId.get()
if Meteor.isServer
Meteor.publish "MeteorFileSubs", (postId) ->
myFiles.collection.find {'meta.postId': postId}
myFiles.insert(file) # Upload file
myFiles.find({'meta.userId': Meteor.userId()}).cursor # Current collection cursor
myFiles.find({'meta.userId': Meteor.userId()}).get() # Array of fetched rows
myFiles.find({'meta.userId': Meteor.userId()}).remove() # Remove all files on the cursor
myFiles.remove({'meta.userId': Meteor.userId()}) # Remove all files returned by passed search
myFiles.remove(fileRef._id) # Remove file by ID
myFiles.findOne(fileRef._id).get() # Get fileRef
myFiles.findOne(fileRef._id).link() # Get download link
myFiles.findOne(fileRef._id).link('version') # Get download link of specific version
myFiles.link(fileObject) # Get download link
myFiles.link(fileObject, 'version') # Get download link of specific version
myFiles.findOne(fileRef._id).remove() # Remove fileTo stream file add ?play=true query to download link.
audio = new Meteor.Files()
if Meteor.isClient
Template.my.helpers
audiofiles: ->
audio.find({'meta.post': postId}).cursorIn template:
template(name="my")
ul
each audiofiles
li
audio(preload="auto" controls="true")
source(src="{{fileURL this}}?play=true" type="{{type}}")To download file use fileURL template helper. Data will be transfered via pipe, - just add ?download=true query to link, so server will send file directly. Use ?download=true query for smaller files, for big files - just use plain link without query.
uploads = new Meteor.Files()
if Meteor.isClient
Template.my.helpers
files: ->
uploads.find({'meta.post': postId}).cursorIn template:
template(name="my")
ul
each files
li
a(href="{{fileURL this}}?download=true" target="_parent") namename:
type: String
type:
type: String
extension:
type: String
path:
type: String
meta:
type: Object
blackbox: true
optional: true
versions:
type: Object
blackbox: true
###
Example
original:
path: String
size: Number
type: String
extension: String
...
other:
path: String
size: Number
type: String
extension: String
###
userId:
type: String
optional: true
isVideo:
type: Boolean
isAudio:
type: Boolean
isImage:
type: Boolean
size:
type: Numbera(href="{{fileURL fileRef}}?download=true" target="_parent" download) {{fileRef.name}}Note: If requested version of file is not available - the original file will be returned
a(href="{{fileURL fileRef 'small'}}?download=true" target="_parent" download) {{fileRef.name}}Note: If thumbnail (basically version of the file) is not available the original file will be returned
img(src="{{fileURL fileRef 'thumb'}}" alt="{{fileRef.name}}")video(width="80%" height="auto" controls="controls" poster="{{fileURL fileRef 'videoPoster'}}")
source(src="{{fileURL fileRef 'ogg'}}?play=true" type="video/ogg")
source(src="{{fileURL fileRef 'mp4'}}?play=true" type="video/mp4")
source(src="{{fileURL fileRef 'webm'}}?play=true" type="video/webm")Note!: There is no build-in way for image or video resizing, encoding and re-sampling, below example how you can multiple file versions:
FilesCollection = new Meteor.Files()
if Meteor.isClient
'change #upload': (e, template) ->
_.each e.currentTarget.files, (file) ->
Collections.FilesCollection.insert
file: file
onUploaded: (error, fileObj) ->
if error
alert error.message
throw Meteor.log.warn "File Upload Error", error
template.$(e.target).val('')
template.$(e.currentTarget).val('')
Meteor.call 'convertVideo', fileObj, () ->
alert "File \"#{fileObj.name}\" successfully uploaded"
onProgress: _.throttle (progress) ->
template.$('input#progress').val progress
,
500
onBeforeUpload: () ->
if ['ogg', 'mp4', 'avi', 'webm'].inArray(@ext) and @size < 512 * 1048 * 1048
true
else
"Please upload file in next formats: 'ogg', 'mp4', 'avi', 'webm' with size less than 512 Mb. You have tried to upload file with \"#{@ext}\" extension and with \"#{Math.round((@size/(1024*1024)) * 100) / 100}\" Mb"
streams: 8
if Meteor.isServer
###
@var {object} bound - Meteor.bindEnvironment aka Fiber wrapper
###
bound = Meteor.bindEnvironment (callback) ->
return callback()
###
@description Require "fs-extra" npm package
###
fs = Npm.require "fs-extra"
Meteor.methods
convertVideo: (fileRef) ->
check fileRef, Object
sourceFile = ffmpeg(fileRef.path).noProfile()
formats =
ogg: true
mp4: true
webm: true
_.each formats, (convert, format) ->
file = _.clone sourceFile
bound ->
version = file.someHowConvertVideoAndReturnFileData(format)
upd =
$set: {}
upd['$set']['versions.' + name] =
path: version.path
size: version.size
type: version.type
extension: version.extension
FilesCollection.collection.update fileRef._id, upd
return truesettings is required object with next properties:
file{File} or {Object} - [REQUIRED] HTML5filesitem, like in change event:event.currentTarget.files[0]meta{Object} - Additional data as object, use later for searchonUploaded{Function} - Callback triggered when upload is finished, with two arguments:errorfileRef- see Current schema section above
onProgress{Function} - Callback triggered when chunk is sent, with only argument:- {
progressNumber} - Current progress from0to100
- {
onBeforeUpload{Function} - Callback triggered right before upload is started, with no arguments:- Context of the function is
File- so you are able to check for extension, mime-type, size and etc. - return
trueto continue - return
falseto abort or {String} to abort upload with message
- Context of the function is
streams{Number} - Quantity of parallel upload streamsonAbort{Function} - Callback triggered whenabort()method is called, with only one argument:file- File object passed asfileproperty toinsert()method
Returns {Object}, with properties:
onPause{ReactiveVar} - Is upload process on the pause?progress{ReactiveVar} - Upload progress in percentspause{Function} - Pause upload processcontinue{Function} - Continue paused upload processtoggleUpload{Function} - Togglecontinue/pauseif upload in the progressabort{Function} - Abort upload progress, and triggeronAbortcallback
# For example we upload file for blog post
post = Posts.findOne(someId) # Get blog post reference
uploads = new Meteor.Files() # Create Meteor.Files instance
if Meteor is client
# Let's create progress-bar
currentUploadProgress = new ReactiveVar false
Template.my.helpers
progress: ->
currentUploadProgress.get()
Template.my.events
'change #file': (e) ->
_.each e.currentTarget.files, (file) ->
uploads.insert
file: file
meta:
post: post._id # Add meta object with reference to blog post
onUploaded: (error, fileObj) ->
if not error
doSomething fileRef.path, post._id, fileRef
currentUploadProgress.set false
$(e.target).val('')
onProgress: _.throttle (progress) ->
currentUploadProgress.set progress
,
500
onBeforeUpload: () ->
# Set Allowed Extensions and max file size
allowedExt = ['mp3', 'm4a']
allowedMaxSize = 26214400
if allowedExt.inArray(@ext) and @size < allowedMaxSize # See `ostrio:jsextensions` package
true
else
"Max upload size is #{Math.round((allowedMaxSize/(1024*1024)) * 100) / 100} Mb. Allowed extensions is #{allowedExt.join(', ')}"
streams: 8Progress bar in template (TWBS):
template(name="my")
input.btn.btn-success#file(type="file")
if progress
.progress
.progress-bar.progress-bar-striped.active(style="width:{{progress}}%")
span.sr-only {{progress}}%Mongo Collection Instance - Use to fetch data. Do not remove or update this collection
uploads = new Meteor.Files()
if Meteor.isClient
# postId.get() is some ReactiveVar or session
Meteor.subscribe "MeteorFileSubs", postId.get()
if Meteor.isServer
Meteor.publish "MeteorFileSubs", (postId) ->
uploads.collection.find {'meta.postId': postId}
uploads.collection.find({'meta.post': post._id})
uploads.collection.findOne('hdjJDSHW6784kJS')Find one fileObj matched by passed search
search{String or Object} -_idof the file orObject
uploads = new Meteor.Files()
uploads.findOne('hdjJDSHW6784kJS').get() # Get fileRef
uploads.findOne('hdjJDSHW6784kJS').remove() # Remove file
uploads.findOne('hdjJDSHW6784kJS').link('version') # Get download link
uploads.findOne({'meta.post': post._id}).get() # Get fileRef
uploads.findOne({'meta.post': post._id}).remove() # Remove file
uploads.findOne({'meta.post': post._id}).link() # Get download linkFind multiply fileObj matched by passed search
search{String or Object} -_idof the file orObject
uploads = new Meteor.Files()
uploads.find({'meta.post': post._id}).cursor # Current cursor
uploads.find({'meta.post': post._id}).fetch() # Get cursor as Array (Array of objects)
uploads.find('hdjJDSHW6784kJS').get() # Get array of fileRef(s)
uploads.find({'meta.post': post._id}).get() # Get array of fileRef(s)
uploads.find({'meta.post': post._id}).remove() # Remove all files on cursorWrite binary data to FS and store in Meteor.Files collection
buffer{Buffer} - Binary dataoptions{Object} - Object with next properties:type- File mime-typesize- File sizemeta- Additional data as object, use later for searchnameorfileName- File name
callback(error, fileObj)
Returns:
fileObj{Object}
uploads = new Meteor.Files()
buffer = fs.readFileSync 'path/to/file.jpg'
uploads.write buffer
,
type: 'image/jpeg'
name: 'MyImage.jpg'
meta:
post: post._id
,
(err, fileObj) ->
# Download File
window.open uploads.link(fileObj, 'original')+'?download=true', '_parent'Upload file via http from remote host to server's FS and store in Meteor.Files collection
url{String} - Binary dataoptions{Object} - Object with next properties:meta- Additional data as object, use later for searchnameorfileName- File name
callback(error, fileObj)
Returns:
fileObj{Object}
uploads = new Meteor.Files()
uploads.load 'http://domain.com/small.png'
,
name: 'small.png'
meta:
post: post._id
,
(err, fileObj) ->
# Download File
window.open uploads.link(fileObj, 'original')+'?download=true', '_parent'