File:BufferedQueue.js
/**
* @module Container
* @namespace springroll.pbskids
*/
(function(undefined)
{
// Import classes
var localStorage = include('localStorage');
var UUID;
var $ = include('jQuery');
/**
* Buffer event
* @class BufferedQueue
* @constructor
* @param {int} batchSize The number of events to buffer
* @param {string} keyPrefix The prefix key for local storage
* @param {string} eventServiceUrl The url
*/
var BufferedQueue = function(batchSize, keyPrefix, eventServiceUrl)
{
if (UUID === undefined)
{
UUID = include('springroll.pbskids.UUID');
}
/**
* If we're online
* @property {boolean} onlineStatus
*/
this.onlineStatus = true;
/**
* The buffer timer check
* @property {int} timer
*/
this.timer = null;
/**
* The buffer timer check
* @property {array} currentBatch
*/
this.currentBatch = [];
/**
* The keys intransit
* @property {object} inTransitKeys
*/
this.inTransitKeys = {};
/**
* The buffer key prefix
* @property {string} keyPrefix
*/
this.keyPrefix = keyPrefix;
/**
* The number of events to buffer
* @property {int} batchSize
*/
this.batchSize = batchSize;
/**
* Path to the end-point
* @property {String} eventServiceUrl
*/
this.eventServiceUrl = eventServiceUrl;
/**
* The name of the localstorage name for the queue
* @property {String} queueName
*/
this.queueName = 'bufferQueue' + UUID.genV4().hexString;
this.resetKey();
};
// Reference to the prototype
var p = BufferedQueue.prototype;
/**
* Process the batch of events
* @method processBatch
* @param {string} key The key to process
* @return {boolean} If the event is being processed
*/
p.processBatch = function(key)
{
var keys = this.inTransitKeys;
if (keys[key] === undefined)
{
var queueName = this.queueName;
keys[key] = 0;
$.ajax(
{
url: this.eventServiceUrl,
data: localStorage.getItem(key),
type: "POST",
contentType: "application/json",
dataType: "json",
success: function()
{
removeFromQueue(queueName, key);
localStorage.removeItem(key);
delete keys[key];
},
error: function(response)
{
if (DEBUG && window.console)
{
console.error("Response", response);
}
if (response.status == 400)
{
//400 is invalid
//data response from server for events
removeFromQueue(queueName, key);
localStorage.removeItem(key);
}
delete keys[key];
}
});
return true;
}
else
{
return false;
}
};
/**
* Remove an item to the queue by key
* @method removeFromQueue
* @private
* @param {String} queueName The name of the queue to remove from
* @param {String} key The key of the item to remove
*/
var removeFromQueue = function(queueName, key)
{
var bufferQueue = getBufferQueue(queueName);
var index = bufferQueue.indexOf(key);
if (index > -1)
{
bufferQueue.splice(index, 1);
localStorage.setItem(queueName, JSON.stringify(bufferQueue));
}
};
/**
* Add an item to the queue
* @method addToQueue
* @private
* @param {String} queueName The name of the queue
* @param {String} key The key of the item to push
*/
var addToQueue = function(queueName, key)
{
var bufferQueue = getBufferQueue(queueName);
var index = bufferQueue.indexOf(key);
// Only add the key once
if (index === -1)
{
bufferQueue.push(key);
localStorage.setItem(queueName, JSON.stringify(bufferQueue));
}
};
/**
* Add an item to the queue
* @method getBufferQueue
* @private
* @param {String} queueName The name of the queue to retrieve
* @return {Array} The list of keys
*/
var getBufferQueue = function(queueName)
{
try
{
return JSON.parse(localStorage.getItem(queueName)) || [];
}
catch (e)
{}
return [];
};
/**
* Start the buffer timer
* @method startTimer
*/
p.startTimer = function()
{
this.stopTimer();
this.timer = setInterval(
this._onTimerTick.bind(this),
1000
);
};
/**
* When the timer updates
* @method onTimerTick
* @private
*/
p._onTimerTick = function()
{
if (!this.onlineStatus) return;
var bufferQueue = getBufferQueue(this.queueName);
for (var i = 0; i < bufferQueue.length; i++)
{
if (this.processBatch(bufferQueue[i]))
{
break;
}
}
};
/**
* Stop the buffer timer
* @method stopTimer
*/
p.stopTimer = function()
{
clearInterval(this.timer);
this.timer = null;
};
/**
* Enable the queue
* @method enable
*/
p.enable = function()
{
this.inTransitKeys = {};
this.currentBatch.length = 0;
this.resetKey();
this.startTimer();
};
/**
* Disable the queue
* @method disable
*/
p.disable = function()
{
this.stopTimer();
};
/**
* Autoflush the event queue
* @method setAutoFlush
* @param {Boolean} on If we should autoflush
*/
p.setAutoFlush = function(on)
{
if (!on)
{
this.stopTimer();
}
else if (!this.timer)
{
this.startTimer();
}
};
/**
* Set the online status
* @method setOnline
* @param {Boolean} isOnline If we are online
*/
p.setOnline = function(isOnline)
{
this.onlineStatus = isOnline;
};
/**
* Push a new event
* @method pushEvent
* @param {object} event THe event data
*/
p.pushEvent = function(event)
{
this.inTransitKeys[this.bufferKey] = 0;
this.currentBatch.push(event);
localStorage.setItem(this.bufferKey, JSON.stringify(this.currentBatch));
addToQueue(this.queueName, this.bufferKey);
if (this.currentBatch.length >= this.batchSize)
{
this.currentBatch.length = 0;
delete this.inTransitKeys[this.bufferKey];
this.resetKey();
}
};
/**
* Flush all the event
* @method flushAll
*/
p.flushAll = function()
{
this.currentBatch.length = 0;
delete(this.inTransitKeys[this.bufferKey]);
this.resetKey();
if (!this.timer)
{
//timer is not running hence manually flush
var bufferQueue = getBufferQueue(this.queueName);
for (var i = 0; i < bufferQueue.length; i++)
{
this.processBatch(bufferQueue[i]);
}
}
};
/**
* Reset the buffer key
* @method resetKey
*/
p.resetKey = function()
{
this.bufferKey = this.keyPrefix + UUID.genV4().hexString;
};
/**
* End and clear the buffer
* @method end
*/
p.end = function()
{
this.currentBatch.length = 0;
delete(this.inTransitKeys[this.bufferKey]);
this.resetKey();
};
/**
* Destroy and don't use after this
* @method destroy
*/
p.destroy = function()
{
this.end();
this.currentBatch = null;
this.inTransitKeys = null;
this.stopTimer();
};
// Assign to namespace
namespace('springroll.pbskids').BufferedQueue = BufferedQueue;
}());