Dart exception when upgrading IndexedDB - dart

I get an exception when i try to upgrade my indexedDB database with a higher version then the browser currently has,
but the funny part abort is that, it gets upgraded. Is this by design or have i done something wrong.
I got very inspired from the dart sample Todo, so my code ended up looking like this.
void open_db(String DB_name, int Version, String Store_Name){
var request = window.indexedDB.open(DB_name, Version);
request.on.success.add((e) => _onDbOpened(request.result));
request.on.error.add((e) => print("Error opening db"));
request.on.upgradeNeeded.add((e) => _onUpgradeNeeded(request.transaction, Store_Name));
}
void _onDbOpened(IDBDatabase db){
_db = db;
print("DB opened");
}
void _onUpgradeNeeded(IDBTransaction changeVersionTransaction, String Store_Name){
changeVersionTransaction.on.error.add((e) => print("Error upgrading db"));
changeVersionTransaction.on.complete.add((e) => print("Success upgrading db"));
changeVersionTransaction.db.createObjectStore(Store_Name);
}
When I run this with version=4 and the browser only have version=3, then it jumps to _onUpgradeNeeded as expected, but I get an IDBDatabaseException with message: "ConstraintError: DOM IDBDatabase Exception 4".
So where is it I go wrong?

Thanks for your question!
You may need to check if the store exists first.
if (db.objectStoreNames.indexOf(storeName) == -1) {
db.createObjectStore(storeName);
}
Here is some code to update your IndexedDB database, using Dart. Note, this compensates for the two ways to upgrade (an old way that Chrome used, and the new way that Firefox and newer versions of Chrome use)
_openDb(afterOpen()) {
var request = window.indexedDB.open(DB_NAME, VERSION);
if (request is IDBOpenDBRequest) {
// New upgrade protocol. FireFox 15, Chrome 24, hopefully IE10.
request.on.success.add(expectAsync1((e) {
db = e.target.result;
afterOpen();
}));
request.on.upgradeNeeded.add((e) {
guardAsync(() {
_createObjectStore(e.target.result);
});
});
request.on.error.add(fail('open'));
} else {
// Legacy setVersion upgrade protocol. Chrome < 23.
request.on.success.add(expectAsync1((e) {
db = e.target.result;
if (db.version != '$VERSION') {
var setRequest = db.setVersion('$VERSION');
setRequest.on.success.add(
expectAsync1((e) {
_createObjectStore(db);
var transaction = e.target.result;
transaction.on.complete.add(
expectAsync1((e) => afterOpen()));
transaction.on.error.add(fail('Upgrade'));
}));
setRequest.on.error.add(fail('setVersion error'));
} else {
afterOpen();
}
}));
request.on.error.add(fail('open'));
}
}
_createObjectStore(db) {
try {
// Nuke object store if it already exists.
db.deleteObjectStore(STORE_NAME);
}
on IDBDatabaseException catch(e) { } // Chrome
on DOMException catch(e) { } // Firefox
db.createObjectStore(STORE_NAME);
}
Note, this code is from this test: http://code.google.com/p/dart/source/browse/trunk/dart/tests/html/indexeddb_3_test.dart

Related

Cannot get NFC write work on NativeScript 7 or 8

I forked the plugin nativescript-nfc and implemented the NFC write feature for iOS, it works well when using NativeScript 6. But if I upgrade the plugin to 7 or 8, the writing doesn't work, NFCNDEFTag.prototype.queryNDEFStatusWithCompletionHandler is always undefined.
The implementation of writing NFC is shown below.
readerSessionDidDetectTags(
session: NFCNDEFReaderSession,
tags: NSArray<NFCNDEFTag> | NFCNDEFTag[]
): void {
const tag = tags[0];
session.connectToTagCompletionHandler(tag, (error: NSError) => {
console.log("connectToTagCompletionHandler");
if (error) {
console.log(error);
session.invalidateSessionWithErrorMessage("Error connecting to tag.");
this.errorCallback(error);
return;
}
const ndefTag: NFCNDEFTag = new interop.Reference<NFCNDEFTag>(
interop.types.id,
tag
).value;
try {
NFCNDEFTag.prototype.queryNDEFStatusWithCompletionHandler.call(
ndefTag,
(status: NFCNDEFStatus, number: number, error: NSError) => {
console.log("queryNDEFStatusWithCompletionHandler");
if (status == NFCNDEFStatus.NotSupported) {
var errMessage = "Tag is not NDEF compliant.";
session.invalidateSessionWithErrorMessage(errMessage);
} else if (status === NFCNDEFStatus.ReadOnly) {
var errMessage = "Tag is read only.";
session.invalidateSessionWithErrorMessage(errMessage);
} else if (status === NFCNDEFStatus.ReadWrite) {
const ndefMessage = this._owner.get().message;
NFCNDEFTag.prototype.writeNDEFCompletionHandler.call(
ndefTag,
ndefMessage,
(error: NSError) => {
if (error) {
console.log(error);
session.invalidateSessionWithErrorMessage("Write failed.");
this.errorCallback(error);
} else {
if (
ndefMessage.records[0].typeNameFormat ==
NFCTypeNameFormat.Empty
) {
session.alertMessage = "Erased data from NFC tag.";
} else {
if (this.options.writeHint) {
session.alertMessage = this.options.writeHint;
}
this.resultCallback(NfcHelper.ndefToJson(ndefMessage));
}
session.invalidateSession();
}
}
);
}
}
);
} catch (e) {
session.alertMessage = "error";
}
});
}
I'm not sure if I implement it in the correct way for NativeScript 7 or 8, but at least it works on 6, I actually don't believe it's a bug in the NativeScript across both 7 and 8. We used to live with 6 for a long time just for using this plugin, but really need to upgrade to 7 or 8 for the sake of other features.
Any help, suggestion or comment would be highly appreciated!
Below is the repo and branches for different NativeScript versions.
Repo: https://github.com/nordsense/nativescript-nfc
Branch feature/upgrade-nativescript: This is NativeScript 8, only read works
Branch nordsense: This is NativeScript 6 and both read and write work
You can use the demo project to test, set ndef listener is for read and write Text is for write
I managed to get it working on NS 8. Referring to the below code snippet, if NFCNDEFTag.prototype is accessed before line 2, like the code in line 1 or by using console.dir(NFCNDEFTag.prototype), line 3 will dump the correct data that belongs to the correct protocol NFCNDEFTag, the remaining code also works well ; if commenting out line 1, line 3 will dump incorrect data which belongs to some other protocols/objects like NSKeyValueCoding and UIAccessibilityAction. I still don't know why this happens, feel like a NativeScript issue, I filed an issue here https://github.com/NativeScript/NativeScript/issues/9609
I rebuilt the plugin and published the package here https://github.com/cloudhx/nativescript-plugins
readerSessionDidDetectTags(session: NFCNDEFReaderSession, tags: NSArray<NFCNDEFTag> | NFCNDEFTag[]): void {
const prototype = NFCNDEFTag.prototype; // Line 1
const tag = (<NSArray<NFCNDEFTag>>tags).firstObject; // Line 2
console.dir(NFCNDEFTag.prototype); // Line 3
session.connectToTagCompletionHandler(tag, (error: NSError) => {
console.log('connectToTagCompletionHandler');
if (error) {
console.log(error);
session.invalidateSessionWithErrorMessage('Unable to connect to tag.');
this.errorCallback(error);
return;
}
const ndefTag: NFCNDEFTag = new interop.Reference<NFCNDEFTag>(interop.types.id, tag).value;
try {
NFCNDEFTag.prototype.queryNDEFStatusWithCompletionHandler.call(ndefTag, (status: NFCNDEFStatus, number: number, error: NSError) => {
console.log('queryNDEFStatusWithCompletionHandler');
// Code omitted for brevity

Client side functions doesn't call

I had lot of difficulties after upgrading signalR & .NET version.
Previously I had 1.XX version now I have 2.4.0 signal R version.
This question is directly connected with - https://github.com/SignalR/SignalR/issues/4339
But after upgrade signal R doesn't work.
Now the problem is client-side functions cannot call.
I just tried this: Signalr doesn't call client side functions
and fixed it according to the correct answer:
In your init prior to $.connection.hub.start call your _subscribe method.
Later I went through a bit deeper down on this issue, and added console.log below place in my signalr.js
connection.socket.onmessage = function (event) {
var data;
try {
console.log(event.data);
data = connection._parseResponse(event.data);
}
catch (error) {
transportLogic.handleParseFailure(connection, event.data, error, onFailed, event);
console.log("socket error" + event.data);
return;
}
if (data) {
transportLogic.processMessages(connection, data, onSuccess);
}
};
After every one joins meeting -> meeting start and ask for vote (this place we should call signalR)
From vote asking person side I see console log like this:
Normal user ( voting persons console log looks like this:
This is from Firefox - another user:
I think it already triggering - client hub event 'sendOnlineMeetingVoteRequest' on hub 'NotificationHub'.
It already hit server-side function too but the thing is it never hits this part of the code:
notificationHub.client.sendOnlineMeetingVoteRequest = function (token, meetingId, meetingVoteId) {
debugger;
if (token == '#Model.Organization' && '#Model.MeetingId' == meetingId) {
ShowMeetingOnlineMeetingVotePopup(meetingId, meetingVoteId);
}
};
I went through http://localhost:33852/signalr/hubs
/*!
* ASP.NET SignalR JavaScript Library v2.3.0-rtm
* http://signalr.net/
*
* Copyright (c) .NET Foundation. All rights reserved.
* Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
*
*/
/// <reference path="..\..\SignalR.Client.JS\Scripts\jquery-1.6.4.js" />
/// <reference path="jquery.signalR.js" />
(function ($, window, undefined) {
/// <param name="$" type="jQuery" />
"use strict";
if (typeof ($.signalR) !== "function") {
throw new Error("SignalR: SignalR is not loaded. Please ensure jquery.signalR-x.js is referenced before ~/signalr/js.");
}
var signalR = $.signalR;
function makeProxyCallback(hub, callback) {
return function () {
// Call the client hub method
callback.apply(hub, $.makeArray(arguments));
};
}
function registerHubProxies(instance, shouldSubscribe) {
var key, hub, memberKey, memberValue, subscriptionMethod;
for (key in instance) {
if (instance.hasOwnProperty(key)) {
hub = instance[key];
if (!(hub.hubName)) {
// Not a client hub
continue;
}
if (shouldSubscribe) {
// We want to subscribe to the hub events
subscriptionMethod = hub.on;
} else {
// We want to unsubscribe from the hub events
subscriptionMethod = hub.off;
}
// Loop through all members on the hub and find client hub functions to subscribe/unsubscribe
for (memberKey in hub.client) {
if (hub.client.hasOwnProperty(memberKey)) {
memberValue = hub.client[memberKey];
if (!$.isFunction(memberValue)) {
// Not a client hub function
continue;
}
// Use the actual user-provided callback as the "identity" value for the registration.
subscriptionMethod.call(hub, memberKey, makeProxyCallback(hub, memberValue), memberValue);
}
}
}
}
}
$.hubConnection.prototype.createHubProxies = function () {
var proxies = {};
this.starting(function () {
// Register the hub proxies as subscribed
// (instance, shouldSubscribe)
registerHubProxies(proxies, true);
this._registerSubscribedHubs();
}).disconnected(function () {
// Unsubscribe all hub proxies when we "disconnect". This is to ensure that we do not re-add functional call backs.
// (instance, shouldSubscribe)
registerHubProxies(proxies, false);
});
proxies['NotificationHub'] = this.createHubProxy('NotificationHub');
proxies['NotificationHub'].client = { };
proxies['NotificationHub'].server = {
sendMeetingStartMessage: function (token, meetingId) {
return proxies['NotificationHub'].invoke.apply(proxies['NotificationHub'], $.merge(["sendMeetingStartMessage"], $.makeArray(arguments)));
},
sendMeetingStopMessage: function (token, meetingId) {
return proxies['NotificationHub'].invoke.apply(proxies['NotificationHub'], $.merge(["sendMeetingStopMessage"], $.makeArray(arguments)));
},
sendMeetingTreeRefreshRequest: function (token, meetingId) {
return proxies['NotificationHub'].invoke.apply(proxies['NotificationHub'], $.merge(["sendMeetingTreeRefreshRequest"], $.makeArray(arguments)));
},
sendMessage: function (token, meetingId, agendaGroupItemId, motionId) {
return proxies['NotificationHub'].invoke.apply(proxies['NotificationHub'], $.merge(["sendMessage"], $.makeArray(arguments)));
},
sendOnlineMeetingVoteCloseRequest: function (token, meetingId, meetingVoteId) {
return proxies['NotificationHub'].invoke.apply(proxies['NotificationHub'], $.merge(["sendOnlineMeetingVoteCloseRequest"], $.makeArray(arguments)));
},
sendOnlineMeetingVoteRequest: function (token, meetingId, meetingVoteId) {
return proxies['NotificationHub'].invoke.apply(proxies['NotificationHub'], $.merge(["sendOnlineMeetingVoteRequest"], $.makeArray(arguments)));
},
sendOnlineVoteCloseRequest: function (token, meetingId, agendaGroupItemId, motionId) {
return proxies['NotificationHub'].invoke.apply(proxies['NotificationHub'], $.merge(["sendOnlineVoteCloseRequest"], $.makeArray(arguments)));
},
sendOnlineVoteRequest: function (token, meetingId, agendaGroupItemId, motionId) {
return proxies['NotificationHub'].invoke.apply(proxies['NotificationHub'], $.merge(["sendOnlineVoteRequest"], $.makeArray(arguments)));
},
sendOnlineVoteResult: function (token, meetingId, agendaGroupItemId, motionId, selectedVotingOptionId) {
return proxies['NotificationHub'].invoke.apply(proxies['NotificationHub'], $.merge(["sendOnlineVoteResult"], $.makeArray(arguments)));
}
};
return proxies;
};
signalR.hub = $.hubConnection("/signalr", { useDefaultPath: false });
$.extend(signalR, signalR.hub.createHubProxies());
}(window.jQuery, window));
So I didn't found any error on it too.
Still, I cannot figure it out why this is happening but I went through the sample project that uses signalR 2.0.3.0 version
I went to reference & just noted that this reference - Microsoft.AspNet.SignalR.Owin is not included in that sample project that I downloaded.
I did some investigation furthermore & find out this:
'The call is ambiguous between the following methods or properties'
This error will occur if a reference to Microsoft.AspNet.SignalR.Owin
is not removed. This package is deprecated; the reference must be
removed and the 1.x version of the SelfHost package must be
uninstalled.
(https://learn.microsoft.com/en-us/aspnet/signalr/overview/releases/upgrading-signalr-1x-projects-to-20)
Do I need to remove that?
In my web config, there is no code like this.
I just call this function purely from another place - about us page. only add relevant script and function.
from that place, it worked.
after that, I changed some scripts placing and fix this issue.
the main thing is I didn't get any error or anything. thing looks working all the time. but because of some script placement, it doesn't work.

Xamarin Mobile MediaPickerController Error after Migration to Unified API

I just migrate my Xamarin iOS app to Xamarin Unified using the Migration Tool.
The code below was working fine and the app didn’t have any error or warning before the migration.
After the migration I got the following errors
Error-1
PresentViewController doesn’t accept the MediaPickerController object as a parameter.
Error-2
mediaPickerController doesn’t have the method DismissViewController
protected void TakePicture()
{
MediaPickerController mediaPickerController = mediaPicker.GetTakePhotoUI(new StoreCameraMediaOptions
{
Name = this.PictureName + ".jpg",
DefaultCamera = CameraDevice.Rear
});
if (!mediaPicker.IsCameraAvailable)
{
ShowUnsupported();
}
//Error-1
PresentViewController(mediaPickerController, true, null);
try
{
mediaPickerController.GetResultAsync().ContinueWith(t =>
{
BTProgressHUD.Show("Processing");
// Dismiss the UI yourself
//Error-2
mediaPickerController.DismissViewController(true, () =>
{
if (t.IsCanceled || t.IsFaulted)
{
BTProgressHUD.Dismiss();
return;
}
MediaFile file = t.Result;
FinishedPickingMedia(file);
BTProgressHUD.Dismiss();
});
}, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (Exception ex)
{
Insights.Report(ex, ReportSeverity.Error);
}
}
Download the latest Xamarin.Mobile dll from here https://components.xamarin.com/view/xamarin.mobile and reference the lib/ios-unified/Xamarin.Mobile.dll instead of the old dll.
This will fix the errors.

Errors Message after migration to unified API

I just migrate my Xamarin iOS app to Xamarin Unified using the Migration Tool. The code below was working fine and the app didn’t have any error or warning before the migration. After the migration I got the following errors Error-1 PresentViewController doesn’t accept the MediaPickerController object as a parameter. Error-2 mediaPickerController doesn’t have the method DismissViewController
protected void TakePicture()
{
MediaPickerController mediaPickerController = mediaPicker.GetTakePhotoUI(new StoreCameraMediaOptions
{
Name = this.PictureName + ".jpg",
DefaultCamera = CameraDevice.Rear
});
if (!mediaPicker.IsCameraAvailable)
{
ShowUnsupported();
}
//Error-1
PresentViewController(mediaPickerController, true, null);
try
{
mediaPickerController.GetResultAsync().ContinueWith(t =>
{
BTProgressHUD.Show("Processing");
// Dismiss the UI yourself
//Error-2
mediaPickerController.DismissViewController(true, () =>
{
if (t.IsCanceled || t.IsFaulted)
{
BTProgressHUD.Dismiss();
return;
}
MediaFile file = t.Result;
FinishedPickingMedia(file);
BTProgressHUD.Dismiss();
});
}, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (Exception ex)
{
Insights.Report(ex, ReportSeverity.Error);
}
}
You need to update your Xamarin component that contains MediaPickerController to the latest version compatible with Xamarin.iOS unified code!
The latest version of Xamarin.Mobile is 0.7.6. Double check with your project if your are using an older one.

Wait for future to complete

I use my postgres database query to determine my next action. And I need to wait for the results before I can execute the next line of code. Now my conn.query returns a Future but I can't manage to get it async when I place my code in another function.
main() {
// get the database connection string from the settings.ini in the project root folder
db = getdb();
geturl().then((String url) => print(url));
}
Future geturl() {
connect(db).then((conn) {
conn.query("select trim(url) from crawler.crawls where content IS NULL").toList()
.then((result) { return result[0].toString(); })
.catchError((err) => print('Query error: $err'))
.whenComplete(() {
conn.close();
});
});
}
I just want geturl() to wait for the returned value but whatever I do; it fires immediately. Can anyone point me a of a piece of the docs that explains what I am missing here?
You're not actually returning a Future in geturl currently. You have to actually return the Futures that you use:
Future geturl() {
return connect(db).then((conn) {
return conn.query("select trim(url) from crawler.crawls where content IS NULL").toList()
.then((result) { return result[0].toString(); })
.catchError((err) => print('Query error: $err'))
.whenComplete(() {
conn.close();
});
});
}
To elaborate on John's comment, here's how you'd implement this using async/await. (The async/await feature was added in Dart 1.9)
main() async {
try {
var url = await getUrl();
print(url);
} on Exception catch (ex) {
print('Query error: $ex');
}
}
Future getUrl() async {
// get the database connection string from the settings.ini in the project root folder
db = getdb();
var conn = await connect(db);
try {
var sql = "select trim(url) from crawler.crawls where content IS NULL";
var result = await conn.query(sql).toList();
return result[0].toString();
} finally {
conn.close();
}
}
I prefer, in scenarios with multiple-chained futures (hopefully soon a thing of the past once await comes out), to use a Completer. It works like this:
Future geturl() {
final c = new Completer(); // declare a completer.
connect(db).then((conn) {
conn.query("select trim(url) from crawler.crawls where content IS NULL").toList()
.then((result) {
c.complete(result[0].toString()); // use the completer to return the result instead
})
.catchError((err) => print('Query error: $err'))
.whenComplete(() {
conn.close();
});
});
return c.future; // return the future to the completer instead
}
To answer your 'where are the docs' question: https://www.dartlang.org/docs/tutorials/futures/
You said that you were trying to get your geturl() function to 'wait for the returned value'. A function that returns a Future (as in the example in the previous answer) will execute and return immediately, it will not wait. In fact that is precisely what Futures are for, to avoid code doing nothing or 'blocking' while waiting for data to arrive or an external process to finish.
The key thing to understand is that when the interpreter gets to a call to then() or 'catchError()' on a Future, it does not execute the code inside, it puts it aside to be executed later when the future 'completes', and then just keeps right on executing any following code.
In other words, when using Futures in Dart you are setting up chunks of code that will be executed non-linearly.

Resources