Accessing indexedDB from code inside a Blob - javascript

First I've to explain the scenario:
Kiosk web app with CHROMIUM, showing LOCAL webs. That is, no webserver installed. Chromium is always showing "file:///" pages.
The reason is: sometimes, the computer can be offline (network issues, wifi range...).
Requirement: we want to use google analytics. When computer is ONLINE, the system send http request to GA normally. When OFFLINE, we want to save http request to indexedDB.
Using a worker that executes a job each X seconds, we test the Internet connection. If success, the worker gets the http requests saved into indexedDB and send to Google Analytics.
We've achieved all steps, but one: accesing indexedDB from javascript code inside a Blob.
The reason to use a js Worker inside a Blob is because Chrome don't allow accesing javascript files when the scenario is locally (File:///). This is a small example of a Worker inside a Blob, that access indexedDb each 3 seconds. The example works great in Firefox, for example. But in Chrome, this exception is launched when executing code that access to indexedDb from Blob code:
Unhandled rejection: OpenFailedError: SecurityError Failed to execute
'open' on 'IDBFactory': access to the Indexed Database API is denied
in this context.
<html>
<head>
<title>Example error blob and indexeddb</title>
</head>
<body>
<p>This example demostrate that javascript code inside a Blob can't access indexedDb in Chrome.</p>
<p>Click 'Start WebWorker' to create a Worker inside a Blob. This worker tries to insert some<br>
data into a database created in 'startWorker()' function.</p>
<button type="button" onclick="startWorker()" id="btnStart">
Start WebWorker
</button>
<button type="button" onclick="stopWorker()" id="btnStop">
Stop WebWorker
</button>
<!-- FOR LOGGING INFO PURPOSES -->
<p id="demo"></p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<!-- TRICK !! Declare this block of type 'javascript/worker' or something non-standard.
Later we can create on the fly javascript executable code
using a Blob (see 'window.onload' function later on this file)
-->
<script id="worker" type="javascript/worker">
var started = false;
var timer;
onmessage = function (event)
{
var orden = event.data.toString();
switch (orden)
{
case 'start':
start();
break;
case 'stop':
stop();
break;
default:
notRecognized(orden);
break;
}
}
function start()
{
if( ! started)
{
timer = setInterval(function(){ job() }, 3000);
started = true;
}
}
function stop()
{
if(started)
{
clearInterval(timer);
started = false;
}
}
//Executed each 3 seconds (see start() )
function job()
{
// Open the database -> ERROR!! Uncaught SecurityError: Failed to execute 'open' on 'IDBFactory':
// access to the Indexed Database API is denied in this context.
var open = indexedDB.open("MyDatabase", 1);
open.onsuccess = function()
{
// Start a new transaction
var db = open.result;
var tx = db.transaction("MyObjectStore", "readwrite");
var store = tx.objectStore("MyObjectStore");
var index = store.index("NameIndex");
// Add some data
store.put({id: 12345, name: {first: "John", last: "Doe"}, age: 42});
store.put({id: 67890, name: {first: "Bob", last: "Smith"}, age: 35});
// Close the db when the transaction is done
tx.oncomplete = function()
{
db.close();
};
}
}//end job()
function notRecognized(orden)
{
var mensaje = 'Comando no reconocido';
selt.postMessage(mensaje + ': ' + orden);
}
</script>
<script type="text/javascript">
var myWorker;
var workerStarted = false;
//Al cargar la pagina, se llama al onload, que carga el WebWorker
window.onload = function () {
var blob = new Blob([ document.querySelector('#worker').textContent ], {type : 'text/javascript'});
myWorker = new Worker(window.URL.createObjectURL(blob));
myWorker.onmessage = function (event)
{
document.getElementById("demo").textContent = event.data; //cambiamos el texto del <p>
console.log("Got: " + event.data + "\n");
};
myWorker.onerror = function (error)
{
document.getElementById("demo").textContent = "Worker error: " + error.message;
console.log("Worker error: " + error.message + "\n");
throw error;
};
};//e onload
//click en botón iniciar, mandamos 'start' al worker
function startWorker()
{
if(workerStarted)
{
document.getElementById("demo").textContent = "Worker yet started !";
return;
}
//Create the DataBase
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB;
// Open (or create) the database
var open = indexedDB.open("MyDatabase", 1);
// Create the schema
open.onupgradeneeded = function() {
var db = open.result;
var store = db.createObjectStore("MyObjectStore", {keyPath: "id"});
var index = store.createIndex("NameIndex", ["name.last", "name.first"]);
};
workerStarted = true;
//Start Worker
myWorker.postMessage('start');
}
//click en botón parar, mandamos 'stop' al worker
function stopWorker() {
myWorker.postMessage('stop');
}
</script>
</body>
</html>

Related

Problems with multiple websockets (over time)

TLDR: My websockets stop connecting after a while, though they work perfectly at first. How do I fix it?
I have a C# web service that makes use of two websockets (via websocket-sharp). They are defined like so:
public WebSocketServer sock1= new WebSocketServer("ws://localhost:802");
sock1.Log.Level = WebSocketSharp.LogLevel.Error;
sock1.Log.File = "LOG\\logfile.LOG";
sock1.AddWebSocketService<StatusWebSocket1>("/");
sock1.KeepClean = false;
sock1.Start();
public WebSocketServer sock2= new WebSocketServer("ws://localhost:803");
sock2.Log.Level = WebSocketSharp.LogLevel.Error;
sock2.Log.File = "LOG\\logfile.LOG";
sock2.AddWebSocketService<StatusWebSocket2>("/");
sock2.KeepClean = false;
sock2.Start();
These websocket servers accept client connections from my angularjs app:
$scope.socket = null;
var startStopPolling = function(action){
if(action == 'close'){
$scope.socket.close(3001, 'User leaving page.');
return;
}
var path = 'ws://' + window.location.hostname + ':802/';
$http({method: 'GET', url: apiRoot+'is-remote', timeout: 1000})
.success(function(response) {
path = 'wss://' + window.location.hostname + '/';
}).finally(function(){
$scope.socket = new WebSocket(path);
$scope.socket.onerror = function(event){
console.log('SOCKET ERROR', event);
$timeout(startStopPolling, 1000);
};
$scope.socket.onopen = function(){
var selfInfo = {
locationCode: $scope.LocationCode,
token: BrowserStorageService.get('token'),
type: 'ClientRegistration',
mode: 'status'
};
$scope.socket.send(JSON.stringify(selfInfo));
$scope.socket.onmessage = function(event){
var data = JSON.parse(event.data);
//do some stuff with data
});
};
};
});
};
startStopPolling();
And elsewhere:
var socket2 = null;
var startStopPolling2 = function(action){
if(action == 'close'){
socket2.close(3001, 'App closing.');
return;
}
var path2 = 'ws://' + window.location.hostname + ':803/';
socket2 = new WebSocket(path2);
socket2.onerror = function(event){
console.log('SOCKET ERROR', event);
$timeout(startStopPolling2, 1000);
};
socket2.onopen = function(){
var selfInfo = {
mode: 'status2',
type: 'ClientRegistration'
};
socket2.send(JSON.stringify(selfInfo));
socket2.onmessage = function(event){
var data = JSON.parse(event.data);
console.log('status2', data.status2);
if(data.status2 == "Closed"){
$state.go("status");
}
};
};
};
startStopPolling2();
$rootScope.$on('$destroy', function(){
startStopPolling2('close');
});
The application mostly sits on one page. (We display a status page most of the time, but allow the user to navigate away to do things like manage configuration.) When we receive a certain status value from the status2 socket (socket2), we want to do some things, so we have to keep track of that all the time. The other socket is only relevant when on that page, so we want to get rid of it when we don't need it.
Here's the problem: The app periodically refreshes the page via a call like location.reload(true). Wile it works perfectly at first, after so many of these refreshes, the sockets no longer connect. There are no errors in the console, and neither onOpen() function fires. What's going on, and how do I fix it?

titanium iOS app for adhoc distribution stuck on splash screen

I'm running a titanium iOS application, it works as expected on the simulator and also on the device when I run it from appcelerator studio, however when I package the app for adhoc distribution and install it on my iPhone device via iTunes it just gets stuck on the splash screen.
Also I can not debug because it is adhoc distribution. The only thing I noticed using alerts is that it runs through alloy.js but never gets to index.js
Any help would be appreciated.
edit: these are my index and alloy files.
index.js
// Arguments passed into this controller can be accessed via the `$.args` object directly or:
var args = $.args;
var webServices = require("webService");
var TAG = "[loginActivity.js] : ";
var fb = Alloy.Globals.Facebook;
var win = $.window;
var core = require("core");
var network = require("NETWORK");
sessionStatus = Ti.App.Properties.getBool('session');
console.log("session estatus "+sessionStatus);
if(!sessionStatus)
Ti.App.Properties.setBool('session', false);
sessionStatus = Ti.App.Properties.getBool('session');
console.log("session estatus "+sessionStatus);
Ti.App.session=sessionStatus;
manageLogin();
Ti.App.addEventListener('resumed',function(e){
//check if login is still valid
console.log("hola");
manageLogin(); //I just reuse my login logic on resume
});
function manageLogin(){
if(Ti.App.session==false){
// require("core").openLogin;
console.log("abro login");
openLogin();
}else{
console.log("abro main");
Ti.App.User_id= Ti.App.Properties.getInt('User_id');
//Ti.App.profIm =Ti.App.Properties.getObject('image');
require("core").openMainActivity();
}
}
function openLogin(){
console.log("First attempt to use geolocation services.");
var hasLocationPermissions = Ti.Geolocation.hasLocationPermissions(Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE);
Ti.API.info('Ti.Geolocation.hasLocationPermissions', hasLocationPermissions);
if (hasLocationPermissions) {
console.log("GPS permissions granted.");
open();
} else {
console.log("Second attempt");
Ti.Geolocation.requestLocationPermissions(Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE, function(e) {
if (e.success) {
// $.index.open();
open();
} else {
console.log("Something happened during second attempt");
if (OS_ANDROID) {
//alert('You denied permission for now, forever or the dialog did not show at all because you denied it forever earlier.');
var activity = Titanium.Android.currentActivity;
activity.finish();
open();
}
// We already check AUTHORIZATION_DENIED earlier so we can be sure it was denied now and not before
Ti.UI.createAlertDialog({
title : 'You denied permission.',
// We also end up here if the NSLocationAlwaysUsageDescription is missing from tiapp.xml in which case e.error will say so
message : e.error
}).show();
}
});
}
}
function open(e) {
var nextWin = core.createWindow({
controllerName : "loginActivity"
});
if (OS_ANDROID) {
nextWin.fbProxy = Alloy.Globals.Facebook.createActivityWorker({lifecycleContainer: nextWin});
}
nextWin.addEventListener("postlayout", function checkGPS(e){
nextWin.removeEventListener("postlayout", checkGPS);
if(Ti.Geolocation.getLocationServicesEnabled() === false) {
if(OS_ANDROID){
var alertDlg = Titanium.UI.createAlertDialog({
title:'GPS apagado',
message:'El GPS está apagado. Enciéndelo en ajustes.',
buttonNames: ['No encender el gps', 'Abrir ajustes']
});
alertDlg.cancel = 0;
alertDlg.addEventListener('click', function(e){
if(!e.cancel) {
//open up the settings page
var settingsIntent = Titanium.Android.createIntent({
action: 'android.settings.LOCATION_SOURCE_SETTINGS'
});
Titanium.Android.currentActivity.startActivity(settingsIntent);
}
});
alertDlg.show();
}
else {
alert("No se detecta tu ubicación, te recomendamos encender el GPS antes de iniciar la aplicación.");
}
}
});
nextWin.open();
}
and alloy.js
(function(){
var ACS = require('ti.cloud'),
env = Ti.App.deployType.toLowerCase() === 'production' ? 'production' : 'development',
username = Ti.App.Properties.getString('acs-username-'+env),
password = Ti.App.Properties.getString('acs-password-'+env);
// if not configured, just return
if (!env || !username || !password) { return; }
/**
* Appcelerator Cloud (ACS) Admin User Login Logic
*
* fires login.success with the user as argument on success
* fires login.failed with the result as argument on error
*/
ACS.Users.login({
login:username,
password:password,
}, function(result){
Ti.API.info("Yes, logged in.");
if (env==='development') {
Ti.API.info('ACS Login Results for environment `'+env+'`:');
Ti.API.info(result);
}
if (result && result.success && result.users && result.users.length){
Ti.App.fireEvent('login.success',result.users[0],env);
} else {
Ti.App.fireEvent('login.failed',result,env);
}
});
})();
Alloy.Globals.Facebook = require('facebook');
var T = function (name) {
return require('T/' + name);
};
T('trimethyl');
var Notifications = T('notifications');
Notifications.onReceived = function(e) {
console.log("onreceived "+JSON.stringify(e));
alert(e.data);
};
Notifications.subscribe();
console.log("token "+Notifications.getRemoteDeviceUUID());
For future references.
I had to test step by step, block by block and line by line using a single alert at a time to find out what part of the code was causing the application to crash.
I did find out that 2 separate files were calling each other like require("file2") in file 1 and require("file1") in file 2. Although I don't know why this problem/bug/whatever happened only in distribution ad-hoc mode and not when running the app directly from the computer.

Check if no Internet Connection - Popup - Windows 10 App(Javascript)

Hello,
i searching around the internet, and can't find a full "tutorial", how to write a code, that's if no internet connection automatically shows a error message. I started with the Visual Studio to create a Windows 10 App with Javascript. I searched around, and found some examples with jQuery or AJAX on stackoverflow, but seem's not working for my application. Can someone share a code, that i can put in my application?
I creating a app for my Website, with some addition features, and it's need's internet connection.
Thanks
you can use the NetworkConnectivityLevel, NetworkInformation.getInternetConnectionProfile and getNetworkConnectivityLevel to do this, and show the information with a MessageDialog in the default.js like this:
var connections = Windows.Networking.Connectivity.NetworkInformation.getInternetConnectionProfile();
if (connections != null) {
var networkConnectivityLevel = connections.getNetworkConnectivityLevel();
if (networkConnectivityLevel == Windows.Networking.Connectivity.NetworkConnectivityLevel.internetAccess) {
var msg = new Windows.UI.Popups.MessageDialog("Internet access OK.");
} else if (networkConnectivityLevel == Windows.Networking.Connectivity.NetworkConnectivityLevel.constrainedInternetAccess) {
var msg = new Windows.UI.Popups.MessageDialog("Limited internet access.");
} else if (networkConnectivityLevel == Windows.Networking.Connectivity.NetworkConnectivityLevel.localAccess) {
var msg = new Windows.UI.Popups.MessageDialog("Local network access only.");
} else if (networkConnectivityLevel == Windows.Networking.Connectivity.NetworkConnectivityLevel.none) {
var msg = new Windows.UI.Popups.MessageDialog("No internet access.");
}
msg.showAsync();
} else {
var msg = new Windows.UI.Popups.MessageDialog("No internet access.");
msg.showAsync();
}
$.get('/').fail(function(){
//request failed for some reason. probably internet down
console.log("your internet is down");
});
You can use some HTTP test service as follows:
<html>
<body>
<div id="status" style="width:100px;height:40px;"></div>
<script>
function GetConnectionStatusToElement(element) {
var request = new XMLHttpRequest();
request.open("GET", "https://httpbin.org/", true);
request.onload = function () {
element.innerHTML = "Connected";
};
request.onerror = function () {
element.innerHTML = "Not Connected";
};
request.send();
}
GetConnectionStatusToElement(document.getElementById("status"));
</script>
</body>
<html>

Why is chrome showing error " The object store currently does not support blob values" when trying to store file in IndexedDB?

I am new to Javascript and IndexedDB. Currently I am writing code for a simple utility which uploads file(s) and stores them in IndexedDB. Then user has the option of either seeing the file names or the contents of the file, which is directly read from stored files in IndexedDB.
Following is my javascript code-
var db;
var display="";
function indexedDOok(){
return "indexedDB" in window;
}
document.addEventListener("DOMContentLoaded", function(){
if(!indexedDOok())
return;
var openRequest = indexedDB.open("fileIndex", 1);
openRequest.onupgradeneeded = function(e){
var thisDB = e.target.result;
if(!thisDB.objectStoreNames.contains("docs")){
thisDB.createObjectStore("docs", {autoIncrement:true});
console.log("Database upgrading....");
}
};
openRequest.onsuccess = function(e){
db = e.target.result;
console.log("Database created");
document.querySelector("#fileSelector").addEventListener("change", handleFileSelection, false);
document.querySelector("#displayButton").addEventListener("click", displayContent, false);
document.querySelector("#getButton").addEventListener("click", getFiles, false);
};
openRequest.onerror = function(e){
console.log(e.target.result);
};
}, false);
function handleFileSelection(e){
console.log("Inside file selection handler...");
var files = e.target.files;
if(!files){
console.log("Files selection failed. Select again");
return;
}//if
try{
var transaction = db.transaction(["docs"],"readwrite");
}catch(ex){
console.log("Exception in opening transaction, "+ex.message);
return;
}//catch
transaction.onerror = function(evt){
console.log("transaction.onerror() fired in handleFileSelection(), error code: "+ (evt.target.error? evt.target.error: evt.target.errorCode));
};
transaction.onabort = function(){
console.log("transaction.onabort() fired in handFileSelection()");
};
transaction.oncomplete = function(){
console.log("transaction.oncomplete() fired in handFileSelection()");
};
try{
var store = transaction.objectStore("docs");
for(var i=0; i<files.length; i++){
file = files[i];
var request = store.put(file);
request.onsuccess = function(){
console.log(files.length);
console.log(file.name+" has been successfully added in table");
};
request.onerror = function(evt){
console.log("Error..."+file.name+" file not added", evt.target.error.name);
};
}
} catch(ex){
console.log("Transaction and/or put() exception in adding file to database...."+ ex.message);
return;
}
};
function getFiles(){
var transaction = db.transaction(["docs"],"readonly");
var cursor = transaction.objectStore("docs").openCursor();
var s ="";
cursor.onsuccess = function(e){
var res = e.target.result;
console.log("Cursor created");
if(res){
s+= "<p>"+res.value.name+"</p>";
res.continue();
}
document.querySelector("#content").innerHTML = s;
};
};
function displayContent(){
var transaction = db.transaction(["docs"],"readonly");
var cursor = transaction.objectStore("docs").openCursor();
document.querySelector("#content").innerHTML = "";
cursor.onsuccess = function(e){
console.log("Inside displayContent() cursor success...");
var res = e.target.result;
if(res){
console.log(res.value.name+ " is loaded");
readerFile(res.value);
res.continue();
}
};
display="";
};
function readerFile(e){
var reader = new FileReader();
reader.readAsText(e);
reader.onload = function(ex){
var rawData = reader.result;
display = document.querySelector("#content");
display.innerHTML = display.innerHTML + "<h2> "+e.name+ "</h2>";
display.innerHTML = display.innerHTML + rawData;
};
}
Following is my index.html
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="files/dbFile.js"></script>
</head>
<body>
<input type="file" id="fileSelector" multiple>
<br><br>
<button id="displayButton">Display Content</button>
<button id="getButton">Display Files</button>
<pre id="content"></pre>
</body>
</html>
It is running successfully in all the browsers. Files are getting uploaded and stored and also getting read and displayed. But only in Chrome it's giving the error "Failed to execute 'put' on 'IDBObjectStore': The object store currently does not support blob values."
Following is the output of Chrome's console, when I try uploading a file-
Database upgrading....
Database created
Inside file selection handler... dbFile.js:38
Transaction and/or put() exception in adding file to database....Failed to execute 'put' on 'IDBObjectStore': The object store currently does not support blob values. dbFile.js:75
transaction.oncomplete() fired in handFileSelection()
Can someone please help me. Why is this happening? I did a lot of research but found nothing helpful

How do we connect video streaming from different tokens generated for a single session using openTok

I want to Connect all the users in a session by providing them separate token under a sessionId, so that they can view each other's streaming. But users can see only their straming. I just need to allocate div on my page for each user with a token connected to any particular sessionId.
This is the code using which users can see their streaming only
<script src="http://static.opentok.com/webrtc/v2.0/js/TB.min.js" ></script>
<script src="https://static.opentok.com/webrtc/v2.0/js/TB.min.js" ></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
var publisher;
var session;
var apiKey = "44686132";
var sessionId = "1_MX40NDY4NjEzMn4xMjcuMC4wLjF-V2VkIE1hciAxOSAyMDo1ODozNyBQRFQgMjAxNH4wLjAzMTA3MTAwN34";
var token = document.getElementById("<%= hdn1.ClientID %>").value;
publisher = TB.initPublisher(apiKey);
session = TB.initSession(sessionId);
session.connect(apiKey, token);
session.addEventListener("sessionConnected",
sessionConnectedHandler);
session.addEventListener("streamCreated",
streamCreatedHandler);
function sessionConnectedHandler(event) {
alert("sessionConnectedHandler");
subscribeToStreams(event.streams);
session.publish(publisher);
}
function subscribeToStreams(streams) {
if (stream.connection.connectionId
!= session.connection.connectionId) {
//var streams = event.streams;
for (var i = 0; i < streams.length; i++) {
var stream = streams[i];
var newDivId = "streams" + stream[i].streamId;
var newDiv = $('<div />', { id: newDivId });
$('body').append(newDiv);
if (stream.connection.connectionId
!= session.connection.connectionId) {
session.subscribe(stream[i], newDivId);
}
}
}
}
function streamCreatedHandler(event) {
subscribeToStreams(event.streams);
}
</script>
Moreover, alert("sessionConnectedHandler"); inside
function sessionConnectedHandler(event) never gets called. What am I doing wrong here?
Please consult your browser console, it will help you solve most of your problems. Here's a few quick bugs I have discovered in your code:
You included the javascript library multiple times.
Your token is probably retrieved incorrectly. Please print your token out in the console and verify that it looks like a token and not null or give you an error.
subscribeToStreams method takes in an array of streams. stream variable in the method is not defined anywhere

Categories