Hi I am displaying a notification based on the output of a server file.The output of the server file is being checked for a period of 5 min interval.Now what I need is that when the output changes at any instant, notification should be automatically be closed at that moment.What I am trying to convey that if the output of the server file is 0,the notification is being displayed in every 5 min. If the output is 1, then notification will not be shown anymore.The problem of my code is that unless I close the notification manually it won't be closed automatically even if the output is 1. Anyone please help me to close my notification automatically.
here is my background.js
var myNotificationID = null;
var oldChromeVersion = !chrome.runtime;
function getGmailUrl() {
return "http://calpinemate.com/";
}
function isGmailUrl(url) {
return url.indexOf(getGmailUrl()) == 0;
}
chrome.browserAction.onClicked.addListener(function(tab) {
if(!localStorage.username){
chrome.windows.create({url : "userinfo.html",type: "popup", height: 200, width:300 , top :400 , left : 800});
}
else{
chrome.tabs.query({
url: "http://calpinemate.com/*",
currentWindow: true
},
function(tabs) {
if (tabs.length > 0) {
var tab = tabs[0];
console.log("Found (at least one) Gmail tab: " + tab.url);
console.log("Focusing and refreshing count...");
chrome.tabs.update(tab.id, { active: true });
updateIcon();
}
else {
console.log("Could not find Gmail tab. Creating one...");
chrome.tabs.create({ url: getGmailUrl() });
updateIcon();
}
});
}
});
function onInit() {
console.log('onInit');
updateIcon();
if (!oldChromeVersion) {
chrome.alarms.create('watchdog', {periodInMinutes:5});
}
}
function onAlarm(alarm) {
console.log('Got alarm', alarm);
if (alarm && alarm.name == 'watchdog') {
onWatchdog();
}
else {
updateIcon();
}
}
function onWatchdog() {
chrome.alarms.get('refresh', function(alarm) {
if (alarm) {
console.log('Refresh alarm exists. Yay.');
}
else {
console.log('Refresh alarm doesn\'t exist!? ' +
'Refreshing now and rescheduling.');
updateIcon();
}
});
}
if (oldChromeVersion) {
updateIcon();
onInit();
}
else {
chrome.runtime.onInstalled.addListener(onInit);
chrome.alarms.onAlarm.addListener(onAlarm);
}
function updateIcon(){
var urlPrefix = 'http://www.calpinemate.com/employees/attendanceStatus/';
var urlSuffix = '/2';
var req = new XMLHttpRequest();
req.addEventListener("readystatechange", function() {
if (req.readyState == 4) {
if (req.status == 200) {
var item=req.responseText;
if(item==1){
chrome.browserAction.setIcon({path:"calpine_logged_in.png"});
chrome.browserAction.setBadgeBackgroundColor({color:[190, 190, 190, 230]});
chrome.browserAction.setBadgeText({text:""});
chrome.notifications.clear(id1);//this is not working
}
else{
chrome.browserAction.setIcon({path:"calpine_not_logged_in.png"});
chrome.browserAction.setBadgeBackgroundColor({color:[190, 190, 190, 230]});
chrome.browserAction.setBadgeText({text:""});
chrome.notifications.create(
'id1',{
type: 'basic',
iconUrl: '/calpine_not_logged_in.png',
title: 'Warning : Attendance',
message: 'Please mark your Attendance !',
buttons: [{ title: 'Mark',
iconUrl: '/tick.jpg'
},{ title: 'Ignore',
iconUrl: '/cross.jpg'}],
priority: 0},
function(id) { myNotificationID = id;}
);
chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
if (notifId === myNotificationID) {
if (btnIdx === 0) {
window.open("http://www.calpinemate.com/");
} else if (btnIdx === 1) {
notification.close();
}
}
});
chrome.notifications.onClosed.addListener(function() {
notification.close();
});
}
}
else {
// Handle the error
alert("ERROR: status code " + req.status);
}
}
});
var url = urlPrefix + encodeURIComponent(localStorage.username) + urlSuffix;
req.open("GET", url);
req.send(null);
}
Two possible problems:
You pass an undefined variable named id1 in chrome.notifications.clear(), when you actually mean the string 'id1'.
According to the docs on chrome.notifications.clear() method, the second argument (callback function) is not optional, yet you fail to supply one.
One possible solution:
// Replace that line:
chrome.notifications.clear(id1);//this is not working
// With this line:
chrome.notifications.clear('id1', function(){});//this is working perfectly
// Or with this line:
chrome.notifications.clear(myNotificationID, function(){});//this is working perfectly
BTW, you don't need to provide a notification ID yourself.
You can replace: chrome.notifications.create('id1',...
with: chrome.notifications.create('',...
(and then, of course, use: chrome.notifications.clear(myNotificationID,...)
Related
I am currently using the Microsoft Bot Framework with node.js to write a bot that traverses a decision tree through an API. I want to allow the user to cancel the tree at any point in the dialog, so that he doesn't have to go through the entire (possibly huge) tree to exit. Because i need to send a message to the API if the session is closed, i am using Dialog.beginDialogAction() to start a "cancel"-Dialog, instead of Dialog.cancelAction(), so that i can prompt the user to confirm as well as close the session.
Now that i have that in place, canceling the tree works just fine, but if the user chooses to say "no" to the confirmation prompt and the bot should actually re-prompt the last question, it sometimes uses the "no" to answer the previous question automatically (or throws an error). This only appears if the valueType of the question is "string" and a Prompts.choice dialog is shown, for Prompts.number and Prompts.time the expected behaviour is produced.
I have searched any Documentation i could find, but no information about some Prompts not supporting DialogActions or anything like that. I am only using session.beginDialog, session.endDialog, session.endConversation and builder.Prompts to control the dialog stack.
Code looks like this:
//This dialog gets the next question node of the tree passed in args[1].
bot.dialog('select', [
function(session, args, next) {
//Depending on the value type of the question, different prompts are used.
switch (args[1].valueType) {
case "string":
builder.Prompts.choice(session, args[1].text, args[1].answerValues, {
listStyle: builder.ListStyle.button,
maxRetries: 0
});
break;
case "number":
builder.Prompts.number(session, args[1].text, {
integerOnly: true,
maxValue: 100,
minValue: 0
})
break;
case "datetime":
builder.Prompts.time(session, message + "\nPlease enter a date in the format 'yyyy-mm-dd'.");
break;
}
},
function(session, results) {
//Use the answer to proceed the tree.
//...
//With the new question node start over.
session.beginDialog('select', [sessionId, questionNode]);
}
]).beginDialogAction('cancelSelect', 'cancel', {
matches: /^stop$/i
});
//This dialog is used for cancelling.
bot.dialog('cancel', [
function(session, next) {
builder.Prompts.confirm(session, 'Do you really want to quit?');
},
function(session, results) {
if (results.response) {
finishSession();
session.endConversation('Session was closed.')
} else {
//Here the bot should stop this cancel-Dialog and reprompt the previous question
session.endDialog();
}
}
])
But instead of re-prompting, the bot jumps to function (session, results) in the 'select'-Dialog, where it tries to parse the answer "no" and obviously fails.
Here the full copy of my app.js. You wont be able to run it without mocking the esc-API of our product, but it shows that i am only using session.beginDialog, session.endDialog, session.endConversation and builder.Prompts. The only changes i did were to remove private information and translate messages to english.
/*---------
-- Setup --
---------*/
//esc and esc_auth are product specific, so obviously i cant share them. They handle the API of our product.
const esc = require("./esc");
const esc_auth = require("./esc_auth");
var restify = require("restify");
var builder = require("botbuilder");
var server = restify.createServer();
server.listen(process.env.PORT || process.env.port || 3978, function() {
console.log(`${server.name} listening to ${server.url}`);
});
var connector = new builder.ChatConnector({
//Cant share these as well
appId: "",
appPassword: ""
});
server.post("/api/messages", connector.listen());
var esc_header;
var esc_session;
var esc_attribs = {};
var treeNames = [];
/*---------
-- Start --
---------*/
//This function is called when no other dialog is currently running.
//It gets the authorization token from the API, reads concepts from the input and searches for matching decision trees.
//If not concepts or trees were found, a text search on the API is cone.
var bot = new builder.UniversalBot(connector, [
function(session) {
var esc_token;
esc_attribs = {};
console.log("Getting token...");
esc.escAccessToken(esc_auth.esc_system, esc_auth.esc_apiUser)
.then(function(result) {
esc_token = result;
esc_header = {
"Content-Type": "application/json",
"Authorization": "Bearer " + esc_token
};
console.log("Got token.");
//Look for concepts in the message.
esc.escAnnotateQuery(esc_header, session.message.text)
.then(function(result) {
for(i in result.concepts) {
for(j in result.concepts[i]) {
esc_attribs[i] = j;
}
}
//If concepts were found, look for trees and solutions with them
if(Object.keys(esc_attribs).length > 0) {
esc.escSearchIndexWithConcepts(esc_header, esc_attribs)
.then(function(result) {
var treeIds = [];
treeNames = [];
result = result;
result.records.forEach(function(entry) {
//Check which tree the found tree is or found solution is in.
if(entry.DecisionTree && !treeIds.includes(entry.DecisionTree)) {
treeIds.push(entry.DecisionTree);
}
})
if(treeIds.length != 0) {
esc.escSearchTrees(esc_header)
.then(function(result) {
console.log("Trees found.");
result.records.forEach(function(tree) {
if(treeIds.includes(tree.DecisionTree)) {
treeNames.push({id:tree.DecisionTree, name: tree.Label})
console.log("Tree: ", tree.DecisionTree, tree.Label);
}
})
session.beginDialog("tree", treeNames);
})
} else {
console.log("No tree found for " + session.message.text);
treeNames = [];
session.beginDialog("textSearch");
return;
}
})
} else {
console.log("No concepts found.");
session.beginDialog("textSearch");
return;
}
})
})
},
function(session, results) {
session.endConversation("You may now start a new search.");
}
]);
//Searches for trees by text.
bot.dialog("textSearch", [
function(session) {
session.send("No concepts were found in your input.");
builder.Prompts.confirm(session, "Start a text search instead?", {"listStyle": builder.ListStyle.button});
},
function(session, results) {
if(results.response) {
builder.Prompts.text(session, "Please enter your new search prompt in keywords.")
} else {
session.endDialog("Ok, back to concept search.")
}
},
function(session) {
//Search gives better results without mutated vowels
esc.escSearchIndex(esc_header, undoMutation(session.message.text))
.then(function(result) {
var treeIds = [];
treeNames = [];
result.records.forEach(function(entry) {
//Check which tree the found document is in.
if(entry.DecisionTree && !treeIds.includes(entry.DecisionTree)) {
treeIds.push(entry.DecisionTree);
}
})
if(treeIds.length != 0) {
esc.escSearchTrees(esc_header)
.then(function(result) {
console.log("Trees found.");
result.records.forEach(function(tree) {
if(treeIds.includes(tree.DecisionTree)) {
treeNames.push({id:tree.DecisionTree, name: tree.Label})
console.log("Tree: ", tree.DecisionTree, tree.Label);
}
})
session.beginDialog("tree", treeNames);
})
} else {
console.log("No tree found for " + session.message.text);
treeNames = [];
session.endConversation("No trees were found for this search.");
}
})
}
])
//The cancel dialog.
bot.dialog("cancel", [
function(session) {
builder.Prompts.confirm(session, "Do you really want to cancel?", {"listStyle": builder.ListStyle.button});
},
function(session, results) {
if(results.response) {
if(esc_session) {
esc.escFinishSession(esc_header, esc_session.sessionId)
.then(function(result) {
esc_session = undefined;
session.endConversation("Session was cancelled.")
})
} else {
session.endConversation("Session was cancelled.")
}
} else {
session.endDialog();
}
}
])
/*-------------------------
-- Decision tree dialogs --
-------------------------*/
//This dialog presents the found decision trees and lets the user select one.
bot.dialog("tree", [
function(session, treeArray) {
var opts = [];
treeArray.forEach(function(t) {
opts.push(t.name);
});
builder.Prompts.choice(session, "Following trees were found:", opts, {listStyle: builder.ListStyle.button})
},
function(session, results) {
let answer = results.response.entity;
console.log("Tree selected:", answer);
let id;
treeNames.forEach(function(t) {
if(t.name === answer && !id) {
id = t.id;
}
})
console.log("Starting session...");
esc.escStartSession(esc_header, id, esc_attribs)
.then(function(result) {
esc_session = result;
for(i in esc_session.concepts) {
for(j in esc_session.concepts[i]) {
esc_attribs[i] = j;
}
}
console.log("Started session.");
session.beginDialog(esc_session.questions[0].nodeType,[esc_session.sessionId, esc_session.questions[0]]);
})
.catch(function(err) {
console.log("Error starting ESC session.");
console.log(err);
})
}
]).beginDialogAction("cancelTree", "cancel", {matches: /^cancel$|^end$|^stop$|^halt/i});
//This dialog is for selection answers on a question node. It also saves recognized concepts within the answer.
bot.dialog("select", [
function(session, args) {
console.log("Select");
message = args[1].text;
attach(args[1].memo["Memo_URL"]);
session.userData = args;
var opts = new Array();
switch(args[1].valueType) {
case "string":
for(var i = 0; i < args[1].answerValues.length; i++) {
opts[i] = args[1].answerValues[i].value;
}
builder.Prompts.choice(session, message, opts, {listStyle: builder.ListStyle.button, maxRetries: 0});
break;
case "number":
for(var i = 0; i < args[1].answerIntervals.length; i++) {
opts[i] = args[1].answerIntervals[i].value;
}
builder.Prompts.number(session, message, {integerOnly: true, maxValue: 100, minValue: 0});
break;
case "datetime":
for(var i = 0; i < args[1].answerIntervals.length; i++) {
opts[i] = args[1].answerIntervals[i].value;
}
builder.Prompts.time(session, message + "\nPlease enter a date in format 'yyyy-mm-dd'.");
break;
}
},
function(session, results) {
let args = session.userData;
let answer;
//An answer was given.
if(results.response != null && results.response.entity != null) {
answer = results.response.entity;
} else if (results.response != null) {
answer = results.response;
} else {
//No answer (to a choice prompt) was given, check if concepts were recognized and try again.
}
esc.escAnnotateQuery(esc_header, session.message.text)
.then(function(result) {
for(i in result.concepts) {
for(j in result.concepts[i]) {
esc_attribs[i] = j;
}
}
console.log("Proceeding tree with answer %s", answer);
esc.escProceedTree(esc_header, args[0], args[1].nodeId, args[1].treeId, answer, esc_attribs)
.then(function(result) {
if(result.questions[0].nodeType === "error") {
//If no concept answers the question, ask again.
session.send("No answer was given.")
session.beginDialog("select", [esc_session.sessionId, esc_session.questions[0]])
} else {
esc_session = result;
console.log("Initiating new Dialog %s", esc_session.questions[0].nodeType);
//the nodeType is either "select", "info" or "solution"
session.beginDialog(esc_session.questions[0].nodeType, [esc_session.sessionId, esc_session.questions[0]])
}
})
.catch(function(err) {
console.log("Error proceeding tree.");
console.log(err);
});
})
}
]).beginDialogAction("cancelSelect", "cancel", {matches: /^abbrechen$|^beenden$|^stop$|^halt/i});
//This dialog is for showing hint nodes. It then automatically proceeds the tree.
bot.dialog("info", [
function(session, args) {
console.log("Info");
message = args[1].text;
attach(args[1].memo["Memo_URL"]);
session.send(message);
console.log("Proceeding tree without answer.");
esc.escProceedTree(esc_header, args[0], args[1].nodeId, args[1].treeId, "OK", esc_attribs)
.then(function(result) {
esc_session = result;
console.log("Initiating new Dialog %s", esc_session.questions[0].nodeType);
session.beginDialog(esc_session.questions[0].nodeType, [esc_session.sessionId, esc_session.questions[0]]);
})
.catch(function(err) {
console.log("Error proceeding tree.");
console.log(err);
});
}
])
//This dialog displays the reached solution. It then ends the dialog, erasing the concepts of this session.
bot.dialog("solution", [
function(session, args) {
console.log("Solution");
message = args[1].text;
attach(args[1].memo["Memo_URL"]);
session.send(message);
esc.escFinishSession(esc_header, args[0])
.then(function(result) {
console.log("Finished Session " + args[0]);
esc_session = undefined;
})
.catch(function(err) {
console.log("Error finishing session.");
console.log(err);
})
console.log("Ending dialog.");
session.endDialog("I hope i could help you.");
}
])
/*-----------
-- Manners --
-----------*/
// Greetings
bot.on("conversationUpdate", function (message) {
if (message.membersAdded && message.membersAdded.length > 0) {
// Don"t greet yourself
if(message.membersAdded[0].id !== message.address.bot.id) {
// Say hello
var reply = new builder.Message()
.address(message.address)
.text("Welcome to the Chatbot. Please enter your search.");
bot.send(reply);
}
} else if (message.membersRemoved) {
// Say goodbye
var reply = new builder.Message()
.address(message.address)
.text("Goodbye.");
bot.send(reply);
}
});
/*---------------------
-- Utility functions --
---------------------*/
//function for attached images
var attach = function(p) {
if(typeof p != undefined && p != null) {
console.log("Found attachment: %s", p);
session.send({
attachments:[{
contentUrl: p,
contentType: "image/jpeg"
}]
})
}
}
var undoMutation = function(s) {
while(s.indexOf("ä") !== -1) {
s = s.replace("ä", "ae");
}
while(s.indexOf("ö") !== -1) {
s = s.replace("ö", "oe");
}
while(s.indexOf("ü") !== -1) {
s = s.replace("ü", "ue");
}
return s;
}
It could be the question of nested string Prompt dialogs. Currently I only find some workarounds to quick fix the issue.
Fastest: Enlarge the retires of prompt dialog, which will reprompt the question if Bot gets the invaild input.
builder.Prompts.choice(session, args[1].text, args[1].answerValues, {
listStyle: builder.ListStyle.button,
maxRetries: 2
});
As I see you will pass the treeNote to the select dialog, so you can try to use replaceDialog() instead of beginDialog() to clear nested dialog stack. In your cancel dialog, also replace endDialog() to replaceDialog()
There is a button on the popup. When clicked, popup.js will send a message to background.js. It works well almost all the time. But after a long time not operating chrome, when I click the button, the message is sent(alert("Start to send message") executed) but cannot be received by background.js(alert("Start to render") not executed). When I click one more, it will sometimes work. If it still doesn't work, I will click again, the third time has much more chance to success. That's very strange.
I use jquery in the popup.html, but I don't think it matter.
Javascript code in popup.js
$('#create).html(chrome.i18n.getMessage('create'))
.on('click', function(){
_current = null;
chrome.runtime.sendMessage({
cmd: 'SITEMAP_DEFINE'
});
alert("Start to send message");
window.close();
})
Javascript code in background.js
var curTabId; //current tab in which scraper is going to scraping
var devtoolPort;
var coord;
var sitemap;
var finish = false;
function sendMessage(msg) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, msg);
});
}
//detective devtools
chrome.runtime.onConnect.addListener(function (port) {
if (port.name == "devtools-papa") {
devtoolPort = port;
}
});
//tab update
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(finish === false && coord && changeInfo.status == 'loading'){
coord.onUpdate(tab);
}
})
chrome.tabs.onRemoved.addListener(function(tabId, removeInfo) {
if(finish === false && coord && removeInfo.isWindowClosing === false){
coord.onRemove(tabId);
}
})
chrome.runtime.onMessage.addListener(function(msg, sender, callback){
var p = msg.params;
//scrape
if(msg.cmd == 'START_SCRAPE'){
sitemap = p.sitemap;
if(sitemap){
finish = false;
coord = new Coordinator(sitemap, 0);
var page = coord.sitemap.pages[0];
coord.openTab(page.id, page.link);
}
}
else if(msg.cmd == 'TEST_SCRAPE'){
sitemap = p.sitemap;
if(sitemap){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var tab = tabs[0];
sitemap.pages[0].link = tab.url;
finish = false;
coord = new Coordinator(sitemap, 20);
var page = coord.sitemap.pages[0];
coord.openTab(page.id, page.link);
})
}
}
else if(msg.cmd == 'SCRAPE_READY'){
print(sender);
coord.readyForScrape(sender.tab.id);
}
else if(msg.cmd == 'TAB_CLICK'){
coord.currentPage = sitemap.getPage(p.page);
}
//define
else if(msg.cmd == 'START_SELECT'){
if(msg.tabId){
chrome.tabs.sendMessage(msg.tabId, msg);
}else{
sendMessage(msg);
}
}
else if(msg.cmd == 'END_SELECT'){
if(devtoolPort){
devtoolPort.postMessage(msg);
}
sendMessage(msg);
}
else if(msg.cmd == 'SITEMAP_DEFINE'){
alert("Start to render");
var url = p && p.url;
sitemap = p && p.sitemap;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var tab = tabs[0];
if(url && url != tab.url){
chrome.tabs.create({url: url}, function(newTab){
doInjectScript(newTab.id);
})
}else{
injectScript(tab.id);
}
});
}
else if(msg.cmd == 'SITEMAP_DEFINE_END'){
var _sm = p.sitemap;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var tab = tabs[0];
_sm.pages[0].link = tab.url;
saveSitemap(_sm);
})
}
else if(msg.cmd == 'SITEMAP_DELETE'){
deleteSitemap(p.sitemap);
}
else if(msg.cmd == 'DEFINE_PAGE_LOADED'){
callback(sitemap);
}
else{
sendMessage(msg);
}
});
var print = function(msg){
if(curTabId){
chrome.tabs.sendMessage(curTabId, {
cmd: 'LOG',
params: msg
});
}else{
sendMessage(msg)
}
}
function saveSitemap(_sm){
var id = _sm.id;
chrome.storage.local.get("sitemaps", function(db){
var _sitemaps = db["sitemaps"];
if(!_sitemaps || !_sitemaps.length){
_sitemaps = [_sm];
}else{
var _idx = _sitemaps.findIndex(function(s){return s.id == id});
if(_idx == -1){
_sitemaps.push(_sm);
}else{
_sitemaps.splice(_idx, 1, _sm);
}
}
var _db = {'sitemaps':_sitemaps}
chrome.storage.local.set(_db, function(){
alert(chrome.i18n.getMessage('saved'));
});
})
}
function deleteSitemap(id){
chrome.storage.local.get("sitemaps", function(db){
var _sitemaps = db["sitemaps"];
var index = _sitemaps.findIndex(function(s){return s.id == id})
_sitemaps.splice(index, 1);
var _db = {'sitemaps':_sitemaps}
chrome.storage.local.set(_db, function(){
alert(chrome.i18n.getMessage('deleted'));
});
})
}
function injectScript(tabId){
var flag;
chrome.tabs.sendMessage(tabId, {
cmd: 'SELF_CHECK'
}, function(r){
flag = r;
});
setTimeout(function(){
if(flag){
chrome.tabs.executeScript(tabId, {file: "injected/define/initUI.js"}, function() {});
}else{
doInjectScript(tabId);
}
}, 200)
}
//Injected scripts will be removed once the tab reload again.
function doInjectScript(tabId){
chrome.tabs.executeScript(tabId, {file: "injected/listener.js"});
chrome.tabs.executeScript(tabId, {file: "lib/jquery/jquery-2.1.1.min.js"}, function() {
chrome.tabs.executeScript(tabId, {file: "lib/model.js"});
chrome.tabs.executeScript(tabId, {file: "lib/css-selector-generator.js"}, function() {});
chrome.tabs.executeScript(tabId, {file: "injected/SelectTool.js"}, function() {});
chrome.tabs.executeScript(tabId, {file: "injected/define/initUI.js"}, function() {});
chrome.tabs.insertCSS(tabId, {file: "injected/injected.css", runAt: "document_end"});
});
}
function createResultTab(title, fields, data){
chrome.tabs.create({url: chrome.extension.getURL('result/table.html')}, function(newTab){
var tabId = newTab.id;
setTimeout(function(){
chrome.tabs.sendMessage(tabId, {
cmd: 'RESULT',
params:{
data: data,
title: title,
fields: fields
}
});
}, 200)
})
}
Thanks in advance for your help.
I find the answer in official document.
If we set persistent = false, the background js will be unload when it goes idle.
{
"name": "My extension",
...
"background": {
"scripts": ["eventPage.js"],
"persistent": false
},
...
}
The document tells sending message from content script will cause background js reload. But I guess message from popup script has issue.
So either change persistent true or chrome.runtime.getBackgroundPage in popup to cause background js reload will solve this issue.
![enter image description here][1]
I'm using sailsJs in my application. My server runs properly in my local, but server throws error "process.nextTick() Error : Can't set header after they sent".
Local version is working fine, But server throws above error. And I could not use any setInterval function in application. Don't know why this has happened.
My Controller Code
var lodash = require("lodash");
var FileController = {
upload: function (req, res) {
if(req.method === 'POST'){
console.log('plus button pressed........');
var filenameOriginal;
var carRecordFound=false;
req.file('uploadFile').upload({saveAs: function(file, cb) {
cb(null, file.filename);
filenameOriginal=file.filename;
},
dirname: '../../assets/images'
}, function whenDone(err, uploadedFiles) {
if(req.param('plateNumber')!=undefined){
var originalPlateNumber=req.param('plateNumber');
var updatedPlateNumber=originalPlateNumber.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
if(err){
return res.json(500, err);
}
else if(uploadedFiles.length === 0){
Account.findOne(req.param('accountID')).populateAll().exec(function found(err, accountData){
if (err) return next(err);
if (!accountData) {res.send({notValid : 'notValid'}); return;}
var i=0;
validate(i);
function validate(i){
if(i < accountData.subscriptionLog.length){
//
if(accountData.subscriptionLog[i].subscriptionStatus==undefined){ //SUBSCRIPTION STATUS UNDEFINED STGRTS HERE
console.log(i+'--Subscription is undefined');
i++;
validate(i);
}//SUBSCRIPTION STATUS UNDEFINED ENDS HERE
else if(accountData.subscriptionLog[i].subscriptionStatus=='active'){ //SUBSCRIPTION STATUS ACTIVE STARTS HERE
if(currentDatems<=(accountData.subscriptionLog[i].subscriptionEndDate).getTime()){ //SUBSCRIPTION END DATE VALIDATION STARTS HERE
console.log(i+'--<<uniqueID-------'+accountData.subscriptionLog[i].uniqueID+'Max'+accountData.subscriptionLog.length);
uniqueID=accountData.subscriptionLog[i].uniqueID;
console.log(i+'--<<Strated Processing-------'+accountData.subscriptionLog[i].uniqueID);
Mastertransactional.count({uniqueID : uniqueID}).exec(function countCB(err, found){ //RESPONSE FROM SERVER FOR THE SUBSCRIPTION COUNT
if (err) { console.log('Error------'+err); exitBoolean=true; return next(err); };
if (!found || found==0) {
console.log('No cars parked for this subscription!!!'+found);
}
console.log('There are '+ found +' records founded ');
found1=found;
console.log("numberOfCars-------"+accountData.subscriptionLog[i].numberOfCars);
console.log("found cars-----------"+found1);
if(found1<(accountData.subscriptionLog[i].numberOfCars)){//CAR COUNT VALIDATION STARTS HERE
activeSubscriptionFound=true;
console.log(new Date()+"active condition--------"+activeSubscriptionFound);
console.log('entered into less than car');
if(req.param('parkingID')==undefined || req.param('parkingID')=='' || req.param('plateNumber')=='' || req.param('plateNumber')==undefined )// check empty object from plus button
{
console.log('plus button');
exitBoolean=true;
}
else if(req.param('parkingID')!=undefined || req.param('parkingID')!='')
{
console.log('Car stored');
// ADD THE CAR IN THE DAILY TRANSACTION
Dailytransactional.create(carObj).exec(function(error,carObj){
if(error){console.log('error');}
console.log("daily"+carObj);
Dailytransactional.publishCreate({id: carObj.id,
parkingID: carObj.parkingID,
plateNumber: carObj.plateNumber,
snap: carObj.snap,
parkingZone: carObj.parkingZone,
color: carObj.color,
brand: carObj.brand,
employeeID: carObj.employeeID,
accountID: carObj.accountID,
venue: carObj.venue,
status:carObj.status,
log:carObj.log
});
carObj1['transactionID']=carObj.id;
carObj1['uniqueID']=uniqueID;
Mastertransactional.create(carObj1).exec(function(error,carObj1){
if(error){console.log('error');}
console.log("Master created ---"+carObj1);
exitBoolean=true;
});
});
if((found1+1)==accountData.subscriptionLog[i].numberOfCars){
console.log('Maximum car reached for the subscription');
//CHANGE STATUS OF THE SUBSCRIPTION TO EXPIRED
FileController.subscriptionExpire(req.param('accountID'), accountData.subscriptionLog, i);
}// found +1 if close
}// else if for record insert
console.log('Car Count True Loop Count Incremented');
if(!exitBoolean)
{
i++;
validate(i);
}
}//CAR COUNT VALIDATION ELSE LOOP HERE
else {
FileController.subscriptionExpire(req.param('accountID'), accountData.subscriptionLog, i);
console.log('Car Count Else Loop');
}//CAR COUNT VALIDATION ENDS HERE
console.log(exitBoolean+'After Else Loop >> Counter INcreased'+activeSubscriptionFound);
if(!exitBoolean)
{
i++;
validate(i);
}
if(exitBoolean)
{
if(!activeSubscriptionFound){
//show error message that no active subscription available
console.log(found1+'plus button error called...'+new Date());
res.send({success : 'error'});
return;
}
else
{
console.log(found1+'plus button success'+new Date());
res.send({success : 'success'});
return;
}
}
else
{
console.log(new Date()+'This is the error'+exitBoolean);
}
});// MASTER DATA COUNT FUNCTION ENDS HERE
}// SUBSCRIPTION END DATE VALIDATION ELSE LOOP
else {
FileController.subscriptionExpire(req.param('accountID') ,accountData.subscriptionLog, i);
if(!exitBoolean)
{
i++;
validate(i);
}
} //SUBSCRIPTION END DATE VALIDATION ENDS LOOP
} // SUBSCRIPTION IN LOOP IS NOT ACTIVE
else
{
i++;
console.log(i+'Expired Subscription');
validate(i);
}//SUBSCRIPTION LOOP ENDS HERE
}//MAIN ENTRANCE ENDS HERE
else
{
exitBoolean=true;
if(!activeSubscriptionFound){
console.log(found1+'plus button error'+new Date());
res.send({success : 'error'});
}
}
console.log('coming here<< active subscription--'+activeSubscriptionFound+"--------exitBoolean <<"+exitBoolean);
if(exitBoolean)
{
if(!activeSubscriptionFound){
//show error message that no active subscription available
console.log(found1+'plus button error'+new Date());
//res.send({success : 'error'});
}
else
{
console.log(found1+'plus button success'+new Date());
}
}
else
{
console.log(new Date()+'This is the error'+exitBoolean);
}
}//FUNCTION VALIDATE ENDS HERE
});// account find close
}
else{
// handle uploaded file
}
});
}
},
subscriptionExpire : function(accountID ,subscriptionLog, i) {
var array=[];
array=subscriptionLog;
var subscriptionWantStatus=subscriptionLog[i];
subscriptionWantStatus.subscriptionStatus="Expired";
array.splice(i,1,subscriptionWantStatus);
array.join();
var sLog={
subscriptionLog: array
};
Account.update(accountID,sLog, function venueUpdated(err, car) {
console.log("-Updated log- expired");
});
}
};
module.exports = FileController;
Error throws this code line
console.log(exitBoolean+'After Else Loop >> Counter INcreased'+activeSubscriptionFound); if(!exitBoolean)
{
i++;
validate(i);
}
if(exitBoolean)
{
if(!activeSubscriptionFound){
//show error message that no active subscription available
console.log(found1+'plus button error called...'+new Date());
res.send({success : 'error'});
return;
}
else
{
console.log(found1+'plus button success'+new Date());
res.send({success : 'success'});
return;
}
I am trying to implement a one to one audio call using webRTC (signalling using websockets) . But it works when i try it in one system using multiple tabs of chrome (localhost). When I try to hit my server from another machine it does initial handshakes , but call doesn't happen.
But when i try to change the tag to and changed the constraints to video constraints . it works even if the we try to access from other machine (i.e video call works ).
I initially thought it was because if firewall but when video call worked I was puzzled .
Here is my code:
// Constraints to get audio stream only
$scope.constraints = {
audio: {
mandatory: {
googEchoCancellation: true
},
optional: []
},
video:false
};
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
// success Callback of getUserMedia(), stream variable is the audio stream.
$scope.successCallback = function (stream) {
if (window.URL) {
myVideo.src = window.URL.createObjectURL(stream); // converting media stream to Blob URL.
} else {
myVideo.src = stream;
}
//attachMediaStream(audioTag, stream);
localStream = stream;
if (initiator)
maybeStart();
else
doAnswer();
};
// failure Callback of getUserMedia()
$scope.failureCallback = function (error) {
console.log('navigator.getUserMedia Failed: ', error);
};
var initiator, started = false;
$("#call").click(function () {
socket.emit("message", undefined);
initiator = true;
navigator.getUserMedia($scope.constraints, $scope.successCallback, $scope.failureCallback);
});
var channelReady = false;
socket.on('message', function (data) {
channelReady = true;
if (data) {
if (data.type === 'offer') {
if (!initiator) {
$("#acceptCall").show();
$("#acceptCall").click(function(){
if (!initiator && !started) {
var pc_config = {
iceServers: [
{ url: "stun:stun.l.google.com:19302" },
{ url: "turn:numb.viagenie.ca", credential: "drfunk", username: "toadums#hotmail.com"}
]
};
pc = new webkitRTCPeerConnection(pc_config);
pc.onicecandidate = onIceCandidate;
pc.onaddstream = onRemoteStreamAdded;
}
pc.setRemoteDescription(new RTCSessionDescription(data));
$scope.acceptCall();
});
}
} else if (data.type === 'answer' && started) {
pc.onaddstream = onRemoteStreamAdded;
pc.setRemoteDescription(new RTCSessionDescription(data));
} else if (data.type === 'candidate' && started) {
var candidate = new RTCIceCandidate({
sdpMLineIndex: data.label,
candidate: data.candidate
});
pc.addIceCandidate(candidate);
} else if (data.type === 'bye' && started) {
console.log("Bye");
}
}
});
function onRemoteStreamAdded(event) {
othersVideo.src = URL.createObjectURL(event.stream);
};
var sdpConstraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': false
}
};
function doAnswer() {
pc.addStream(localStream);
pc.createAnswer(gotDescription,null,sdpConstraints);
}
function gotDescription(desc) {
pc.setLocalDescription(desc);
socket.send(desc);
}
function maybeStart() {
if (!started && localStream && channelReady)
createPeerConnection();
pc.addStream(localStream);
started = true;
if (initiator)
doCall();
}
$scope.acceptCall = function () {
navigator.getUserMedia($scope.constraints, $scope.successCallback, $scope.failureCallback);
}
function createPeerConnection() {
var pc_config = {
iceServers: [
{ url: "stun:stun.l.google.com:19302" },
{ url: "turn:numb.viagenie.ca", credential: "drfunk", username: "toadums#hotmail.com"}
]
};
pc = new webkitRTCPeerConnection(pc_config);
pc.onicecandidate = onIceCandidate;
console.log("Created RTCPeerConnnection with config:\n" + " \"" +
JSON.stringify(pc_config) + "\".");
};
function doCall() {
$scope.caller = true;
pc.createOffer(setLocalAndSendMessage,null,sdpConstraints);
};
function setLocalAndSendMessage(sessionDescription) {
pc.setLocalDescription(sessionDescription);
socket.send(sessionDescription);
}
function onIceCandidate(event) {
if (event.candidate) {
socket.emit('message', {
type: 'candidate',
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate
});
} else {
console.log("End of candidates.");
}
}
If navigator.mediaDevices is undefined, this because work only in secure context (https)
see:
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
I am writing a testing application, for the company where I work, using Node.js and Phantomjs. Right now, the relevant part of my code is something like this:
phantom.create(function (ph) {
ph.createPage(function (page) {
page.set('viewportSize', { width: 1920, height: 1080 });
page.set('settings.javascriptEnabled', true);
page.set('settings.loadImages', true);
page.set('settings.localToRemoteUrlAccess', true);
page.set('settings.userAgent', userAgentStrings[randomInt(0, 5)]);
page.set('settings.webSecurityEnabled', false);
page.set('settings.resourceTimeout', 5000);
page.open(URL, function (status) {
if (status == 'success') {
page.evaluate(function (result) {
return document.title;
}, function (result) {
setTimeout(function () {
log.info('Status: ', status);
ph.exit();
}, 60 * 1000);
});
} else if (status == 'fail') {
log.error('Status: ', status);
ph.exit();
}
});
});
});
My question is this: Is there a way to refactor my code in such a way that I can call the "page.open(..." function from outside the "phantom.create(..." block?
I plan to implement node-cron and have one block of code where I set up all the options for the page and another one that I will actually use to open the page. In the end, the opening part will be handled by node-cron, repeating ad infinitum.
Here is a quick example on how to do this. You just need to store your phantom object somewhere and reuse it. Be aware that I made this simple so that you can reuse the concept but that you would need more error handling.
var jobRunner = function() {
// The phantom object will be stored here
this.ph;
// The page object will be stored here
this.page;
};
jobRunner.prototype.start = function(readyCallback) {
var self = this;
phantom.create(function (ph) {
self.ph = ph;
self.ph.createPage(function (page) {
page.set('viewportSize', { width: 1920, height: 1080 });
page.set('settings.javascriptEnabled', true);
page.set('settings.loadImages', true);
page.set('settings.localToRemoteUrlAccess', true);
page.set('settings.userAgent', userAgentStrings[randomInt(0, 5)]);
page.set('settings.webSecurityEnabled', false);
page.set('settings.resourceTimeout', 5000);
self.page = page;
readyCallback();
});
});
};
jobRunner.prototype.doUrl = function(url) {
var self = this;
this.page.open(URL, function (status) {
if (status == 'success') {
page.evaluate(function (result) {
return document.title;
}, function (result) {
setTimeout(function () {
log.info('Status: ', status);
self.ph.exit();
}, 60 * 1000);
});
} else if (status == 'fail') {
log.error('Status: ', status);
self.ph.exit();
}
});
}
var CronJob = require('cron').CronJob;
var phantomJob = new jobRunner();
// Wait for Phantom to be ready then start the Cron Job.
phantomJob.start(function() {
var cron = new CronJob('*/5 * * * * *', function() {
phantomJob.doUrl("http://yoururl.com");
});
});