File upload using MeteorJS? - node.js

(Cross post from the Meteor forums)
Say I wanted to upload a file to a server that is built with Meteor from another computer through HTTP when the second computer hits a certain API.
So far, I've been able to create such an application using NodeJS, the Express framework, and multer middlewear. I thought it would be easy to move that to Meteor.
NodeJS:
var express = require('express');
var multer = require('multer');
var done = false;
var port = 8888;
var app = express();
//Multer configuration
app.use(multer({
dest: './uploads/',
limits: {
fileSize: undefined
},
rename: function(fieldName, fileName){
return fieldName + Date.now();
},
onFileUploadStart: function(file){
console.log(file.originalname + ' has started downloading!');
},
onFileUploadComplete: function(file){
console.log(file.fieldname + ' has been uploaded to ' + file.path);
done = true;
},
onFileSizeLimit: function(file){
console.log("File " + file.originalname + " is too large");
},
onError: function(){
console.log("ERROR!!");
}
}));
// POST /api/upload
app.post('/api/upload', function(req, res){
if(done === true){
console.log(req.files);
done = false;
}
res.write("Ack!");
res.end();
});
app.listen(port);
However, when I tried to translate the app to Meteor, files were just not uploaded.
MeteorJS
var multer = Npm.require('multer');
var done = false;
//Set up Multer
Picker.middleware(multer({
dest: './fileUploads',
limits: {
fileSize: undefined
},
rename: function(fieldName, fileName){
return fieldName + Date.now();
},
onFileUploadStart: function(file){
console.log("[.]" + file.originalname + " upload has started at " + Date.now());
},
onFileUploadComplete: function(file){
console.log("[.]" + file.originalname + " upload has finished at " + Date.now());
done = true;
},
onFileSizeLimit: function(file){
console.log("[.]" + file.originalname + " file size limit has been reached");
},
onError: function(){
console.log("[.]ERROR!");
}
}));
var postPicker = Picker.filter(function(req, res){
return req.method === "POST";
});
//Actual route, after the middleware has been set up
postPicker.route('/api/upload', function(params, req, res, next){
if(done === true){
console.log(req.files);
done = false;
}
res.write("Ack!");
res.end();
})
When a call is made to the Meteor server, nothing happens. There is no error, and the server does not print anything. However, the caller receives the "Ack!" from the server.
This has me a bit baffled, and I will appreciate any and all help.
Is there a better way of doing this?
Thank you!

FS.Utility.eachFile(event, function(file){
var doc = new FS.File(file);
doc.metadata = {};
_.extend(doc.metadata, {
userId: userId
});
Images.insert(doc, function(err, fileObj){
})
})

Related

How to display images stored in Mongodb using Node.Js

I need your help on displaying images stored in MongoDB using Node.JS and express framework.
I've successfully saved the image using this method:
var multer = require('multer');
//var upload = multer({ dest: 'public/Images/' });
var fs = require("fs");
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/Images/')
},
filename: function (req, file, cb) {
//cb(null, file.originalname + '-' + Date.now())
cb(null, Date.now() + '-' + file.originalname);
}
});
var upload = multer({storage: storage});
var user = require('../app/model/user');
app.post('/upload', upload.single('meme'), function (req, res, next) {
if (req.file){
var host = req.hostname;
var filePath = req.protocol + "://" + host + '/' + 'public/Images/' + req.file.originalname;
//console.log(filePath);
var newMeme = new user();
newMeme.meme.imgs = filePath;
newMeme.uploadDate = Date.now();
newMeme.save(function (err) {
if (err)
throw err;
//console('Meme saved');
});
return res.send({
success: true
}) ;
} else {
console.log('failed');
res.send({
success: false
});
}
})
I'm now lost when it comes to displaying the images stored.
These are the stuff I want to display:
please, can someone help? I'm using express JS and ejs as my view engine.
Thanks.

Image Upload using nodejs

I am using Ionic v3 and and for backend used Nodejs.
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './uploads')
},
filename: function(req, file, callback) {
console.log(file)
callback(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
});
var upload = multer({storage: storage});
To call this method we require req ,res through API call like below,
upload(req, res, function(err) {
res.end('File is uploaded')
});
My question that is it possible to call this upload function without API call(req,res) ? If yes how can we do ?
What i want to do is, I am developing chat application using ionic2 and nodejs where i can share image. That image should be upload to server side. How can I do for socket programming ?
If you want to upload image using base64 then you can use following code
socket.on('Upload_Image_base64', function(data)
{
var fs = require('fs');
var img = data.image64;
var imgname = new Date().getTime().toString();
imgname = data.userid + imgname + '.png';
var data = img.replace(/^data:image\/\w+;base64,/, "");
var buf = new Buffer(data, 'base64');
fs.writeFile(__dirname + "/uploads/" +imgname, buf);
});
// here data.image64 and data.userid --> is the parameter which we pass during socket event request.
For multi part - this may help you.
socket.on('Upload_Image', function(data)
{
var app = require('express')();
var multer = require('multer')
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage }).single(data.file);
console.log(data.file);
app.post('/', function (req, res)
{
upload(req,res,function(req,res)
{
if(err)
{
console.log("error uploading file");
}
else
{
console.log("uploaded");
}
});
});
});

Nodejs - Video streaming problems

I'm having some problems when trying to stream videos in nodejs. When I tried just pass the video path to the source/video html tag, it doenst worked. Then, I realized that problably I would have to stream the video.
The problem is: When I stream the video, I just get the video being played in the browser, as a direct link to some downloaded video, not the renderized page with some data(video title and path).
I wanna render the page and then run the video.
When I render, I receive the error: "Can't set headers after they're sent".
My code:
const express = require('express')
const multer = require('multer')
const moment = require('moment')
const uuidv4 = require('uuid/v4');
const bodyParser = require('body-parser')
const fs = require('fs')
const videoLib = require('node-video-lib')
const app = express()
const db = require('./db')
let Video = require('./models/videoModel')
//***** STAND LIBRARIES CONFIGURATION **********//
app.use(bodyParser.urlencoded({extended:true}))
app.use(bodyParser.json())
app.set('views', 'views')
app.set('view engine', 'ejs')
app.set(db)
//***** MULTER CONFIGURATION ***************//
let storage = multer.diskStorage({
destination: function(req, file, cb){
cb(null, './uploads')
},
filename: function(req, file, cb){
let mime = file.mimetype.split('/')[1]
let uuid = uuidv4()
cb(null, uuid + "." + mime)
}
})
function fileFilter(req, file, cb){
const extension = file.mimetype.split('/')[0];
if(extension !== 'video'){
return cb(new Error('Something went wrong. Wrong file format'), false);
}
cb(null, true);
};
var upload = multer({storage:storage, fileFilter: fileFilter})
const uploadHandler = upload.single('video')
function uploadVideo(req, res, next){
uploadHandler(req, res, next, function(err){
if(req.fileValidationError){
res.send('Error when upload')
}
console.log(req.file.filename)
next()
})
}
//******************************************//
function newVideo(req, res){
let videoParams = {title: req.body.title, path: req.file.filename}
Video.create(videoParams, function(err, result){
if(err){
console.log(err)
}
else{
console.log("Video salvo com sucesso")
console.log(result)
res.send(result )
}
})
}
app.get('/videos/:id', function(req, res){
let path = req.params.id
Video.find({path:path}, function(err, result){
if(err){
console.log(err);
}
else{
if (true) {
console.log("The url is:" + req.url);
const path = req.url.split('/')[2]
console.log("Path:" + path);
var file = `./uploads/${path}`
var range = req.headers.range;
fs.stat(file, function(err, stats) {
var total = stats.size;
if(range){
console.log('RANGE: ' + range);
var positions = range.replace(/bytes=/, "").split("-");
var start = parseInt(positions[0], 10);
var end = positions[1] ? parseInt(positions[1], 10) : total - 1;
var chunksize = (end - start) + 1;
console.log(req.url, start, end);
res.writeHead(206, {
"Content-Range": "bytes " + start + "-" + end + "/" + total,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": "video/mp4"
});
fs.createReadStream(file, { start: start, end: end }).pipe(res);
} else {
res.writeHead(200, { 'Content-Length': total, 'Content-Type': 'video/mp4' });
fs.createReadStream(file).pipe(res);
res.render('videos', {videoData:result})//Erro: can't set header after they're sent
}
});
} else {
console.log(req.url + ' (static)');
next();
}
}
})
})
app.get('/', function(req, res){
Video.find({}, function(err, result){
if(err){
console.log(err);
}
else{
console.log();
res.render('home', {videoData:result})
}
})
})
app.post('/upload', uploadVideo, newVideo)
app.listen(3000, ()=>{
console.log("Server running on port 3000")
})
You can't use both
res.writeHead();
and
res.render();
Read more: Error: Can't set headers after they are sent to the client

Node multer in routes

I have multer in my app.js like :
var multer = require('multer');
app.use(multer({ dest: './public/img/profile/',
rename: function (fieldname, filename) {
return fieldname;
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
limits: {
files: 1
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
imageUploaded=true;
}
}));
This works but I want to set these settings in a secific route. for example imageRoute.js and not in my app.js. But what should I use instead of app.use() than because I cant access app in my routes. I create routes in my app.js like:
var imageRoutes = require('./routes/imageRoutes')();
app.use('/image', imageRoutes);
imageRoutes.js
module.exports = function(passport) {
var that = this;
// Modules
var express = require('express');
var router = express.Router();
var fs = require('fs');
// Middleware: Checks if user is authenticated removed for more readable code
router.post('/fileupload', that.ensureAuthenticated, function(req, res, next) {
//setup multer here
});
router.post('/fileupload2', that.ensureAuthenticated, function(req, res, next) {
//setup multer here with a different destination path/filename etc
});
return router;
}
i've found this question but it didnt really help me.
UPDATE
I now edited my app.js with :
var multer = require('multer');
var imageRoutes= require('./routes/imageRoutes')(someRepo, multer);
imageRoutes.js
// POST: CREATE avatar
router.post('/avatar', function(req, res) {
router.use(multer({
dest: './public/img/profile/',
rename: function (fieldname, filename) {
return fieldname;
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
limits: {
files: 1
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
imageUploaded=true;
console.log(req.files);
res.redirect('/');
}
}))
});
I see chrome is uploading a file to 100% but then it does nothing. it dosn't log is starting.. or any other error.
You can pass multiple middleware/routers to .use():
var multer = require('multer');
var parseUploads = multer({
dest: './public/img/profile/',
rename: function (fieldname, filename) {
return fieldname;
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
limits: {
files: 1
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
imageUploaded=true;
}
});
// ...
var imageRoutes = require('./routes/imageRoutes')();
app.use('/image', parseUploads, imageRoutes);
If you want to move the logic completely to imageRoutes.js and your multer logic is route-specific, you could do something like:
router.post('/avatar', multer({
dest: './public/img/profile/',
rename: function (fieldname, filename) {
return fieldname;
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
limits: {
files: 1
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
}
}), function(req, res) {
// Here you can check `Object.keys(req.files).length`
// or for specific fields like `req.files.imageField`
res.redirect('/');
});

Store the uploaded files into file system in Express Js

I am new to nodejs and want to know how to put a file into my system backend or even upload it to S3 etc.
Here are the file object:
req.body { homeColor: 'black',
guestColor: 'white',
thirdColor: 'red',
file:
{ webkitRelativePath: '',
lastModifiedDate: '2014-05-05T02:26:11.000Z',
name: '2014-05-05 10.26.11.jpg',
type: 'image/jpeg',
size: 1310720 },
title: 'tfuyiboinini' }
How to handle req.body.file so that it can be physically saved?
Please help and thanks!
long story short
var fs = require('fs');
app.post('/file-upload', function(req, res) {
var tmp_path = req.files.thumbnail.path;
var target_path = './public/images/' + req.files.thumbnail.name;
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
fs.unlink(tmp_path, function() {
if (err) throw err;
res.send('File uploaded to: ' + target_path + ' - ' + req.files.thumbnail.size + ' bytes');
});
});
};
you can read more about it here:
http://www.hacksparrow.com/handle-file-uploads-in-express-node-js.html
First make sure your POST is encoded as enctype="multipart/form-data"....
In Express 4 you need to set the body parser in your server:
var bodyParser = require('dy-parser');
//...
var app = express();
//...
app.use(bodyParser()); // pull information from html in POST
var busboy = require('connect-busboy');
app.use(busboy());
In earlier version of Express you only needed to add the body parser from the framework itself and files will be store on the configured location:
app.use(express.bodyParser({limit: '10mb', uploadDir: __dirname + '/public/uploads' })); // pull information from html in POST
Since version 4 removed support for connect now you need to add your custom support for multipart/form data to parser multi/part POSTs, so you will have to to do something like:
var fs = require('fs');
var busboy = require('connect-busboy');
//...
app.use(busboy());
//...
app.post('/fileupload', function(req, res) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
console.log("Uploading: " + filename);
fstream = fs.createWriteStream(__dirname + '/files/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
res.redirect('back');
});
});
});
This topic already shared the correct answer so might It is helpful.
Also, please find the below solution.
var express = require('express');
var busboy = require('connect-busboy');
var path = require('path');
var fs = require('fs-extra');
var app = express();
app.use(busboy());
app.use(express.static(path.join(__dirname, 'public')));
app.route('/fileupload')
.post(function (req, res, next) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
console.log("Uploading: " + filename);
//Path where image will be uploaded
fstream = fs.createWriteStream(__dirname + '/img/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
console.log("Uploading process finish " + filename);
// res.redirect('back');
});
});
});

Resources