Skip to content

Instantly share code, notes, and snippets.

@MorningLightMountain713
Created October 22, 2019 19:51
Show Gist options
  • Save MorningLightMountain713/69fd57216111ccadc4c822d05613cb8f to your computer and use it in GitHub Desktop.
Save MorningLightMountain713/69fd57216111ccadc4c822d05613cb8f to your computer and use it in GitHub Desktop.
Genieacs extension script to return how many times provision has been run per day.
// Genieacs provision usage
// let ts = new Date().getTime() / 1000; // unix timestamp
// let serial = declare("InternetGatewayDevice.DeviceInfo.SerialNumber", {value:null}).value[0];
// let unique_ts = serial + "_" + parseInt(ts, 10);
// let limit = ext("checkFirmware","counter", unique_ts);
// limit is boolean. If the limit has been reached or this provision has been run already (idempotency) limit will be true.
// script resets at midnight.
var redis = require('redis');
const TODAY_KEY = "today";
const LIMIT_KEY = "fw_update_count";
const LIMIT_PER_DAY = 200;
const REDIS_URL = null;
class redisCounter {
// written to run on node 6 and above. (no promisify on node 6)
constructor(today_key, fw_limit_key, limit, device_timestamp) {
this.today_key = today_key;
this.fw_limit_key = fw_limit_key;
this.limit = limit;
this.device_timestamp = device_timestamp;
this.client = redis.createClient(REDIS_URL);
// 'connect' can be used to check if connected.
this.client.on('error', function (err) {
console.log('Unable to connect to redis: ' + err);
process.exit(1);
});
}
prov_has_run_already() {
var self = this;
return new Promise((resolve, reject) => {
self.client.get(self.device_timestamp, function (err, reply) {
if (err) {
reject(err);
}
else {
if (reply === null) {
// this is first run
// set a key to expire in 30 seconds, value isn't important.
self.client.set(self.device_timestamp, "some_info", 'EX', 30);
resolve(false);
}
else {
resolve(true);
}
}
});
});
}
atCounterLimit() {
var self = this;
return new Promise((resolve, reject) => {
self.client.get(self.fw_limit_key, function (err, reply) {
if (err) {
reject(err)
}
else {
if (parseInt(reply, 10) < self.limit) {
self.client.incr(self.fw_limit_key);
resolve(false)
}
resolve(true)
}
});
});
}
resetCounter() {
this.client.set(this.fw_limit_key, 0)
}
keyIsToday() {
var self = this;
// checks if the passed in key is today. I.e if it's the 21st the key should be 21, if they key isn't today - it is set to today
// returns a promise with a value of true for today (or if key doesn't exist) and false if it's not today.
var todayAsDay = new Date().getDate();
return new Promise((resolve, reject) => {
self.client.get(self.today_key, function (err, reply) {
if (err) {
reject(err)
}
else {
switch (reply) {
case todayAsDay.toString(10):
resolve(true);
break;
default:
self.client.set(self.today_key, todayAsDay);
resolve(false);
}
}
});
});
}
close() {
this.client.quit()
}
}
function counter(device_ts, callback) {
// args is actually an array, doesn't say that in the Genieacs docs - just infers it.
counter = new redisCounter(TODAY_KEY, LIMIT_KEY, LIMIT_PER_DAY, device_ts[0])
// to make the script idempotent, we look at the timestamp passed by the provision
// it can run multiple times but will have the same timestamp.
counter.prov_has_run_already().then((isTrue) => {
if (isTrue) {
counter.close();
return callback(null, true);
}
// check if it's a new day - if it is reset the counter
counter.keyIsToday().then((keyIsToday) => {
if (!keyIsToday) {
// we need to reset the counter
counter.resetCounter();
}
//check if counter is at limit, if not, it gets incremented
counter.atCounterLimit().then((result) => {
counter.close();
callback(null, result);
}).catch((err) => {
counter.close();
callback(err);
});
}).catch((err) => {
counter.close();
callback(err);
});
}).catch((err) => {
counter.close();
callback(err);
});
}
exports.counter = counter;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment