GraphicsMagick processes resulting in empty file - javascript

I'm doing this
gm(jpgName).setFormat('jpg')
.resize(160,158)
.compress('JPEG')
.write(fs.createWriteStream(jpgName),function(err){
if(err){
console.log(err,jpgName);
res.send(400);
}else{
console.log('file formated to jpg' + jpgName);
And I get
{ [Error: Command failed: gm convert: Empty input file (/home/ubuntu/node/uploads/icon.jpg). ] code: 1, signal: null }
If I stop the code right before the first line written here, and then look at the file, it has a file length. If I let this process happen (error out) then look at the file, then it has a size of 0 bytes.
I also tried this:
fs.stat(jpgName, function (err, stats) {
console.log('file size:',stats.size);
gm(jpgName).setFormat('jpg')
.resize(160,158)
.compress('JPEG')
.write(fs.createWriteStream(jpgName),function(err){
if(err){
console.log('console.log error writing jpg file',err,jpgName);
fs.unlink(jpgName);
callback(400);
return;
}else{//...
And I'm getting a file size back, so I know it's not empty before I start this process.
EDIT: I now start this process on form.on('end') so I could be sure the entire upload process was done.
The entire function:
function formatProfileImage(req,form,file,callback){
console.log('formatting profile image');
var ext = file.name.split('.')[1].toLowerCase();
var name = encodeURIComponent(file.name.split('.')[0].toLowerCase());
var smallName = form.uploadDir+"/"+"small_"+name+".jpg";
var jpgName = form.uploadDir + "/" + name+'.jpg';
console.log('extension:',ext);
console.log('name:',name);
console.log('smallName:',smallName);
console.log('jpgName:',jpgName);
if(!(ext == "png" || ext == "jpeg"|| ext == "jpg"|| ext == "gif")){
fs.unlink(file.path);
console.log("extension rejected");
callback(415);
return;
}
console.log('renaming file from ' + file.path + ' to ' + jpgName);
fs.rename(file.path,jpgName,function(err){
if(err){
console.log('error renaming file',err);
callback(400);
return;
}
console.log('file renamed');
fs.stat(jpgName, function (err, stats) {
console.log('file size:',stats.size);
if(!(typeof req.query.tenant === 'undefined')){
//rename to jpg
gm(jpgName).setFormat('jpg')
.resize(160,158)
.compress('JPEG')
.write(fs.createWriteStream(jpgName),function(err){
if(err){
console.log('console.log error writing jpg file',err,jpgName);
fs.unlink(jpgName);
callback(400);
return;
}else{
console.log('file formated to jpg' + jpgName);
//make "thumbnail"
gm(jpgName).setFormat('jpg')
.resize(50)
.write(fs.createWriteStream(smallName),function(err){
if(err){
fs.unlink(smallName);
console.log('error writing thumbnail',err,smallName);
callback(400);
return;
}else{
console.log('thumbnail created' + smallName);
//upload everything
uploadS3(jpgName,req.query.tenant,function(back){
if(back.success){
console.log('success ' +back.url);
callback(back.url);
fs.unlink(jpgName);
}else{
console.log('error uploading' + jpgName, back);
callback(400);
fs.unlink(jpgName);
return;
}
});
uploadS3(smallName,req.query.tenant,function(back){
if(back.success){
console.log('success ' +back.url);
fs.unlink(smallName);
}else{
console.log('error uploading ' + smallName, back);
callback(400);
fs.unlink(smallName);
return;
}
});
}
});
}
});
}
});
});
}

.write() accept string as path. So you need replace your stream with string (location, where resulting image must me saved).
GM support 3 ways of saving files.
1) Save to file. Simple, just use .write() and send as parameter string, where file should saved. Example:
gm('image.png')
.resize()
.write('resized.png', function (error) {
if (error) {
console.error(error);
}
});
2) Use streams, example:
gm('image.png')
.resize()
.stream(function (error, stdout, stderr) {
var writeStream = fs.createWriteStream('resized.jpg');
stdout.pipe(writeStream);
});
3) And last one - buffers:
gm('image.png')
.resize()
.toBuffer(function (error, buffer) {
if (error) {
console.error(error);
}
});

Related

code throws error, write after end but why

So i made a small api to start up minecraft servers in screen, which works fine.
But now, everytime i start or stop the server, the api crashes somehow because the http server wrote after an end, i cant find anything that ended the server.
I cant seem to find where it ends, its very weird.
I am new to http servers, api's and this stuff so it may be just my dumb fault.
//#author WizzerStudios on Github
//CC 2021
//Allowed:
//:: Editing
//Disallowed
//:: Redistributing
//:: Claiming as yours
//Importing stuff
var http = require('http');
const { exec } = require("child_process");
var url = require('url');
var https = require('https');
const fs = require('fs');
//Console log
console.log("Wizzer API booted.")
//Create API / HTTP Server
http.createServer(function (req, res) {
var q = url.parse(req.url, true).query;
//Check if password is correctly given.
if(q.password == "Password"){
//Switch to the action.
switch(q.action){
//If action is undefined:
case undefined:
res.end("Action not given.");
break;
//Get Logs is coming soon.
case "getlogs":
if(q.sname == undefined) res.end("No server name given.");
try {
const data = fs.readFileSync('serverfiles/' + q.sname + '/logs/latest.log', 'utf8');
res.end(data);
} catch (err) {
console.error(err)
res.end("Error occured! Server does not exist or isn't available.");
}
break;
//Start the server using the bash screen command.
case "stop":
//If no server name is given, end the connection.
if(q.sname == undefined) res.end("Server name not specified.");
//If server exists, run the screen command.
if (fs.existsSync('./servers/' + q.sname + '.json')) {
//Check if a screen session with the same name is already running.
exec('screen -S ' + q.sname + ' -Q select . ; echo $?',
(error, stdout, stderror) => {
if (error) {
console.error("Error: ", error);
return;
}
var out = stdout;
if(out.includes('0')){
exec('screen -p 0 -S minecraft-server -X eval `stuff "say TEST MESSAGE..."\\015`', (error, stdout, stderror) => {
res.end("Server stopped!"); //It says it stopped and crashes here !!!
});
} else {
res.end('Server already stopped!');
return;
}});
} else {
res.end("Server does not exist!");
return;
}
break;
case "start":
//If no server name is given, end the connection.
if(q.sname == undefined) res.end("Server name not specified.");
//If server exists, run the screen command.
if (fs.existsSync('./servers/' + q.sname + '.json')) {
//Check if a screen session with the same name is already running.
exec('screen -S ' + q.sname + ' -Q select . ; echo $?',
(error, stdout, stderror) => {
if (error) {
console.error("Error: ", error);
return;
}
var out = stdout;
if(out.includes('1')){
exec('screen -S ' + q.sname + ' -dm bash /home/mcserver/api/serverfiles/' + q.sname + '/start.sh', (error, stdout, stderror) => {
res.end("Server started!"); // Here it says it already stopped!
});
} else {
res.end('Server already started!');
return;
}});
} else {
res.end("Server does not exist!");
return;
}
break;
//Create server action.
case "createServer":
//If no game is given, end connection.
if(q.game == undefined) res.end("Game not given");
//Switch to the game chosen.
switch(q.game){
//Minecraft
case "minecraft":
if(q.sname == undefined) res.end("Server name not given."); // No server name given, end connection.
if(q.port == undefined) res.end("Port not given."); // No port given, end connection.
if(q.ram == undefined) res.end("Please give ram in gigabytes."); // No ram given, end connection.
if(q.software == undefined) res.end("Server software not given."); // Server software not given, end connection.
if(q.version == undefined) res.end("Server version not given."); // Version not given, end connection.
//Check if server already exists:
var path = './servers/' + q.sname + '.json';
if (fs.existsSync(path)) {
res.end("Server Exists.");
return;
}
ram = Number(q.ram);
ram *= 1024;
let server = {
name: q.sname,
port: q.port,
game: 'Minecraft',
ram: Number(ram),
software: q.software,
version: q.version
};
let data = JSON.stringify(server, null, 2);
fs.mkdir('./serverfiles/' + q.sname, (err) => {
if (err) {
throw err;
res.end(err)
}
});
fs.writeFile('./serverfiles/' + q.sname + '/eula.txt', 'eula=true', function (err) {
if (err) res.end(err);
if(err) console.log(err);
});
fs.writeFile('./serverfiles/' + q.sname + '/start.sh', '#!/bin/bash\njava -Xmx' + Number(ram) + 'M ' + '-Xms' + Number(ram) + 'M -jar /home/mcserver/api/serverfiles/' + q.sname + '/server.jar', function (err) {
if (err) res.end(err);
if(err) console.log(err);
});
exec('chmod +x ./serverfiles/' + q.sname + '/start.sh');
fs.writeFile('./serverfiles/' + q.sname + '/server.properties', 'port=' + q.port, function (err) {
if (err) res.end(err);
if(err) console.log(err);
});
try{
https.get("https://serverjars.com/api/fetchJar/" + q.software + "/" + q.version, function(response) { response.pipe(fs.createWriteStream("serverfiles/" + q.sname + '/server.jar'))});
} catch(err){
res.end("Failed!")
console.log(err)
}
fs.writeFile("servers/" + q.sname + ".json", data, (err) => {});
res.write("Server Software: " + q.software);
res.write("\nRam: " + Number(ram));
res.write("\nServer name: " + q.sname);
res.write("\nGame: Minecraft");
res.write("\nPort: " + q.port);
res.end("\nVersion " + q.version);
}
}
//if(req.url == "/?password=Password&?action=create"){
// res.write("game not given")
//} else if(req.url == "/?password=Password&?action=create&game"){
// res.write("Authenticated!")
//}
//} else {
//res.write("WRONG PASSWORD!")
}
res.end(); //end the response
}).listen(8080); //the server object listens on port 808
events.js:174
throw er; // Unhandled 'error' event
^
Error [ERR_STREAM_WRITE_AFTER_END]: write after end
at write_ (_http_outgoing.js:572:17)
at ServerResponse.write (_http_outgoing.js:567:10)
at exec (/home/mcserver/api/index.js:86:21)
at ChildProcess.exithandler (child_process.js:285:7)
at ChildProcess.emit (events.js:198:13)
at maybeClose (internal/child_process.js:982:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)
Emitted 'error' event at:
at writeAfterEndNT (_http_outgoing.js:634:7)
at process._tickCallback (internal/process/next_tick.js:63:19)
``` is the error.
I do know that i'm writing after the end, but where did it end?
Also, changing res.write to res.end doesn't crash my code, but it doesn't give anything in my browser.
Take out the following line:
res.end(); //end the response <-----------------
}).listen(8080); //the server object listens on port 8080
You are calling "res.end()" after already calling it inside the function
res.end("\nVersion " + q.version); // In createServer
calls it then it drops out the switch statements and executes the above res.end() again
U have to check that in case u already send some response to not send something again.
So each it's better to use:
return res.end();
To stop function.

How to fetch current filename that is being processed using gulp.src()

I have to run certain gulp task over multiple json files in a folder but the task would fetch files different location based on the filename.
I am able to run the task by passing the filename as an argument in cmd but I want to automate the script so that it would get executed for all the files in the src location.
gulp.task("writeJSON", function() {
dataObj = require("./src/data/" + argv["filename"] + ".json");
dataObjKeysList = require("./src/data/stats/" + argv["filename"] + ".json");
segregateData(dataObj, dataObjKeysList, tabspace, false);
gulp
.src("./src/metadata.html")
.pipe(rename(argv["filename"] + ".html"))
.pipe(gulp.dest("./src/output"));
});
Any help would be greatly appreciated.
I am able to resolve the above issue using node filestream. I found this useful article
Filewalker Source
Used the below utility function which take the directory path and callback as args.
function filewalker(dir, done) {
let results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file){
file = path.resolve(dir, file);
fs.stat(file, function(err, stat){
// If directory, execute a recursive call
if (stat && stat.isDirectory()) {
// Add directory to array [comment if you need to remove the directories from the array]
results.push(file);
filewalker(file, function(err, res){
results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
results.push(file);
if (!--pending) done(null, results);
}
});
});
});
};
Added the below execution in my gulp task
filewalker("./src/data/stats/" , function(err, dataFilesList){
if(err){
throw err;
}
dataFilesList.map((name) => {
let fileName = path.basename(name);
fileName = fileName.split('.')[0];
gutil.log('Generating ' + fileName + '.html file.');
});
});

Get file path with dynamic path inside

I need to create file from directory like following
application/userxxx.txt/manifest.txt
The path is constant except the userxxx which can be any alpha numeric
/application/
user12.txt
newfile.txt
newFile2.txt
There is only one file which start with user...
I think of using the which is currently not working..
fs.readdir('c://application', function (err, files) {
if (err) {
throw err;
}
and then get all the files under the application
and search for file which start with userabcd1234.txt and when I find it do the read file like following
readFile('application/userabcd1234/manifest.txt')
There is no two files inside application which start with /user. just one but after the user. and before the third '/manifest.txt' can be any random alpha numeric.
You can do something like
var filePath = path.join(__dirname, '../your path to application folder');
fs.readdir(filePath, function (err, files) {
if (err) {
return console.error(err);
}
files.forEach(function (file) {
if (file.indexOf('user') === 0) {
var relFilePath = filePath + '/' + file + '/manifest.txt';
fs.readFile(relFilePath,'utf8', function read(err, data) {
if (err) {
throw err;
}
console.log(data);
});
}
});
});

Reading and Writing files async in node.js

Currently i'm reading and writing files asynchronously, the thing is that i'm not sure that all the line from the file were read before the rest of my code is executed, here is my code:
var fs = require('fs');
//var str = fs.readFileSync("stockststs.json");
function updateJson(ticker) {
//var stocksJson = JSON.parse(fs.readFileSync("stocktest.json"));
fs.readFile('stocktest.json', function(error, file) {
stocksJson = JSON.parse(file);
if (stocksJson[ticker]!=null) {
console.log(ticker+" price : " + stocksJson[ticker].price);
console.log("changin the value...")
stocksJson[ticker].price = 989898;
console.log("Price after the change has been made -- " + stocksJson[ticker].price);
fs.writeFile('stocktest.json',JSON.stringify(stocksJson, null, 4) , function(err) {
if(!err) {
console.log("File successfully written");
}
});
}
else {
console.log(ticker + " doesn't exist on the json");
}
});
}
updateJson("APPL");
I'm wondering if there is any better way to to implement ?
its always a good practice to check in your callback for error. For example, i have written a small getCache function that checks if the file exists first, then tries to read that file and fire a callback afterwards
Cache.prototype.getCache = function(cache_filename, callback) {
cache_filename = this.cache_foldername + cache_filename;
fs.exists(cache_filename, function(exists) {
if (exists) {
fs.readFile(cache_filename, 'utf8', function (error, data) {
if (!error) {
console.log('File: '+ cache_filename +' successfully Read from Cache!');
_.isObject(data) ? callback(null,data) : callback(null,JSON.parse(data));
} else console.log("Error Reading Cache from file: " + cache_filename + " with Error: " + error);
});
} else callback(null,false);
});
}
note that in here what you need to do is to write the file after it has been read and checked with the if (!error)
i hope this helps

Crypto module - Node.js

Which is the simplest way to compare a hash of a file without storing it in a database?
For example:
var filename = __dirname + '/../public/index.html';
var shasum = crypto.createHash('sha1');
var s = fs.ReadStream(filename);
s.on('data', function(d) {
shasum.update(d);
});
s.on('end', function() {
var d = shasum.digest('hex');
console.log(d + ' ' + filename);
fs.writeFile(__dirname + "/../public/log.txt", d.toString() + '\n', function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
});
The above code returns the hash of the HTML file. If I edit the file how can I know if it has been changed? In other words, how can I know if the hash has been changed?
Any suggestions?
Edited
Now the hash is being saved in the log file. How can I retrieve the hash from the file and match it with the new generated one? A code example would be awesome to give me a better understanding.
There is no difference with this question, but it isn't clear for me yet how to implement it.
If you're looking for changes on a file, then you can use one of Node's filesystem functions, fs.watch. This is how it's used:
fs.watch(filename, function (event, filename) {
//event is either 'rename' or 'change'
//filename is the name of the file which triggered the event
});
The watch function is however not very consistent, so you can use fs.watchFile as an alternative. fs.watchFile uses stat polling, so it's quite a bit slower than fs.watch, which detects file changes instantly.
Watching a file will return an instance of fs.FSWatcher, which has the events change and error. Calling .close will stop watching for changes on the file.
Here's an example relating to your code:
var filename = __dirname + '/../public/index.html';
var shasum = crypto.createHash('sha1');
var oldhash = null;
var s = fs.ReadStream(filename);
s.on('data', function(d) {
shasum.update(d);
});
s.on('end', function() {
var d = shasum.digest('hex');
console.log(d + ' ' + filename);
oldhash = d.toString();
fs.writeFile(__dirname + "/../public/log.txt", d.toString() + '\n', function(err) {
if(err) {
console.log(err);
}
else {
console.log("The file was saved!");
}
});
});
//watch the log for changes
fs.watch(__dirname + "/../public/log.txt", function (event, filename) {
//read the log contents
fs.readFile(__dirname + "/../public/log.txt", function (err, data) {
//match variable data with the old hash
if (data == oldhash) {
//do something
}
});
});
What's the difference between this question and the previous one you asked? If you're not wanting to store it in a database, then store it as a file. If you want to save the hash for multiple files, then maybe put them in a JSON object and write them out as a .json file so they're easy to read/write.
EDIT
Given what you added to your question, it should be pretty simple. You might write a function to do check and re-write:
function updateHash (name, html, callback) {
var sha = crypto.createHash('sha1');
sha.update(html);
var newHash = sha.digest('hex');
var hashFileName = name + '.sha';
fs.readFile(hashFileName, 'utf8', function (err, oldHash) {
var changed = true;
if (err)
console.log(err); // probably indicates the file doesn't exist, but you should consider doing better error handling
if (oldHash === newHash)
changed = false;
fs.writeFile(hashFileName, newHash, { encoding: 'utf8' }, function (err) {
callback(err, changed);
});
});
}
updateHash('index.html', "<html><head><title>...", function (err, isChanged) {
// do something with this information ?
console.log(isChanged);
});

Categories