Device shadow state not changes - node.js

Trying to create aws-iot device by using manual. I did all required settings while creating Pi3-DHT11-Node device. Simplified code below:
var awsIot = require('aws-iot-device-sdk');
const NODE_ID = 'Pi3-DHT11-Noded';
const INIT_DELAY = 15;
const TAG = '[' + NODE_ID + '] >>>>>>>>> ';
var thingShadow = awsIot.thingShadow({
keyPath: './certs_p/fea2f8efae7-private.pem.key',
certPath: './certs_p/fea2f8efae7-certificate.pem.crt',
caPath: './certs_p/AmazonRootCA1.pem',
clientId: NODE_ID,
host: 'a3cnel9blokzm0-ats.iot.eu-west-3.amazonaws.com',
port: 8883,
region: 'eu-west-3',
debug: true, // optional to see logs on console
});
thingShadow.on('connect', function() {
console.log(TAG, 'Connected.');
thingShadow.register(NODE_ID, {}, function() {
console.log(TAG, 'Registered.');
console.log(TAG, 'Reading data in ' + INIT_DELAY + ' seconds.');
setTimeout(sendData, INIT_DELAY * 1000); // wait for `INIT_DELAY` seconds before reading the first record
});
});
function sendData() {
var DHT11State = {
"state": {
"desired":
{
"temp": 20,
"humd": 33
}
}
};
var clientTokenUpdate = thingShadow.update(NODE_ID, DHT11State);
if (clientTokenUpdate === null) {
console.log(TAG, 'Shadow update failed, operation still in progress');
} else {
console.log(TAG, 'Shadow update success.');
}
// keep sending the data every 30 seconds
console.log(TAG, 'Reading data again in 30 seconds.');
setTimeout(sendData, 30000); // 30,000 ms => 30 seconds
}
Script is working fine, but this does not change shadow state. Why? How to fix that?

It is most likely that you do not have the device setup to sync the shadow to the cloud.
Follow the steps in this part of the tutorial, and ensure that you click on "Sync to the Cloud" as per Step 2, then redeploy your Greengrass Group.
https://docs.aws.amazon.com/greengrass/latest/developerguide/comms-enabled.html

Related

Lambda function taking >3 seconds to run + 5-10 secs warmup each time

I have a simple node.js function with 2 REST API calls and a socket connection output hosted in an AWS lambda. It takes 5-10 secs warmup time and >3+ secs execution time.
When the code is run locally it executes both requests, socket connection and completes in about ~1300ms. Why is AWS more then double the execution time? I have set-timeout to 120seconds and memory at 128mb (default).
I appreciate the code is not very tidy; I am working on cleaning it but needed something going for the time being.
The project simply gets info from ServiceM8 via API when called by a webhook subscription, then formats the info into ZPL strings and forwards them to a tcp server for printing via thermal printer.
My questions are:
Is it my code bottle necking?
Can it be optimized to run faster?
Do i simply need to employ a warming plugin for my function to allow hot starting?
My function:
'use strict';
//Require libraries
var request = require("request");
var net = require('net');
exports.handler = (event, context, callback) => {
if (event.eventName != 'webhook_subscription') {
callback(null, {});
}
//Global Variables
var strAssetUUID;
var strAssetURL;
var strFormUUID;
var strTestDate;
var strRetestDate;
var appliancePass = true;
var strAccessToken;
var strResponseUUID;
//Printer Access
const tcpUrl = 'example.com';
const tcpPort = 12345;
var client = new net.Socket();
//UUID of Appliance Test Form.
const strTestFormUUID = 'UUID_of_form';
//Begin function
/**
* Inspect the `eventArgs.entry` argument to get details of the change that caused the webhook
* to fire.
*/
strResponseUUID = event.eventArgs.entry[0].uuid;
strAccessToken = event.auth.accessToken;
console.log('Response UUID: ' + strResponseUUID);
console.log('Access Token: ' + strAccessToken);
//URL Options for FormResponse UUID query
const urlFormResponse = {
url: 'https://api.servicem8.com/api_1.0/formresponse.json?%24filter=uuid%20eq%20' + strResponseUUID,
headers: {
// Use the temporary Access Token that was issued for this event
'Authorization': 'Bearer ' + strAccessToken
}
};
//Query form Response UUID to get information required.
request.get(urlFormResponse, function(err, res, body) {
//Check response code from API query
if (res.statusCode != 200) {
// Unable to query form response records
callback(null, {err: "Unable to query form response records, received HTTP " + res.statusCode + "\n\n" + body});
return;
}
//If we do recieve a 200 status code, begin
var arrRecords = JSON.parse(body);
//Store the UUID of the form used for the form response.
strFormUUID = arrRecords[0].form_uuid;
console.log('Form UUID: ' + strFormUUID);
//Store the UUID of the asset the form response relates to.
strAssetUUID = arrRecords[0].asset_uuid;
console.log('Asset UUID: ' + strAssetUUID);
if (strFormUUID == strTestFormUUID){
//Get the edited date and parse it into a JSON date object.
var strEditDate = new Date(arrRecords[0].edit_date);
//Reassemble JSON date to dd-mm-yyyy.
strTestDate = strEditDate.getDate() + '/' + (strEditDate.getMonth() + 1) + '/' + strEditDate.getFullYear();
//Extract the response for retest period.
var strRetestAnswer = JSON.parse(arrRecords[0].field_data);
strRetestAnswer = strRetestAnswer[0].Response;
//Appropriate function based on retest response.
switch(strRetestAnswer) {
case '3 Months':
//Add x months to current test date object
strEditDate.setMonth(strEditDate.getMonth() + 3);
strRetestDate = strEditDate.getDate() + '/' + (strEditDate.getMonth() + 1) + '/' + strEditDate.getFullYear();
break;
case '6 Months':
strEditDate.setMonth(strEditDate.getMonth() + 6);
strRetestDate = strEditDate.getDate() + '/' + (strEditDate.getMonth() + 1) + '/' + strEditDate.getFullYear();
break;
case '12 Months':
strEditDate.setMonth(strEditDate.getMonth() + 12);
strRetestDate = strEditDate.getDate() + '/' + (strEditDate.getMonth() + 1) + '/' + strEditDate.getFullYear();
break;
case '2 Years':
strEditDate.setMonth(strEditDate.getMonth() + 24);
strRetestDate = strEditDate.getDate() + '/' + (strEditDate.getMonth() + 1) + '/' + strEditDate.getFullYear();
break;
case '5 Years':
strEditDate.setMonth(strEditDate.getMonth() + 60);
strRetestDate = strEditDate.getDate() + '/' + (strEditDate.getMonth() + 1) + '/' + strEditDate.getFullYear();
break;
default:
strRetestDate = "FAIL";
appliancePass = false;
}
console.log('Appliance Pass: ' + appliancePass);
console.log('Test Date: ' + strTestDate);
console.log('Retest Period: ' + strRetestAnswer);
console.log('Retest Date: ' + strRetestDate);
//URL Options for Asset UUID query
const urlAssetResponse = {
url: 'https://api.servicem8.com/api_1.0/asset/' + strAssetUUID + '.json',
headers: {
// Use the temporary Access Token that was issued for this event
'Authorization': 'Bearer ' + strAccessToken
}
};
//Query the api for the asset URL of the provided asset UUID.
request.get(urlAssetResponse, function(err, res, body) {
//Check response code from API query
if (res.statusCode != 200) {
// Unable to query asset records
callback(null, {err: "Unable to query asset records, received HTTP " + res.statusCode + "\n\n" + body});
return;
}
//If we do recieve a 200 status code, begin
var strAssetResponse = JSON.parse(body);
//Store the asset URL
strAssetURL = 'https://sm8.io/' + strAssetResponse.asset_code;
console.log('Asset URL: ' + strAssetURL);
//generate tag and send to printer
var strZPLPass = ('^XA....^XZ\n');
var strZPLFail = ('^XA....^XZ\n');
//Now that we have our ZPL generated from our dates and URLs
//Send the correct ZPL to the printer.
client.connect(tcpPort, tcpUrl, function() {
console.log('Connected');
//Send Appropriate ZPL
if (appliancePass) {
client.write(strZPLPass);
}else {
client.write(strZPLFail);
}
console.log('Tag Successfully Printed!');
//As the tcp server receiving the string does not return any communication
//there is no way to know when the data has been succesfully received in full.
//So we simply timeout the connection after 750ms which is generally long enough
//to ensure complete transmission.
setTimeout(function () {
console.log('Timeout, connection closing...');
client.destroy();
}, 750);
});
});
}
});
};
First of all, I would suggest you stop using the request module and switch to native. Everything can be done without a tons of lines these days. request is a module with 48 total dependencies; if you do the math, that's thousands of lines for a simple GET request.
You should always minimize the complexity of your dependencies. I use a Lambda to check the health of my sites, grabbing the whole request and checking the HTML on completely different servers. VPS is located in Frankfurt, AWS in Ireland. My ms/request is ranging between 100~150 ms.
Here's a simple promise request I'm using:
function request(obj, timeout) {
return new Promise(function(res, rej) {
if (typeof obj !== "object") {
rej("Argument must be a valid http request options object")
}
obj.timeout = timeout;
obj.rejectUnauthorized = false;
let request = http.get(obj, (response) => {
if (response.statusCode !== 200) {
rej("Connection error");
}
var body = '';
response.on('data', (chunk) => {
body += chunk;
});
response.on('end', () => {
res(body);
});
response.on('error', (error) => {
rej(error);
});
});
request.setTimeout(timeout);
request.on('error', (error) => {
rej(error);
})
request.on('timeout', () => {
request.abort();
rej("Timeout!")
})
});
}
Example
const reqOpts = {
hostname: 'www.example.com',
port: 443,
path: '/hello',
method: 'GET',
headers: {
handshake: "eXTNxFMxQL4pRrj6JfzQycn3obHL",
remoteIpAddress: event.sourceIp || "lambda"
}
}
try {
httpTestCall = await request(reqOpts, 250);
}
catch (e) {
console.error(e);
}
Now based on that change switch your handler to async using exports.handler = async(event, context, callback) => {} and use console to measure the execution time of every request using console.time() and console.timeEnd() for your request or anything. From there you could see what's stepping down your code using Cloudwatch logs. Here's another example based on your code:
let reqOpts = {
hostname: 'api.servicem8.com',
port: 443,
path: '/api_1.0/formresponse.json?%24filter=uuid%20eq%20' + strResponseUUID,
method: 'GET',
headers: {
// Use the temporary Access Token that was issued for this event
'Authorization': 'Bearer ' + strAccessToken
}
}
console.time("=========MEASURE_servicem8=========")
let error = null;
await request(reqOpts, 5555).catch((e)=>{
error = e;
})
console.timerEnd("=========MEASURE_servicem8=========")
if (error){
callback(null, {err: "Unable to query form response records, received HTTP" + error}); /* or anything similar */
}
References
https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html
https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
aws lambdas are not fast by nature (as of writing this answer). The startup time is not guaranteed, and it is known to be high.
If you need performance - you will not get it this way.

Nodejs generating duplicate http-requests

Hope some can help with my issue. i'm using below nodejs code from this SAP Tutorial to read Sensor values post them per HTTP. All works pretty fine, but for the fact that every record is posted twice(see Screenshot). i'm not versed with server-side JS and don't know why the duplicates.Agreed, the values not aways the same, but for further processing i'd like to have single datasets per timestamp. Could someone please help me locate the issue and if possible, provide a solution/workaround?
Also the script reads and transmits the data every 10s. Am looking for a way to set the interval to maybe 3mins. I would appreciate every bit of help here as well
/* sensorTag IR Temperature sensor example
* Craig Cmehil, SAP SE (c) 2015
*/
/* Choose the proper HTTP or HTTPS, SAP Cloud Platformrequires HTTPS */
var http = require('https');
var SensorTag = require('sensortag');
var lv_temp;
var lv_humid;
var lv_deviceid = "";
var DEBUG_VALUE = true;
var xtimestamp;
var date = new Date();
var time = date.getTime ();
// SAP Cloud Platform connection details
var portIoT = 443;
var pathIoT = '/com.sap.iotservices.mms/v1/api/http/data/';
var hostIoT = 'iotmmsXXXXXXXXXXtrial.hanatrial.ondemand.com';
var authStrIoT = 'Bearer XXXXXXXXXXXX';
var deviceId = 'XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX';
var messageTypeID = 'XXXXXXXXXXXX';
var options = {
host: hostIoT,
port: portIoT,
path: pathIoT + deviceId,
agent: false,
headers: {
'Authorization': authStrIoT,
'Content-Type': 'application/json;charset=utf-8',
'Accept': '*/*'
},
method: 'POST',
};
/***************************************************************/
/* Coding to access TI SensorTag and values of various sensors */
/***************************************************************/
console.log("If not yet activated, then press the power button.");
SensorTag.discover(function(tag) {
tag.on('disconnect', function() {
console.log('disconnected!');
process.exit(0);
});
function connectExecute() {
console.log('Connect Device and Execute Sensors');
tag.connectAndSetUp(enableSensors);
}
function enableSensors() {
/* Read device specifics */
tag.readDeviceName(function(error, deviceName) {
console.log('Device Name = ' + deviceName);
});
tag.readSystemId(function(error, systemId) {
console.log('System ID = ' + systemId);
lv_deviceid = systemId;
});
tag.readSerialNumber(function(error, serialNumber) {
console.log('Serial Number = ' + serialNumber);
});
tag.readFirmwareRevision(function(error, firmwareRevision) {
console.log('Firmware Rev = ' + firmwareRevision);
});
tag.readHardwareRevision(function(error, hardwareRevision) {
console.log('Hardware Rev = ' + hardwareRevision);
});
tag.readHardwareRevision(function(error, softwareRevision) {
console.log('Software Revision = ' + softwareRevision);
});
tag.readManufacturerName(function(error, manufacturerName) {
console.log('Manufacturer = ' + manufacturerName);
});
/* Enable Sensors */
console.log("Enabling sensors:");
console.log('\tenableIRTemperatureSensor');
tag.enableIrTemperature(notifyMe);
console.log('\tenableHumidity');
tag.enableHumidity(notifyMe);
console.log("*********************************************");
console.log(" To stop press both buttons on the SensorTag ");
console.log("*********************************************");
}
function notifyMe() {
tag.notifySimpleKey(listenForButton);
setImmediate(function loop () {
tag.readIrTemperature(function(error, objectTemperature, ambientTemperature){
lv_obj = objectTemperature.toFixed(1);
lv_ambient = ambientTemperature.toFixed(1);
});
tag.readHumidity(function(error, temperature, humidity) {
lv_temp = temperature.toFixed(1);
lv_humid = humidity.toFixed(1);
});
if(DEBUG_VALUE)
console.log("Sending Data: " + lv_deviceid + " " + lv_temp + " " + lv_humid);
setSensorData(lv_temp, lv_humid);
setTimeout(loop, 10000);
});
}
function listenForButton() {
tag.on('simpleKeyChange', function(left, right) {
if (left && right) {
tag.disconnect();
}
});
}
connectExecute();
});
/******************************************************************/
/* FUNCTION to get Temperature from the Sensor & update into HANA */
/******************************************************************/
function setSensorData(lv_temp,lv_humid){
date = new Date();
time =date.getTime();
var data = {
"mode":"sync",
"messageType": messageTypeID,
"messages": [{
"timestamp": time,
"temperature": lv_temp,
"humidity": lv_humid
}]
};
var strData = JSON.stringify(data);
if(DEBUG_VALUE)
console.log("Data: " + strData);
if(strData.length > 46){
if(DEBUG_VALUE)
console.log("Sending Data to server");
/* Process HTTP or HTTPS request */
options.agent = new http.Agent(options);
var request_callback = function(response) {
var body = '';
response.on('data', function (data) {
body += data;
});
response.on('end', function () {
if(DEBUG_VALUE)
console.log("REQUEST END:", response.statusCode);
});
response.on('error', function(e) {
console.error(e);
});
}
var request = http.request(options, request_callback);
request.on('error', function(e) {
console.error(e);
});
request.write(strData);
request.end();
}else{
if(DEBUG_VALUE)
console.log("Incomplete Data");
}
}
It should only be posting once to the system but twice to the screen.
In the function notifyMe you need to change the line
setTimeout(loop, 10000);
Change the number to the interval you want it to delay before posting again.

Session auto logout after inactivity

Is there a built in feature in express session, to enable auto logout after given time of inactivity ? I am using it as below, and want it to logout if session is inactive for half an hour.
app.use(session({
key: 'sessid',
secret: 'This is secret',
resave: true,
saveUninitialized: true,
store: new RedisStore(redisOptions),
cookie: {
path: '/',
httpOnly: true,
secure: false,
maxAge: 24 * 60 * 60 * 1000,
signed: false
}
}))
Ok, I'll throw my two cents into the ring here.
Even though it's in theory possible to implement this using rolling session, I don't think you should...
It would require each user action the send a request to the server, in order for the user not to be logged out.
You miss an opportunity to inform your user that he/she will be logged out automatically soon (this is what the banks do, for example).
#Seth did point out in a comment above that there is actually a way to remedy this: "If the front end is separate from the server, you could have client side routing middleware that checks the cookie and visually logs you out, thus proving a good UX."
I think this is clever, but I also think it's like putting lipstick on a pig.
I believe that the best approach here is to handle this on the client side.
I would suggest something like this:
var AutoLogout = (function() {
function AutoLogout() {
this.events = ['load', 'mousemove', 'mousedown',
'click', 'scroll', 'keypress'];
this.warn = this.warn.bind(this);
this.logout = this.logout.bind(this);
this.resetTimeout = this.resetTimeout.bind(this);
var self = this;
this.events.forEach(function(event) {
window.addEventListener(event, self.resetTimeout);
});
this.setTimeout();
}
var _p = AutoLogout.prototype;
_p.clearTimeout = function() {
if(this.warnTimeout)
clearTimeout(this.warnTimeout);
if(this.logoutTimeout)
clearTimeout(this.logoutTimeout);
};
_p.setTimeout = function() {
this.warnTimeout = setTimeout(this.warn, 29 * 60 * 1000);
this.logoutTimeout = setTimeout(this.logout, 30 * 60 * 1000);
};
_p.resetTimeout = function() {
this.clearTimeout();
this.setTimeout();
};
_p.warn = function() {
alert('You will be logged out automatically in 1 minute.');
};
_p.logout = function() {
// Send a logout request to the API
console.log('Sending a logout request to the API...');
this.destroy(); // Cleanup
};
_p.destroy = function() {
this.clearTimeout();
var self = this;
this.forEach(function(event) {
window.removeEventListener(event, self.resetTimeout);
});
};
return AutoLogout;
})();
es2015
class AutoLogout {
constructor() {
this.events = ['load', 'mousemove', 'mousedown',
'click', 'scroll', 'keypress'];
this.warn = this.warn.bind(this);
this.logout = this.logout.bind(this);
this.resetTimeout = this.resetTimeout.bind(this);
this.events.forEach((event) => {
window.addEventListener(event, this.resetTimeout);
});
this.setTimeout();
}
clearTimeout() {
if(this.warnTimeout)
clearTimeout(this.warnTimeout);
if(this.logoutTimeout)
clearTimeout(this.logoutTimeout);
}
setTimeout() {
this.warnTimeout = setTimeout(this.warn, 29 * 60 * 1000);
this.logoutTimeout = setTimeout(this.logout, 30 * 60 * 1000);
}
resetTimeout() {
this.clearTimeout();
this.setTimeout();
}
warn() {
alert('You will be logged out automatically in 1 minute.');
}
logout() {
// Send a logout request to the API
console.log('Sending a logout request to the API...');
this.destroy(); // Cleanup
}
destroy() {
this.clearTimeout();
this.events.forEach((event) => {
window.removeEventListener(event, this.resetTimeout);
});
}
}
Partial polling solution:
var activityPolling = (function() {
var events = ['load', 'mousemove', 'mousedown', 'click', 'scroll', 'keypress'];
var active = true;
var timeout;
function poll() {
if(active) {
console.log('polling the server...')
}
}
function setIdle() {
active = false;
}
function setActive() {
active = true;
if(timeout)
clearTimeout(timeout);
timeout = setTimeout(setIdle, 30 * 60 * 1000);
}
function destroy() {
clearInterval(interval);
events.forEach(function(event) {
window.removeEventListener(event, setActive);
});
}
events.forEach(function(event) {
window.addEventListener(event, setActive);
});
setActive();
var interval = setInterval(poll, 60 * 1000);
return {
interval: interval,
destroy: destroy
}
})();
Rolling session may solve the purpose.
If you use the "rolling" option for session to "true," it will update the session timeout on new requests.
What you can do is: set max-age to 5 minutes.
maxAge: 30*10000
When there is no activity max-age will destroy the session.
However, when there is any activity, rolling will renew the session to be alive for next 30 minutes.
Again, the word in-activity in this question is little misleading.
In-activity could be any (or all) of no-mouse-movement, no-mouse-click, or no-interaction-with-server.
If you refer inactivity as no-interaction-with-server, this logic will work. However for no-ui-interactions inactivity, you need to handle from client side

Automate login + posting to forum using nodejs + phantomjs

I am trying to automate login to a forum ( yet another forum , test forum available here: http://testforum.yetanotherforum.net/ ) using node-phantom.
This is my code:
/**
* Yet Another Forum Object
*
*
*/
var yaf = function() {}; //
module.exports = new yaf();
var phantom = require('node-phantom');
//var sleep = require('sleep');
var configTestForum = {
loginUrl: "http://testforum.yetanotherforum.net/login",
loginFormDetail: {
usernameBox: 'forum_ctl03_Login1_UserName', // dom element ID
passwordBox: 'forum_ctl03_Login1_Password',
submitButton: 'forum_ctl03_Login1_LoginButton'
},
loginInfo: {
username: 'testbot',
password: 'testbot123'
}
};
var config = configTestForum;
// program logic
yaf.prototype.login = function(username, password, cb) {
var steps = [];
var testindex = 0;
var loadInProgress = false; //This is set to true when a page is still loading
/*********SETTINGS*********************/
phantom.create(function(error, ph) {
ph.createPage(function(err, page) {
page.set('settings', {
userAgent: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:40.0) Gecko/20100101 Firefox/40.0",
javascriptEnabled: true,
loadImages: false,
});
phantom.cookiesEnabled = true;
phantom.javascriptEnabled = true;
/*********SETTINGS END*****************/
console.log('All settings loaded, start with execution');
/**********DEFINE STEPS THAT FANTOM SHOULD DO***********************/
steps = [
//Step 1 - Open Amazon home page
function() {
console.log('Step 1 - Open Login Page');
page.open(config.loginUrl, function(status) {
});
},
function() {
console.log('Step 2 - Populate and submit the login form');
var submitForm = function(config) {
console.log('Form Submit 1 ( putting login )');
document.getElementById(config.loginFormDetail.usernameBox).value = config.loginInfo.username;
console.log('Form Submit 2 ( putting pass )');
//jQuery('#' + config.loginFormDetail.passwordBox).val(config.loginInfo.password);
//jQuery('#' + config.loginFormDetail.usernameBox).val(config.loginInfo.password);
document.getElementById(config.loginFormDetail.passwordBox).value = config.loginInfo.password;
console.log('Form Submit 3 ( clicking button ) ');
document.getElementById(config.loginFormDetail.submitButton).click();
//var clickElement = function (el) {
// var ev = document.createEvent("MouseEvent");
// ev.initMouseEvent(
// "click",
// true /* bubble */, true /* cancelable */,
// window, null,
// 0, 0, 0, 0, /* coordinates */
// false, false, false, false, /* modifier keys */
// 0 /*left*/, null
// );
// el.dispatchEvent(ev);
// console.log('dispatched!');
//};
//document.getElementById(config.loginFormDetail.submitButton).click();
//clickElement(jQuery("#forum_ctl03_Login1_LoginButton")[0]);
//
//var form = document.getElementById('form1');
////var list = function(object) {
//// for(var key in object) {
//// console.log(key);
//// }
////};
////list(form);
//
//
//// jQuery('#form1').submit();
//
//form.submit();
//
//document.forms[0].submit();
//HTMLFormElement.prototype.submit.call(jQuery('form')[0]);
console.log('Form Has Been Submitted <-----------------');
};
var subittedForm = function(err, retVal) {
console.log('Form Submit error : ' + err);
console.log('Form Submit returned : ' + retVal);
};
//page.evaluateJavaScript(jsCode);
page.evaluate(submitForm, subittedForm, config);
},
//Step 3 - wait for submit form to finish loading..
function() {
//sleep.sleep(5);
console.log("Step 3 - wait for submit form to finish loading..");
//sleep.sleep(3);
page.render('loginComplete.png');
page.get('cookies', function(err, cookies) {
// console.log(cookies);
});
page.evaluate(function() {
console.log(document.URL);
});
},
function() {
console.log('Exiting');
}
];
/**********END STEPS THAT FANTOM SHOULD DO***********************/
//Execute steps one by one
interval = setInterval(executeRequestsStepByStep, 500);
function executeRequestsStepByStep() {
if (loadInProgress == false && typeof steps[testindex] == "function") {
//console.log("step " + (testindex + 1));
steps[testindex]();
testindex++;
}
if (typeof steps[testindex] != "function") {
console.log("test complete!");
ph.exit();
// cb(ph);
cb('done');
}
}
page.onLoadStarted = function() {
loadInProgress = true;
console.log('Loading started');
};
page.onLoadFinished = function() {
loadInProgress = false;
console.log('Loading finished');
};
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.onError = function(msg, trace) {
var msgStack = ['ERROR: ' + msg];
if (trace && trace.length) {
msgStack.push('TRACE:');
trace.forEach(function(t) {
msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function+'")' : ''));
});
}
console.error('\n' + msgStack.join('\n'));
};
page.onResourceError = function(resourceError) {
console.error('Unable to load resource (#' + resourceError.id + ' URL:' + resourceError.url + ')');
console.error('Error code: ' + resourceError.errorCode + '. Description: ' + resourceError.errorString);
};
page.onResourceTimeout = function(msg) {
console.error('onResourceTimeout!!>' + msg);
};
page.onAlert = function(msg) {
console.error('onAlert!!> ' + msg);
};
});
});
// var page = webPage.create();
};
Output of the code is :
Step 1 - Open Login Page
Loading started
Loading finished
Step 2 - Populate and submit the login form
Form Submit 1(putting login)
Form Submit 2(putting pass)
Form Submit 3(clicking button)
Form Has Been Submitted < -----------------
Form Submit error: null
Form Submit returned: null
Unable to load resource(#14 URL:http://testforum.yetanotherforum.net/login?g= login &= )
Error code: 5.Description: Operation canceled
ERROR: TypeError: 'undefined'
is not an object(evaluating 'Sys.WebForms.Res.PRM_TimeoutError'), [object Object], [object Object], [object Object], [object Object], [object Object], [object Object], [object Object]
Step 3 - wait
for submit form to finish loading..
http: //testforum.yetanotherforum.net/login
Exiting
test complete!
done
Option client store expiration is not valid.Please refer to the README.
Process finished with exit code 0
What it attempts to do is :
Open login page : http://testforum.yetanotherforum.net/login?returnurl=%2fcategory%2f1-Test-Category
Try to login using login name / password and then clicking the button.
Take a screenshot and Retrieve the cookies ( containing the auth data )
Currently it is getting stuck in step 2. It can populate the login and password box, but no kind of clicking or submitting the form is working.Basically it is stuck as shown:
(as you can see the login / password are filled correctly ).
By looking at step 2 ( Step 2 - Populate and submit the login form ) in my code, do you notice anything obvious? or am I doing something wrong in the page settings?

How to implement APNS notifications through nodejs?

Does someone now a good npm module to implement Apple PUSH notifications?
A simple example would be great.
The solution I've found is the following which uses the apn module.
var apn = require('apn');
var ca = ['entrust_2048_ca.cer'];
/* Connection Options */
var options = {
cert: 'path to yuour cert.pem',
key: 'path to your key.pem',
ca: ca,
passphrase: 'your passphrase',
production: true,
connectionTimeout: 10000
};
var apnConnection = new apn.Connection(options);
/* Device */
var deviceToken = 'your device token';
var myDevice = new apn.Device(deviceToken);
/* Notification */
var note = new apn.Notification();
note.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.
note.badge = 3;
note.payload = {'message': 'hi there'};
apnConnection.pushNotification(note, myDevice);
If you need to use the APNS feedback service to avoid to send notifications to devices which cannot receive it (application uninstalled) you can add the following:
/* Feedback Options */
var feedbackOptions = {
cert: 'path to yuour cert.pem',
key: 'path to your key.pem',
ca: ca,
passphrase: 'your passphrase',
production: true,
interval: 10
};
var feedback = new apn.feedback(feedbackOptions);
feedback.on('feedback', handleFeedback);
feedback.on('feedbackError', console.error);
function handleFeedback(feedbackData) {
var time, device;
for(var i in feedbackData) {
time = feedbackData[i].time;
device = feedbackData[i].device;
console.log("Device: " + device.toString('hex') + " has been unreachable, since: " + time);
}
}
To handle the different events connected to the connection you can use the following:
apnConnection.on('connected', function(openSockets) {
//
});
apnConnection.on('error', function(error) {
//
});
apnConnection.on('transmitted', function(notification, device) {
//
});
apnConnection.on('transmissionError', function(errCode, notification, device) {
//
});
apnConnection.on('drain', function () {
//
});
apnConnection.on('timeout', function () {
//
});
apnConnection.on('disconnected', function(openSockets) {
//
});
apnConnection.on('socketError', console.error);

Resources