The terminal out is:
but actually this is what I really want:
progressbar will alway be the fist line,and got a response,then show it at below.
anyway to fix that?
Nodejs:
var request = require('request');
var ProgressBar = require('progress');
var year=[14,15,16];
var month=[1,2,3,4,5,6,7];
var bar = new ProgressBar('Processing [:bar] :percent', {
complete: '=',
incomplete: '-',
width: 30,
total: year.length*month.length,
});
/*-------------------------------------*/
function init(year,month){
check(year,month);
}
function check(year,month){
var options = { method: 'POST',
url: 'http://dev.site/date.php',
formData:{year:year,month:month}
};
request(options, function (error, response, body) {
if (error) {
console.log(error);;
}
if (body=='A task #') {
bar.tick();
console.log('\n'+body+year+':'+month);
}else{
bar.tick();
}
})
}
/*-------------------------------------*/
for (var i = 0; i < year.length; i++) {
for (var n = 0; n < month.length; n++) {
init(year[i],month[n]);
}
}
Using ansi-escapes you may be able to do this.
Here's a standalone version:
const ProgressBar = require('progress');
const ansiEscapes = require('ansi-escapes');
const write = process.stdout.write.bind(process.stdout);
let bar = new ProgressBar('Processing [:bar] :percent', {
complete : '=',
incomplete : '-',
width : 30,
total : 100
});
// Start by clearing the screen and positioning the cursor on the second line
// (because the progress bar will be positioned on the first line)
write(ansiEscapes.clearScreen + ansiEscapes.cursorTo(0, 1));
let i = 0;
setInterval(() => {
// Save cursor position and move it to the top left corner.
write(ansiEscapes.cursorSavePosition + ansiEscapes.cursorTo(0, 0));
// Update the progress bar.
bar.tick();
// Restore the cursor position.
write(ansiEscapes.cursorRestorePosition);
// Write a message every 10 ticks.
if (++i % 10 === 0) {
console.log('Now at', i);
}
// We're done.
if (i === 100) {
process.exit(0);
}
}, 100);
Related
I've followed the sample code from https://github.com/alexa/skill-sample-nodejs-audio-player and gotten the example podcast player to play via my Amazon Echo.
How would one modify this code in order to tell Alexa to "Ask MySkill to Play $trackname". Instead of just playing from the top?
I'm very new to creating skills but I've read all the documentation and understand that this involves Audio Directives. However, I can't figure out what goes where.
In the sample code, the audioAssets.js contains a list of titles and urls. So for example, if I wanted to say "Play Episode 138" (one of the titles) - which files would I need to modify in order to do this?
'use strict';
var audioData = [
{
'title' : 'Episode 140',
'url' : 'https://feeds.soundcloud.com/stream/275202399-amazon-web- services-306355661-amazon-web-services.mp3'
},
{
'title' : 'Episode 139',
'url' : 'https://feeds.soundcloud.com/stream/274166909-amazon-web-services-306355661-aws-podcast-episode-139.mp3'
},
{
'title' : 'Episode 138',
'url' : 'https://feeds.soundcloud.com/stream/273105224-amazon-web-services-306355661-aws-podcast-episode-138.mp3'
},
{
'title' : 'Episode 137',
'url' : 'https://feeds.soundcloud.com/stream/272089501-amazon-web-services-306355661-aws-podcast-episode-137.mp3'
}
];
module.exports = audioData;
I'm assuming the code would go into stateHandlers.js but honestly I'm not sure.
'use strict';
var Alexa = require('alexa-sdk');
var audioData = require('./audioAssets');
var constants = require('./constants');
var stateHandlers = {
startModeIntentHandlers : Alexa.CreateStateHandler(constants.states.START_MODE, {
/*
* All Intent Handlers for state : START_MODE
*/
'LaunchRequest' : function () {
// Initialize Attributes
this.attributes['playOrder'] = Array.apply(null, {length: audioData.length}).map(Number.call, Number);
this.attributes['index'] = 0;
this.attributes['offsetInMilliseconds'] = 0;
this.attributes['loop'] = true;
this.attributes['shuffle'] = false;
this.attributes['playbackIndexChanged'] = true;
// Change state to START_MODE
this.handler.state = constants.states.START_MODE;
var message = 'Welcome to the AWS Podcast. You can say, play the audio to begin the podcast.';
var reprompt = 'You can say, play the audio, to begin.';
this.response.speak(message).listen(reprompt);
this.emit(':responseReady');
},
'PlayAudio' : function () {
if (!this.attributes['playOrder']) {
// Initialize Attributes if undefined.
this.attributes['playOrder'] = Array.apply(null, {length: audioData.length}).map(Number.call, Number);
this.attributes['index'] = 0;
this.attributes['offsetInMilliseconds'] = 0;
this.attributes['loop'] = true;
this.attributes['shuffle'] = false;
this.attributes['playbackIndexChanged'] = true;
// Change state to START_MODE
this.handler.state = constants.states.START_MODE;
}
controller.play.call(this);
},
'AMAZON.HelpIntent' : function () {
var message = 'Welcome to the AWS Podcast. You can say, play the audio, to begin the podcast.';
this.response.speak(message).listen(message);
this.emit(':responseReady');
},
'AMAZON.StopIntent' : function () {
var message = 'Good bye.';
this.response.speak(message);
this.emit(':responseReady');
},
'AMAZON.CancelIntent' : function () {
var message = 'Good bye.';
this.response.speak(message);
this.emit(':responseReady');
},
'SessionEndedRequest' : function () {
// No session ended logic
},
'Unhandled' : function () {
var message = 'Sorry, I could not understand. Please say, play the audio, to begin the audio.';
this.response.speak(message).listen(message);
this.emit(':responseReady');
}
}),
playModeIntentHandlers : Alexa.CreateStateHandler(constants.states.PLAY_MODE, {
/*
* All Intent Handlers for state : PLAY_MODE
*/
'LaunchRequest' : function () {
/*
* Session resumed in PLAY_MODE STATE.
* If playback had finished during last session :
* Give welcome message.
* Change state to START_STATE to restrict user inputs.
* Else :
* Ask user if he/she wants to resume from last position.
* Change state to RESUME_DECISION_MODE
*/
var message;
var reprompt;
if (this.attributes['playbackFinished']) {
this.handler.state = constants.states.START_MODE;
message = 'Welcome to the AWS Podcast. You can say, play the audio to begin the podcast.';
reprompt = 'You can say, play the audio, to begin.';
} else {
this.handler.state = constants.states.RESUME_DECISION_MODE;
message = 'You were listening to ' + audioData[this.attributes['playOrder'][this.attributes['index']]].title +
' Would you like to resume?';
reprompt = 'You can say yes to resume or no to play from the top.';
}
this.response.speak(message).listen(reprompt);
this.emit(':responseReady');
},
'PlayAudio' : function () { controller.play.call(this) },
'AMAZON.NextIntent' : function () { controller.playNext.call(this) },
'AMAZON.PreviousIntent' : function () { controller.playPrevious.call(this) },
'AMAZON.PauseIntent' : function () { controller.stop.call(this) },
'AMAZON.StopIntent' : function () { controller.stop.call(this) },
'AMAZON.CancelIntent' : function () { controller.stop.call(this) },
'AMAZON.ResumeIntent' : function () { controller.play.call(this) },
'AMAZON.LoopOnIntent' : function () { controller.loopOn.call(this) },
'AMAZON.LoopOffIntent' : function () { controller.loopOff.call(this) },
'AMAZON.ShuffleOnIntent' : function () { controller.shuffleOn.call(this) },
'AMAZON.ShuffleOffIntent' : function () { controller.shuffleOff.call(this) },
'AMAZON.StartOverIntent' : function () { controller.startOver.call(this) },
'AMAZON.HelpIntent' : function () {
// This will called while audio is playing and a user says "ask <invocation_name> for help"
var message = 'You are listening to the AWS Podcast. You can say, Next or Previous to navigate through the playlist. ' +
'At any time, you can say Pause to pause the audio and Resume to resume.';
this.response.speak(message).listen(message);
this.emit(':responseReady');
},
'SessionEndedRequest' : function () {
// No session ended logic
},
'Unhandled' : function () {
var message = 'Sorry, I could not understand. You can say, Next or Previous to navigate through the playlist.';
this.response.speak(message).listen(message);
this.emit(':responseReady');
}
}),
remoteControllerHandlers : Alexa.CreateStateHandler(constants.states.PLAY_MODE, {
/*
* All Requests are received using a Remote Control. Calling corresponding handlers for each of them.
*/
'PlayCommandIssued' : function () { controller.play.call(this) },
'PauseCommandIssued' : function () { controller.stop.call(this) },
'NextCommandIssued' : function () { controller.playNext.call(this) },
'PreviousCommandIssued' : function () { controller.playPrevious.call(this) }
}),
resumeDecisionModeIntentHandlers : Alexa.CreateStateHandler(constants.states.RESUME_DECISION_MODE, {
/*
* All Intent Handlers for state : RESUME_DECISION_MODE
*/
'LaunchRequest' : function () {
var message = 'You were listening to ' + audioData[this.attributes['playOrder'][this.attributes['index']]].title +
' Would you like to resume?';
var reprompt = 'You can say yes to resume or no to play from the top.';
this.response.speak(message).listen(reprompt);
this.emit(':responseReady');
},
'AMAZON.YesIntent' : function () { controller.play.call(this) },
'AMAZON.NoIntent' : function () { controller.reset.call(this) },
'AMAZON.HelpIntent' : function () {
var message = 'You were listening to ' + audioData[this.attributes['index']].title +
' Would you like to resume?';
var reprompt = 'You can say yes to resume or no to play from the top.';
this.response.speak(message).listen(reprompt);
this.emit(':responseReady');
},
'AMAZON.StopIntent' : function () {
var message = 'Good bye.';
this.response.speak(message);
this.emit(':responseReady');
},
'AMAZON.CancelIntent' : function () {
var message = 'Good bye.';
this.response.speak(message);
this.emit(':responseReady');
},
'SessionEndedRequest' : function () {
// No session ended logic
},
'Unhandled' : function () {
var message = 'Sorry, this is not a valid command. Please say help to hear what you can say.';
this.response.speak(message).listen(message);
this.emit(':responseReady');
}
})
};
module.exports = stateHandlers;
var controller = function () {
return {
play: function () {
/*
* Using the function to begin playing audio when:
* Play Audio intent invoked.
* Resuming audio when stopped/paused.
* Next/Previous commands issued.
*/
this.handler.state = constants.states.PLAY_MODE;
if (this.attributes['playbackFinished']) {
// Reset to top of the playlist when reached end.
this.attributes['index'] = 0;
this.attributes['offsetInMilliseconds'] = 0;
this.attributes['playbackIndexChanged'] = true;
this.attributes['playbackFinished'] = false;
}
var token = String(this.attributes['playOrder'][this.attributes['index']]);
var playBehavior = 'REPLACE_ALL';
var podcast = audioData[this.attributes['playOrder'][this.attributes['index']]];
var offsetInMilliseconds = this.attributes['offsetInMilliseconds'];
// Since play behavior is REPLACE_ALL, enqueuedToken attribute need to be set to null.
this.attributes['enqueuedToken'] = null;
if (canThrowCard.call(this)) {
var cardTitle = 'Playing ' + podcast.title;
var cardContent = 'Playing ' + podcast.title;
this.response.cardRenderer(cardTitle, cardContent, null);
}
this.response.audioPlayerPlay(playBehavior, podcast.url, token, null, offsetInMilliseconds);
this.emit(':responseReady');
},
stop: function () {
/*
* Issuing AudioPlayer.Stop directive to stop the audio.
* Attributes already stored when AudioPlayer.Stopped request received.
*/
this.response.audioPlayerStop();
this.emit(':responseReady');
},
playNext: function () {
/*
* Called when AMAZON.NextIntent or PlaybackController.NextCommandIssued is invoked.
* Index is computed using token stored when AudioPlayer.PlaybackStopped command is received.
* If reached at the end of the playlist, choose behavior based on "loop" flag.
*/
var index = this.attributes['index'];
index += 1;
// Check for last audio file.
if (index === audioData.length) {
if (this.attributes['loop']) {
index = 0;
} else {
// Reached at the end. Thus reset state to start mode and stop playing.
this.handler.state = constants.states.START_MODE;
var message = 'You have reached at the end of the playlist.';
this.response.speak(message).audioPlayerStop();
return this.emit(':responseReady');
}
}
// Set values to attributes.
this.attributes['index'] = index;
this.attributes['offsetInMilliseconds'] = 0;
this.attributes['playbackIndexChanged'] = true;
controller.play.call(this);
},
playPrevious: function () {
/*
* Called when AMAZON.PreviousIntent or PlaybackController.PreviousCommandIssued is invoked.
* Index is computed using token stored when AudioPlayer.PlaybackStopped command is received.
* If reached at the end of the playlist, choose behavior based on "loop" flag.
*/
var index = this.attributes['index'];
index -= 1;
// Check for last audio file.
if (index === -1) {
if (this.attributes['loop']) {
index = audioData.length - 1;
} else {
// Reached at the end. Thus reset state to start mode and stop playing.
this.handler.state = constants.states.START_MODE;
var message = 'You have reached at the start of the playlist.';
this.response.speak(message).audioPlayerStop();
return this.emit(':responseReady');
}
}
// Set values to attributes.
this.attributes['index'] = index;
this.attributes['offsetInMilliseconds'] = 0;
this.attributes['playbackIndexChanged'] = true;
controller.play.call(this);
},
loopOn: function () {
// Turn on loop play.
this.attributes['loop'] = true;
var message = 'Loop turned on.';
this.response.speak(message);
this.emit(':responseReady');
},
loopOff: function () {
// Turn off looping
this.attributes['loop'] = false;
var message = 'Loop turned off.';
this.response.speak(message);
this.emit(':responseReady');
},
shuffleOn: function () {
// Turn on shuffle play.
this.attributes['shuffle'] = true;
shuffleOrder((newOrder) => {
// Play order have been shuffled. Re-initializing indices and playing first song in shuffled order.
this.attributes['playOrder'] = newOrder;
this.attributes['index'] = 0;
this.attributes['offsetInMilliseconds'] = 0;
this.attributes['playbackIndexChanged'] = true;
controller.play.call(this);
});
},
shuffleOff: function () {
// Turn off shuffle play.
if (this.attributes['shuffle']) {
this.attributes['shuffle'] = false;
// Although changing index, no change in audio file being played as the change is to account for reordering playOrder
this.attributes['index'] = this.attributes['playOrder'][this.attributes['index']];
this.attributes['playOrder'] = Array.apply(null, {length: audioData.length}).map(Number.call, Number);
}
controller.play.call(this);
},
startOver: function () {
// Start over the current audio file.
this.attributes['offsetInMilliseconds'] = 0;
controller.play.call(this);
},
reset: function () {
// Reset to top of the playlist.
this.attributes['index'] = 0;
this.attributes['offsetInMilliseconds'] = 0;
this.attributes['playbackIndexChanged'] = true;
controller.play.call(this);
}
}
}();
function canThrowCard() {
/*
* To determine when can a card should be inserted in the response.
* In response to a PlaybackController Request (remote control events) we cannot issue a card,
* Thus adding restriction of request type being "IntentRequest".
*/
if (this.event.request.type === 'IntentRequest' && this.attributes['playbackIndexChanged']) {
this.attributes['playbackIndexChanged'] = false;
return true;
} else {
return false;
}
}
function shuffleOrder(callback) {
// Algorithm : Fisher-Yates shuffle
var array = Array.apply(null, {length: audioData.length}).map(Number.call, Number);
var currentIndex = array.length;
var temp, randomIndex;
while (currentIndex >= 1) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temp = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temp;
}
callback(array);
}
You need to create a custom intent and custom slot to your skill.
Go to your interaction model
add this
{
"intent": "PodcastIntent",
"slots": [
{
"name": "Podcast",
"type": "AMAZON.NUMBER"
}
]
}
In your sample Utterances add
PodcastIntent play episode {Podcast}
This will let user to able to say play episode 140 etc...
Then in your var stateHandlers = {
startModeIntentHandlers create a new function for PodcastIntent
That part is up to you , the code I write wont work but should give you some idea, maybe something like
'PodcastIntent' : function () { var podname = this.handlerContext.event.request.intent.slots.Podcast.value;
//this should get the value from alexa if user say play episode 140 , podname sould be 140
//then in your audiodata dictionary you need to find episode 140
//again this part is your work
//when you find the url for episode 140
//you can set your state to _PLAY_MODE
//then pass the url to audio player
response().audioPlayerPlay('REPLACE_ALL', podcast.audioURL, token, previousToken, 0);
check the https://github.com/alexa for the AMAZON.NUMBER intents...
I was able to set specific indexes when I modified the intents within "playModeIntentHandlers." In the example, they were only setting this.attributes['index'] within "startModeIntentHandlers" - which in my case were never being called.
There are several intents that go in each handler, but I'm only showing 1 (PlaySongIntent) as an example.
var stateHandlers = {
startModeIntentHandlers : Alexa.CreateStateHandler(constants.states.START_MODE, {
'PlaySongIntent' : function () {
if (!this.attributes['playOrder']) {
// Initialize Attributes if undefined.
this.attributes['playOrder'] = Array.apply(null, {length: audioData.length}).map(Number.call, Number);
this.attributes['index'] = 1; //CHANGING THIS NUMBER NEVER WORKED FOR ME.
this.attributes['offsetInMilliseconds'] = 0;
this.attributes['loop'] = false;
this.attributes['shuffle'] = false;
this.attributes['playbackIndexChanged'] = true;
// Change state to START_MODE
this.handler.state = constants.states.START_MODE;
}
controller.play.call(this);
},...}),
playModeIntentHandlers : Alexa.CreateStateHandler(constants.states.PLAY_MODE, {
'PlaySongIntent' : function () {
this.attributes['index'] = 1; //HERE IS WHERE THE INDEX STICKS.
this.attributes['offsetInMilliseconds'] = 0;
this.attributes['playbackIndexChanged'] = true;
controller.play.call(this);
},...})
}
I am using RecordRTC from recording webrtc meeting. After implementing recording, when I test this application if both client are on the same system then its working fine. When I test this application on different system it isn't working fine and meeting is not recorded.
Here this is my code from stop recording client side.
recordRTC.stopRecording(function (videoURL) {
console.log('recordRTC.stopRecording Function inside');
SelectedFile = recordRTC.getBlob();
$('#uploadForm').append('#attachmentFileId', recordRTC.getBlob());
StartUpload();
});
var FReader;
var Name = "Meeting" + "_" + Date.now() + ".webm";
function StartUpload()
{
FReader = new FileReader();
FReader.onload = function (evnt)
{
socket.emit('Upload', { 'Name': Name, Data: evnt.target.result });
}
socket.emit('Start', { 'Name': Name, 'Size': SelectedFile.size });
}
socket.on('MoreData', function (data)
{
var Place = data['Place'] * 524288; //The Next Blocks Starting Position
var NewFile; //The Variable that will hold the new Block of Data
if (SelectedFile.webkitSlice)
NewFile = SelectedFile.webkitSlice(Place, Place + Math.min(524288, (SelectedFile.size - Place)));
else
NewFile = SelectedFile.slice(Place, Place + Math.min(524288, (SelectedFile.size - Place)));
FReader.readAsBinaryString(NewFile);
});
Server Side Code
I get this from here.
socket.on('Start', function (data) { //data contains the variables that we passed through in the html file
var Name = data['Name'];
Files[Name] = { //Create a new Entry in The Files Variable
FileSize : data['Size'],
Data : "",
Downloaded : 0
}
var Place = 0;
try{
var Stat = fs.statSync('Temp/' + Name);
if(Stat.isFile())
{
Files[Name]['Downloaded'] = Stat.size;
Place = Stat.size / 524288;
}
}
catch(er){} //It's a New File
fs.open("Temp/" + Name, 'a', 0755, function(err, fd){
if(err)
{
console.log(err);
}
else
{
Files[Name]['Handler'] = fd; //We store the file handler so we can write to it later
socket.emit('MoreData', { 'Place' : Place, Percent : 0 });
}
});
});
socket.on('Upload', function (data){
var Name = data['Name'];
Files[Name]['Downloaded'] += data['Data'].length;
Files[Name]['Data'] += data['Data'];
if(Files[Name]['Downloaded'] == Files[Name]['FileSize']) //If File is Fully Uploaded
{
fs.write(Files[Name]['Handler'], Files[Name]['Data'], null, 'Binary', function(err, Writen){
var input = fs.createReadStream("Temp/" + Name);
var output = fs.createWriteStream("Video/" + Name);
//util.pump(readableStream, writableStream, [callback])
//Deprecated: Use readableStream.pipe(writableStream)
input.pipe(output);
input.on("end", function() {
console.log("end");
fs.unlink("Temp/" + Name, function ()
{ //This Deletes The Temporary File
console.log("unlink this file:",Name );
//socket.emit('Done', {'Image' : 'Video/' + Name + '.jpg'});
});
});
});
}
else if(Files[Name]['Data'].length > 10485760){ //If the Data Buffer reaches 10MB
fs.write(Files[Name]['Handler'], Files[Name]['Data'], null, 'Binary', function(err, Writen){
Files[Name]['Data'] = ""; //Reset The Buffer
var Place = Files[Name]['Downloaded'] / 524288;
var Percent = (Files[Name]['Downloaded'] / Files[Name]['FileSize']) * 100;
socket.emit('MoreData', { 'Place' : Place, 'Percent' : Percent});
});
}
else
{
var Place = Files[Name]['Downloaded'] / 524288;
var Percent = (Files[Name]['Downloaded'] / Files[Name]['FileSize']) * 100;
socket.emit('MoreData', { 'Place' : Place, 'Percent' : Percent});
}
});
If both clients are on same machine/system its working fine, but if both clients are on different system then meeting is not recorded.
I want to shutdown my computer 1 min after I push button, and if I push button again it will shutdown after it push last time.
for(var i=1; i<=10; ++i){
setDelay();
}
var nn;
function setDelay(){
clearTimeout(nn);
nn = setTimeout(function(){
console.log("shutdown");
}, 60000);
}
But my code have another "setTimeout" too. Will it work fine ?, or will it damage my other setTimeout ?
I'd suggest you create an object that allows you to add time to it:
function Timer(t, fn) {
this.fn = fn;
this.time = Date.now() + t;
this.updateTimer();
}
Timer.prototype.addTime = function(t) {
this.time += t;
this.updateTimer();
}
Timer.prototype.stop = function() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
}
Timer.prototype.updateTimer = function() {
var self = this;
this.stop();
var delta = this.time - Date.now();
if (delta > 0) {
this.timer = setTimeout(function() {
self.timer = null;
self.fn();
}, delta);
}
}
Then, you can use it like this:
var timer = new Timer(60000, function() {
console.log("shutdown");
});
// add one second of time
timer.addTime(1000);
// add one minute of time
timer.addTime(1000 * 60);
I'm trying to alter the interval by using a the variable 'counter'.
The Twitter stream is working and the LED is blinking.
I have removed all the twitter credentials.
Any help would be greatly appreciated!
Here is my code:
var Gpio = require('onoff').Gpio;
var Twit = require('twit');
var T = new Twit({
consumer_key: '' // Your Consumer Key
, consumer_secret: '' // Your Co$
, access_token: '' // Your Ac$
, access_token_secret: '' // Your Access $
});
var stream = T.stream('statuses/filter', { track: '#blessed, #peace'})
led = new Gpio(17, 'out'),
counter = 500;
stream.start();
var iv = setInterval(function(){
led.writeSync(led.readSync() === 0 ? 1 : 0);
}, counter);
stream.on('tweet', function(tweet) {
if(tweet.text.indexOf('#blessed') > -1) {
console.log("blessed");
counter += 100;
} else if (tweet.text.indexOf('#peace') > -1) {
console.log("peace");
counter -= 100;
}
});
Once you've made the setInterval() call, the timer's locked in, you can't change it. This is how arguments to functions work: Changing them after the fact does nothing. There is no binding to the value supplied, numbers get passed in as a copy.
You'll need to clear and re-set the timer. setInterval() returns a handle you can pass through to clearInterval() to turn it off. You've captured this, so you just need to use it:
var iv;
function blink(interval) {
if (iv) {
clearInterval(iv);
}
iv = setInterval(function() {
led.writeSync(led.readSync() === 0 ? 1 : 0);
}, interval);
}
Then use this function to reset it:
counter -= 100;
blink(counter);
Just make sure you don't go negative.
I added a check to counter and interval:
var Gpio = require('onoff').Gpio;
var Twit = require('twit');
var T = new Twit({
consumer_key: '' // Your Consumer Key
, consumer_secret: '' // Your Co$
, access_token: '' // Your Ac$
, access_token_secret: '' // Your Access $
});
var stream = T.stream('statuses/filter', { track: '#blessed, #peace'})
led = new Gpio(17, 'out'),
counter = 200;
stream.start();
var iv;
function blink(interval) {
if (iv) {
clearInterval(iv);
}
if (interval <= 100) {
interval = 100;
}
console.log("interval = " + interval);
iv = setInterval(function(){
led.writeSync(led.readSync() === 0 ? 1 : 0);
}, interval);
}
stream.on('tweet', function(tweet) {
if(tweet.text.indexOf('#blessed') > -1) {
console.log("blessed");
counter += 100;
if (counter <= 100) {
counter = 100;
}
console.log(counter);
blink(counter);
} else if (tweet.text.indexOf('#peace') > -1) {
console.log("peace");
counter -= 100;
if (counter <= 100) {
counter = 100;
}
console.log(counter);
blink(counter);
}
});
I am pulling information from some collections in mongo that contain node and edge data. First i must get the node so i can grab its edges. Once i have a list of edges i then go back out and grab more nodes (etc.. based on a depth value). The following code is an loose example of how i am attempting to use async.waterfall and the task list.
Initially i have only a single task but once i make my first query i add to the task array. Unfortunately this does not seem to register with async and it does not continue to process the tasks i am adding.
Is there a better way to do this?
var async = require('async')
var mongoose = require('mongoose')
var _ = requrie('underscore')
var Client = this.Mongo.connect(/*path to mongo*/)
var Node = mongoose.Schema({
id : String,
graph_id : String
})
var Edge = mongoose.Schema({
id : String,
source_id : String,
destination_id : String
})
var Nodes = Client.model('myNode', Node)
var Edges = Client.model('myEdge', Edge)
var funcs = []
var round = 1
var depth = 2
var query = {
node : {
id : '12345'
},
edge : {
id : '12345'
}
}
var addTask = function(Nodes, Edges, query, round, depth) {
return function(callback) {
queryData(Nodes, Edges, query, function(err, node_list) {
if(depth > round) {
round++
function_array.push(addTask(Nodes, Edges, query, round, depth))
}
})
}
}
var queryData = function(Nodes, Edges, query, cb) {
async.waterfall([
function(callback) {
Nodes.find(query.node, function(err, nodes) {
var node_keys = _.map(nodes, function(node) {
return node.id
})
callback(null, nodes, node_keys)
})
},
function(nodes, node_keys, callback) {
query.edge.$or = [ {'source_id' : {$in:node_keys}}, {'destination_id' : {$in:node_keys}} ]
Edges.find(query.edge, function(err, edges) {
var edge_keys = _.map(edges, function(edge) {
if(edge['_doc']['source_id'] != query.node.id) {
return edge['_doc']['source_id']
} else {
return edge['_doc']['destination_id']
}
callback(null, nodes, edges, node_keys, edge_keys)
})
})
}
], function(err, nodes, edges, node_keys, edge_keys) {
// update the results object then...
cb(null, _.uniq(edge_keys)
})
}
var function_array = []
function_array.push(addTask(Nodes, Edges, query, round, depth))
async.waterfall(function_array, function(err) {
Client.disconnect()
//this should have run more than just the initial task but does not
})
--------------------- UPDATE ---------------------------
So after playing around with trying to get Async waterfall or series to do this by adding trailing functions I decided to switch to using async.whilst and am now happy with the solution.
function GraphObject() {
this.function_array = []
}
GraphObject.prototype.doStuff = function() {
this.function_array.push(this.buildFunction(100))
this.runTasks(function(err) {
console.log('done with all tasks')
}
}
GraphObject.prototype.buildFunction = function(times) {
return function(cb) {
if(times != 0) {
this.function_array.push(this.buildFunction(times - 1))
}
cb(null)
}
}
GraphObject.prototype.runTasks = function(cb) {
var tasks_run = 0
async.whilst(
function(){
return this.function_array.length > 0
}.bind(this),
function(callback) {
var func = this.function_array.shift()
func.call(this, function(err) {
tasks_run++
callback(err)
})
}.bind(this),
function(err) {
console.log('runTasks ran '+tasks_run+' tasks')
if(err) {
cb(500)
}
cb(null)
}.bind(this)
)
}
A task in your function_array can only add a new task to the array provided it is NOT the last task in the array.
In your case, your function_array contained only 1 task. That task itself cannot add additional tasks since it's the last task.
The solution is to have 2 tasks in the array. A startTask to bootstrap the process, and a finalTask that is more of a dummy task. In that case,
function_array = [startTask, finalTask];
Then startTask would add taskA, taskB will add task C and eventually
function_array = [startTask, taskA, taskB, taskC, finalTask];
The sample code below that illustrates the concepts.
var async = require('async');
var max = 6;
var nodeTask = function(taskId, value, callback){
var r = Math.floor(Math.random() * 20) + 1;
console.log("From Node Task %d: %d", taskId, r);
// add an edge task
if (taskId < max) {
function_array.splice(function_array.length-1, 0, edgeTask);
}
callback(null, taskId + 1, value + r);
};
var edgeTask = function(taskId, value, callback){
var r = Math.floor(Math.random() * 20) + 1;
console.log("From Edge Task %d: %d", taskId, r);
// add a node task
if (taskId < max) {
function_array.splice(function_array.length-1, 0, nodeTask);
}
callback(null, taskId + 1, value + r);
};
var startTask = function(callback) {
function_array.splice(function_array.length-1, 0, nodeTask);
callback(null, 1, 0);
};
var finalTask = function(taskId, value, callback) {
callback(null, value);
};
var function_array = [startTask, finalTask];
async.waterfall(function_array, function (err, result) {
console.log("Sum is ", result);
});