Jump To …

index.js

endPoints/files/

Mongodb GridFs API Endpoint

var ObjectID = mongo.ObjectID;
var spawn = require('child_process').spawn;
(exports = module.exports = function(house, options){
    

This endpoint requires a data source

    var ds = options.ds;
    var filesRoot = options.collection;
    var col = filesRoot+'.files';
    
    var getExifDataFromPath = function(filePath) {
        var self = this;
       var exif = spawn('/usr/bin/exiftool', [filePath]);
       var exifOut = '';
       exif.stdout.on('data', function (data) {

console.log('stdout: ' + data);

         exifOut += data.toString();
       });
    
       exif.stderr.on('data', function (data) {
         console.log('stderr: ' + data);
         console.dir(data);
       });
    
       exif.on('close', function (code) {

console.log('exiftool process exited with code ' + code);

         if(code == 0){ // good
           var exifObject = {};
           exifOut = exifOut.split('\n');
           exifOut.forEach(function(e, i){
             var tmp = e.split(': ');
             exifObject[tmp[0].trim()] = tmp[1];
           });

console.log(exifObject);

           if(self.hasOwnProperty('resultCb')) {
               self.resultCb(exifObject);
           }
         }
       });
           
        return {
            "result": function(callback){
                self.resultCb = callback;
            }
        }
    }
    
    var getUniqueFileName = function(name) {
        
    }
    
    var importFileToGrid = function(file, metadata, callback) {
        var self = this;
        
        if (typeof metadata == "function") {
            callback = metadata;
            metadata = {};
        } else {
            metadata = metadata || {};
        }
        
        var file_name = decodeURIComponent(file.name);
        file_name.substr(0,file_name.lastIndexOf('.')).replace('.','')+file_name.substr(file_name.lastIndexOf('.'));
        
        var mime_type = file.type;
        
        var uploadFileGridStore = new mongo.GridStore(ds.db, file_name, "w", {
            content_type: mime_type,
            metadata: metadata,
            root: filesRoot
        });
        uploadFileGridStore.writeFile(file.path, function(err, gridFile){

console.log('uploadFileGridStore.writeFile'); console.log(gridFile);

            callback(err, gridFile);
        });
    }
    
    var getReadableGridStore = function(filename) {
        var gs = new mongo.GridStore(ds.db, filename, "r", {'root': filesRoot});
        return gs;
    }
    
    var handleReq = function(req, res, next) {
        var path = req.hasOwnProperty('urlRouted') ? req.urlRouted : req.url;

console.log(req.headers) console.log(req.method)

        var findQuery = function(query, callback) {
            ds.find(col, query, function(err, data){
                if(err) {
                    house.log.err(err);
                } else if(data) {
                    res.data(data);
                } else {
                    house.log.err(new Error('no data from mongo'));
                }
            });
        }
        
        if(req.method == 'GET' || req.method == 'HEAD') {
            var query = {};
            

console.log(path);

            if(path === '' || path === '/') {
                findQuery(query);
            } else {
                var filename = decodeURIComponent(path.substr(1));

console.log(filename); console.log('mongo.GridStore.exist');

                mongo.GridStore.exist(ds.db, filename, filesRoot, function(err, result) {
                    if(result) {
                        
                        getReadableGridStore(filename).open(function(err, gs){
                            var resCode = 200;
                            var offset = 0;
                            var etag = '"'+gs.length+'-'+gs.uploadDate+'"';
                            var contentType = gs.contentType;
                            var headerFields = {
                                'Content-Type': contentType
                                , 'Date': gs.uploadDate
                              , 'ETag': etag
                            };
                            
                            if(req.method == 'HEAD') {

console.log('HEAD');

                                headerFields["Content-Length"] = gs.length;
                                headerFields["Accept-Ranges"] = 'bytes';
                                gs.close(function(){

house.log.debug('gridstore closed');

                                    res.writeHead(200, headerFields);
                                    res.end('');
                                });
                                return;
                            }
                            
                            if(req.headers['if-none-match'] == etag){
                              resCode = 304;
                              headerFields['Content-Length'] = 0;
                              gs.close(function(){
                                  res.writeHead(resCode, headerFields);
                                  res.end();
                              });
                              return;
                            }
                            
                            var contentLen = gs.length;
                            var bytStr = 'bytes=';
                            var chunkSize = 4096
                            , lengthRemaining = gs.length;

console.log('req.headers.range.substr(0,bytStr.length)');

                            if(req.headers.range && req.headers.range.substr(0,bytStr.length) == bytStr) {

console.log('range '+req.headers.range);

                              var rangeString = '';
                                var bytSelection = req.headers.range.substr(bytStr.length);
                              var bytDashPos = bytSelection.indexOf('-');
                              var bytPreDash = bytSelection.substr(0, bytDashPos);
                              var bytEndDash = bytSelection.substr(bytDashPos+1);
                              resCode = 206;
                                delete headerFields['ETag'];
                              if(bytPreDash == '0') {
                                if(bytEndDash) {
                                  contentLen = parseInt(bytEndDash);
                                        rangeString = bytPreDash + '-' + bytEndDash+1;
                                } else {
                                    rangeString = '0-' + (gs.length-1).toString();
                                }
                              } else if(bytEndDash != '' && bytPreDash != '') {
                                contentLen = parseInt(bytEndDash) - parseInt(bytPreDash);
                                offset = parseInt(bytPreDash);
                                rangeString = bytPreDash + '-' + bytEndDash;

console.log(offset);

                              } else if(bytEndDash == '' && bytPreDash != '') {

ex, 1234-

                                contentLen = contentLen - parseInt(bytPreDash);
                                offset = parseInt(bytPreDash) - 1;
                                rangeString = bytPreDash + '-' + (gs.length - 1).toString();
                              }
                              headerFields["Content-Range"] = 'bytes ' + rangeString+'/'+gs.length; // needs to always be the full content length? // req.headers.range; //bytSelection; // should include bytes= ???
                                headerFields["Vary"] = "Accept-Encoding";
                              lengthRemaining = contentLen;
                            }
                            
                            house.log.debug(resCode+' '+filename+' as: '+gs.contentType+' with length: ' + contentLen, resCode);
                            headerFields["Content-Length"] = contentLen;

headerFields["Accept-Ranges"] = 'bytes'; // enables scrubbing in chrome

                            

house.log.debug(headerFields);

                            res.writeHead(resCode, headerFields);
                            
                            if(lengthRemaining < chunkSize) {
                              chunkSize = lengthRemaining;
                            }
                            
                            var gridStoreReadChunk = function(gs) {
                                var readAndSend = function(chunk) {
                                  gs.read(chunk, function(err, data) {
                                  if(err) {
                                    house.log.err('file read err: '+filename);
                                    house.log.err(err);
                                      gs.close(function(){

house.log.debug('gridstore closed');

                                          res.end();
                                      });
                                      return;
                                  }
                                    
                                      res.write(data, 'binary');
                                      lengthRemaining = lengthRemaining - chunk;
                                      
                                      if(lengthRemaining < chunkSize) {
                                        chunkSize = lengthRemaining;
                                      }
                                    
                                    
                                    if(lengthRemaining > 0) {
                                      readAndSend(chunkSize);
                                    } else {

close the gridstore

                                      gs.close(function(){

house.log.debug('gridstore closed');

                                          res.end();
                                      });
                                    }
                                  }); // read
                                }
                                if(chunkSize > 0) {
                                  readAndSend(chunkSize);
                                }
                            }
                            if(offset != 0) {

house.log.debug('gridstore seek '+offset);

                                 gs.seek(offset, function(err, gs) {
                                  if(err) {
                                    house.log.err('err');
                                  }
                                  gridStoreReadChunk(gs);
                                 });
                            } else {
                                 gridStoreReadChunk(gs);
                            }
                        });
                        
                    } else {
                       if(err) {
                           house.log.err(err);
                           res.end('error');
                       } else {

console.log(filename)

                           try {
                              findQuery({_id: new ObjectID(filename)});
                           } catch(e) {
                               res.end('file does not exist');
                           }

res.end('file does not exist');

                       }
                    }
                });
            }
            
        } else if(req.method == 'POST') {
            house.log.debug('post to files (upload)');
            if(path == '') {
                if(req.files) {
                    for(var i in req.files) {
                        var file = req.files[i];
                        importFileToGrid(file, {}, function(err, data){
                            if(err) {
                                console.log('file upload err');
                                console.log(err);
                            } else {
                                if(data.contentType.indexOf('audio') === 0) {
                                    console.log('proces audio upload');
                                    
                                    getExifDataFromPath(file.path).result(function(exif){
                                        console.log('metadata');
                                        console.log(exif);
                                    
                                        var newSong = {
                                            file_id: data._id,
                                            filename: data.filename,
                                            ss: ''
                                        }
                                        if(exif.Title) {
                                            newSong.title = exif.Title;
                                            newSong.ss += exif.Title;
                                        } else {
                                            newSong.title = newSong.filename;
                                            newSong.ss += newSong.filename;
                                        }
                                        if(exif.Album) {
                                            newSong.album = exif.Album;
                                            newSong.ss += ' '+exif.Album;
                                        }
                                        if(exif.Artist) {
                                            newSong.artist = exif.Artist;
                                            newSong.ss += ' '+exif.Artist;
                                        }
                                        if(exif.Year) {
                                            newSong.year = exif.Year;
                                        }
                                        if(exif.Genre) {
                                            newSong.genre = exif.Genre;
                                        }
                                        if(exif.Duration) {
                                            newSong.duration = exif.Duration;
                                            var iof = newSong.duration.indexOf(' (approx)');
                                            if(iof !== -1) {
                                                newSong.duration = newSong.duration.substr(0,iof);
                                            }
                                            var dArr = newSong.duration.split(':');
                                            var secs = parseInt(dArr.pop(), 10);
                                            var mins = parseInt(dArr.pop(), 10);
                                            
                                            newSong.duration = (mins * 60) + secs;
                                        }
                                        if(exif.Lyrics) {
                                            newSong.lyrics = exif.Lyrics;
                                        }

picture track lyrics

                                        
                                        ds.insert('songs', newSong, function(err, songData) {

console.log('new song!');

                                            res.data({song: songData, file: data});
                                            
                                            fs.unlink(file.path, function(){
                                                console.log('file unlinked from tmp');
                                            });
                                        });
                                    });
                                    
                                } else {
                                    console.log('done upload');
                                    res.data({file:data});
                                }
                            }
                        });
                    }
                }
            }
        } else if(req.method == 'PUT') {
            var query = {};
            var docId = new ObjectID(path.substr(1));
            return;
            if(docId) {
                query._id = docId;
            
                ds.update(col, query, req.fields, function(err, data){
                    if(err) {
                        house.log.err(err);
                        res.end('error');
                    } else {
                        house.log.debug(data);
                        res.data({});
                    }
                });
            }
        } else if(req.method == 'DELETE') {
            var query = {};
            var docId = new ObjectID(path.substr(1));
            if(docId) {
                query._id = docId;
                ds.remove(col, query, function(err, data){
                    if(err) {
                        house.log.err(err);
                        res.end('error');
                    } else {
                        console.log('deleted file');
                        res.data(data);
                    }
                });
                
            }
        } else if(req.method == 'HEAD') {

console.log(req.headers) console.log('HEAD');

            res.data({});
        } else if(req.method == 'OPTIONS') {

console.log('OPTIONS');

        } else {
            if(req.method) {

console.log('bad method '+req.method);

            } else {

console.log('NO method!');

            }
        }
    }
    return handleReq;
});

JukeboxJS