How to find out if reading dir is completed - node.js

everyone
I am working on some sort of image view application using node-webkit. I made a function to read dir inside the given location and search for the image files(*.jpg and *.png). Code I used is as follows:
app.js
var fs = require("fs");
var gui = require('nw.gui');
var win = gui.Window.get();
var directory;
var db = require('diskdb');
var path = require('path')
db = db.connect("lib/collections", ['temp']);
function chooseFile(name) {
var chooser = $(name);
scr = 0;
chooser.change(function(evt) {
directory = $(this).val();
var asdf;
console.clear();
readDir(directory);
$(this).val('').hide();
});
}
function readDir(directory){
c = 0;
console.log("reading "+directory);
if(fs.statSync(directory).isDirectory() == true){
fs.readdir(directory,function(err,files){
if (err){
console.log(err);
return;
}
var ext;
files.forEach(function(file){
console.log("Got what: "+file);
var fulls = directory+"\\"+file;
if(file.indexOf(".") != 0){
if(path.extname(fulls) == ""){
console.log("Got a directory: "+file);
if(fs.statSync(fulls).isDirectory() == true){
readDir(fulls);
}
}
else{
console.log("Got a file: "+file);
if(checkExtension(file, 'jpg,png')){
scr++;
c = saveTemp(fulls,scr,file);
}
}
}
});
if(c == 1){
loadgun();
}
});
}
}
function loadgun(){
if(db.temp.count()!=0){
for(i=1;i<=db.temp.count();i++){
var asd = db.temp.findOne({'id':i});
var theTempScript = $("#tmpl-imgholder").html();
var theTemp = Handlebars.compile(theTempScript);
$("#ContentWrapper").append(theTemp({"fulls":asd.file, "id":asd.id, "title":asd.title}));
}
}
}
saveTemp = function(file,id, title) {
var savedUser = db.temp.save({
file:file,
id:id,
title:title
});
return 1;
};
function checkExtension(str, ext) {
extArray = ext.split(',');
for(i=0; i < extArray.length; i++) {
if(str.toLowerCase().split('.').pop() == extArray[i]) {
return true;
}
}
return false;
};
$(document).ready(function(){
if(db.temp.count() != 0){
loadgun();
}
else{
$('#blah').css('display','block');
chooseFile('#blah');
}
});
index.html
<html>
.
.
.
<body>
<input type="file" nwdirectory id="blah" style="display:none"/>
<script src="js/jquery.min.js"></script>
<script src="js/app.js"></script>
<script src="js/handlebars.js"></script>
<script id="tmpl-imgholder" type="x-handlebars-template">
<div class="image-container grid__item" data-id="{{id}}" data-src="{{fulls}}">
<div class="cover" style="background:url({{fulls}})" title="{{title}}"></div>
<div class="info">
<div class="title">{{title}}</div>
</div>
<div class="clear"></div>
</div>
</script>
</body>
</html>
Here i tried to load data using loadgun function. Its hangs the node webkit window. If I could know when the readDir function terminates then i could do load the required datas.
If there is another way please do say.
Thanks in advance.

the problem with readDir is that is asynchronous function , that is why you have to provide a callback. you can however use fs.readdirSync(path) which is synchronous , and then the code flows synchronously. a psoducode may look like this :
function readDirAsynch(dir){
var files = fs.readdirSync(dir);
for (var i in files){
if (files[i] isDir){
readDirAsynch(files[i]);
} else if (myCondition){
//do somehting
}
}
}
needless to say , you know that the function is done when the next line after the function call is being executed

Quick answer:
You can use the synchrohous method fs.readdirSync(path) and everything should work just fine for you. You don't need to keep reading. https://nodejs.org/api/fs.html#fs_fs_readdirsync_path
My personal suggestion:
Since node is single threaded I would recommend you to keep using the asynchronous version but adding a callback to your method.
This means that your "readDir" method is going to be asynchronous too. You only need to add a callback parameter to your method. E.g.
readDir(dir, fnCallback) {
...
fs.readdir(directory, function(err,files){
... doing cool stuff ...
fnCallback();
});
}
If you want to read more about writing asynchronous code maybe this guide can help you.
http://callbackhell.com/
Also if you want to go further in the wonderful asynchronous world you can take a look to 'Promises' https://www.npmjs.com/package/node-promise, 'Future' https://www.npmjs.com/package/async-future, 'Async' https://www.npmjs.com/package/async and have more fun than you have ever imagined before.

Related

Not able to figure out how to wait until forEach loop iterates completely and use that result

I am new to cloud functions (node js with typescript). I am using it to fetch data from Firebase database( as the code below). But Not able to figure out how to wait until forEach loop iterates completely and use that result.
const reference = admin.database().ref('/books')
var path_key:string
var total_count:number = 0
reference .forEach(function (snapshot) {
path_key= snapshot(key).val()
ref_users_advance_bookings.child(path_key)
.once('value').then((snapshot2)=>{
if(condidtion met){
return response.send("failed")
}
else{
total_count++
}
)}
return true
})
// i want to use total_count value here
return response.send("count :"+total_count) // but every time I gets 0, as it get executed before forEach has ended
)}
My guess is that you're trying to wait for a number of items to load from the database. For that you'll want to use Promise.all(), in something like:
var promises = [];
ref.forEach(function (snapshot) {
path_key= snapshot(key).val()
promises.push(ref_users_advance_bookings.child(path_key).once('value'));
});
Promise.all(promises).then(function(snapshots) {
var failed = false;
snapshot.forEach(function(snapshot2) {
if(condition met){
failed = true;
}
else {
total_count++;
}
)}
if (failed) {
return response.status(500).send("ERROR");
}
else {
return response.send("count :"+total_count);
}
});

Header script causing alert

When loading the page I get a alert box with unidentified in, when remove this bit code it goes. I need this as it makes the menu work.
Going in a bit blind on this so wasn't sure what it doesn't like, I suppose I should be asking what does this actually mean?
<script type="text/javascript">
var loadEvents = new Array();
function addInitFunction(func) { loadEvents.push( { 'func':func, 'seq':-1 } ); }
function addLoadEvent(func, seq) { loadEvents.push( { 'func':func, 'seq':seq } ); }
var linkver="-65";
var IP="";
var proto="https:";
var def_proto="http:";
</script>
Narrowed it down to this line
function addInitFunction(func) { loadEvents.push( { 'func':func, 'seq':-1 }); }
I've also found what I think is the function with the issue
<script type="text/javascript">
// Move responsive divs
function homeRespChange(from, too, source) {
respMoveContent('respHeaderLogin', { 'default':'respMove_HeaderLogin_default', 'phone':'respMove_HeaderLogin_phone' });
}
function homeInit() {
responsiveKick();
}
addInitFunction('homeInit');
addInitFunction('menuFixup');
addInitFunction('setWallp');
addInitFunction('tidyFunc');
addInitFunction('moveBasket');
addInitFunction('loginMenu');
function mess() {
alertX('EUCookieMessage_Holder');
}
//addLoadEvent(mess);
</script>

Custom chrome extension not launching device list

I'm trying to launch the cast api from a chrome extension that i'm writing. When I run this same code in a regular old HTML file on my webserver, it works perfectly. It doesn't work when I use this code in the popup of my extension. The requestSession call doesn't work at all in that case and nothing seems to happen after it's called.
I believe the expected behaviour is that the google cast extension will show the device list popup. Here is my javascript and html. Most of it is copied right out of CastHelloVideo-chrome.
HTML:
<html>
<head>
<title>Popup</title>
<style>
body {
min-width:5px;
overflow-x:hidden;
}
</style>
<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>
</head>
<body>
<button type="button" id="castButton">Cast!</button>
</body>
<script type="text/javascript" src="popup.js"></script>
</html>
Javascript:
//Constants
var applicationID = "<App ID>";
var session;
var currentMediaSession;
///////////////////////////////////////////////////////////////////
//Chromecast API
///////////////////////////////////////////////////////////////////
if (!chrome.cast || !chrome.cast.isAvailable) {
setTimeout(initializeCastApi, 1000);
}
function loadMedia() {
if (!session) {
console.log("no session");
return;
}
var mediaInfo = new chrome.cast.media.MediaInfo('http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4');
mediaInfo.contentType = 'video/mp4';
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.autoplay = false;
request.currentTime = 0;
session.loadMedia(request,
onMediaDiscovered.bind(this, 'loadMedia'),
onMediaError);
}
/**
* callback on success for loading media
* #param {Object} e A non-null media object
*/
function onMediaDiscovered(how, mediaSession) {
console.log("new media session ID:" + mediaSession.mediaSessionId);
currentMediaSession = mediaSession;
}
/**
* callback on media loading error
* #param {Object} e A non-null media object
*/
function onMediaError(e) {
console.log("media error");
}
//////////////////////////////////////////////////////////////////
//UI
//////////////////////////////////////////////////////////////////
var castbutton = document.getElementById("castButton");
castButton.onclick=function(){
window.close();
chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);
// loadMedia();
};
//////////////////////////////////////////////////////////////////
//Helper Functions
//////////////////////////////////////////////////////////////////
function initializeCastApi() {
var sessionRequest = new chrome.cast.SessionRequest(applicationID);
var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
sessionListener,
receiverListener);
chrome.cast.initialize(apiConfig, onInitSuccess, onError);
}
function sessionListener(e) {
console.log('New session ID: ' + e.sessionId);
session = e;
}
function receiverListener(e) {
console.log(e);
}
function onInitSuccess() {
console.log("init success");
}
function onError() {
console.log("error");
}
function onSuccess(message) {
console.log(message);
}
function onRequestSessionSuccess(e) {
session = e;
console.log("session created");
}
function onLaunchError(e) {
console.log(e.description);
}
I think this may be caused because I'm trying to run this out of the popup of my extension. Maybe chrome doesn't allow multiple plugins to show their (the device list is google cast's popup) popup window's at the same time? I've tried closing the popup before executing the requestSession call, but it still doesn't work. Anyone have any ideas?
Invoking requestionSession API call within a Chrome extension is not supported. That's why you cannot get a list of devices.
In any case this method call only works from a regular web page and it triggers the extension to show a pop-up of Cast devices. That's the only current way it's supposed to work.

How to get rid of the asynchoronous code here

I have been trying to retrieve the data using the MongoJS driver for node.js.The Code which I am using is as follows
req.on('end', function(){
var decodedBody = querystring.parse(fullBody);
story=decodedBody.name;
var z=new Array();
console.log(story);
res.writeHead(200,{'Content-Type': 'text/html'});
res.write('<html><body>');
db.frames.find({str_id:story}).toArray(function(err,doc){
console.log(doc);
for(var t=0;t<doc.length;t++)
{
var picid=doc[t].pic_id;
console.log(picid);
db.pictures.find({_id:picid}).toArray(function(err,pic){
res.write('<img src="'+pic[0].name+'"/>');
});
}
})
res.end('</body></html>');
});
The problem here is that because of the asynchronous nature of the code the response gets ends first and then the code inside the block of database gets executed and because of that nothing gets displayed on the browser i.e an image in this case .Thankx in advance.
Don't fight the asynchronous nature of node.js, embrace it!
So you should fire off all your requests, marking each one as completed when the response arrives. When all requests are completed, render your images and body/html closing tags.
I don't usually work with node.js, so I can make some mistakes, but it may look like this:
res.write('<html><body>');
db.frames.find({str_id:story}).toArray(function(err,doc){
console.log(doc);
var completed = {};
for(var t = 0; t < doc.length; t++) {
var picid = doc[t].pic_id;
completed.picid = false;
console.log(picid);
db.pictures.find({_id: picid}).toArray(function(err, pic) {
// mark request as completed
completed.picid = pic;
// check if all requests completed
var all_finished = true;
for(var k in completed) {
if(completed[k] === false) {
all_finished = false;
break;
}
}
// render final markup
if(all_finished) {
for(var k in completed) {
var pic = completed[k];
res.write('<img src="'+pic[0].name+'"/>');
}
res.end('</body></html>);
}
});
}
})
just put the res.end('</body></html>'); inside your db.frames.find function. Check when you reached doc.length - 1 and then send the end command.

chrome extension connection issues

I have written an extension for google chrome and I have a bug I need a help solving.
what I do is using either a text selection or an input of text search for photos on flickr and then create a results tab.
The extension works most of the times. but sometimes it creates a blank tab with no results and when I repeat the same search it then shows results. I figured that it's something to do with the html files messaging maybe something to do with them communicating. I have to say that I always receive the results from flickr so that the request/responce with flickr works ok. Sometimes the error happens when I play with other tabs or do something on other tabs while waiting for results. can you please help me figure out where's the fault?
the background file:
function searchSelection(info,tab){
var updated;
if(info.selectionText==null){
var value = prompt("Search Flickr", "Type in the value to search");
updated=makeNewString(value);
}
else{
updated=makeNewString(info.selectionText);
}
var resultHtml;
var xhReq = new XMLHttpRequest();
xhReq.open(
"GET",
"http://api.flickr.com/services/rest/?method=flickr.photos.search&text="+updated+
"&api_key=a0a60c4e0ed00af8d70800b0987cae70&content_type=7&sort=relevance&per_page=500",
true);
xhReq.onreadystatechange = function () {
if (xhReq.readyState == 4) {
if (xhReq.status == 200) {
chrome.tabs.executeScript(tab.id, {code:"document.body.style.cursor='auto';"});
var photos = xhReq.responseXML.getElementsByTagName("photo");
if(photos.length==0){
alert("No results found for this selection");
chrome.tabs.executeScript(tab.id, {code:"document.body.style.cursor='auto';"});
return;
}
var myJSPhotos=[];
for(var i=0; i<photos.length; i++){
var data={"id":photos[i].getAttribute("id"),"owner":photos[i].getAttribute("owner"),
"secret":photos[i].getAttribute("secret"),"server":photos[i].getAttribute("server"),
"farm":photos[i].getAttribute("farm"),"title":photos[i].getAttribute("title")};
myJSPhotos[i]=data;
}
chrome.tabs.create({"url":"results.html"},function(thistab){
var port= chrome.tabs.connect(thistab.id);
port.postMessage({photos:myJSPhotos});
});
}
};
};
xhReq.send(null);
chrome.tabs.executeScript(tab.id, {code:"document.body.style.cursor='wait';"});
}
var context="selection";
var id = chrome.contextMenus.create({"title": "search Flickr", "contexts":[context,'page'],"onclick":searchSelection});
results html: has only a reference to the js file res.js
res.js :
chrome.extension.onConnect.addListener(function(port) {
port.onMessage.addListener(function(msg) {
//*****//
var photos=msg.photos;
createPage(photos);
});
});
I have to mention that when the tab is empty if I put alert on the //*****// part it won't
fire.
but when I print out the photos.length at the tab create call back function part it prints out the correct result.
Try to set "run_at":"document_start" option for your res.js in the manifest.
I think callback from chrome.tabs.create is fired right away without waiting for page scripts to be loaded, so you might try something like this instead:
//global vars
var createdTabId = null;
var myJSPhotos = null;
xhReq.onreadystatechange = function () {
//assign myJSPhotos to a global var
chrome.tabs.create({"url":"results.html"},function(thistab){
createdTabId = thistab.id;
});
}
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "complete" && tab.id == createdTabId) {
createdTabId = null;
//now page is loaded and content scripts injected
var port = chrome.tabs.connect(tab.id);
port.postMessage({photos:myJSPhotos});
}
});

Resources