Firefox SDK simple-storage and Firefox Sync - firefox-addon

I'm currently converting a Chrome extension into a Firefox add-on and would appreciate to replicate the chrome.storage.sync feature.
However, I cannot manage to find whether the data stored by a Firefox add-on using simple-storage will be automatically synced whenever a user of the add-on is signed into Firefox Sync.
Given that all the pieces of data stored via the latter method can be found in the user profile, I presume it will... as long as the add-on is available at https://addons.mozilla.org ?
Any information on the topic would be greatly appreciated.

simple-storage is not synced. But you can sync it with little effort.
The trick it to store the storage object, it is serializable by definition, as a string preference and tell to the sync service to synchronize it.
Lets name that preference syncstorage and mark it as synchronizable.
var self = require("sdk/self");
var prefs = require("sdk/preferences/service");
prefs.set("services.sync.prefs.sync.extensions." + self.id + ".syncstorage", true);
When storing something to simple-storage reflect the change to syncstorage.
var sp = require("sdk/simple-prefs");
var ss = require("sdk/simple-storage");
sp.prefs["syncstorage"] = JSON.stringify(ss.storage);
For the opposite effect watch syncstorage for changes
sp.on("syncstorage", function(prefname){
ss.storage = JSON.parse(sp.prefs["syncstorage"]);
})
Last but not least, It would nice and perhaps mandatory to sync only with the explicit consent of the user.

Related

Multiple user Video Call using WebRTC SDK Directly

Hi I am working on a Video Call Solution by using WebRTC directly. I have achieved 1-1 video call using firebase as Signaling service and using default google ICE Servers.
Core Req: Multiple users with in a Room using WebRTC at least 4 users using the default ice/stun servers available. I'm using pod 'GoogleWebRTC'
Issue comes when multiple users joins the same room ID.
So, I am maintaining Peerconnection reference as this
var peerConnection: RTCPeerConnection! = nil
When a new user i.e., remote user joins I set its description as below
self.peerConnection.setRemoteDescription(offer, completionHandler: {(error: Error?) in
if error == nil {
LOG("setRemoteDescription(offer) succsess")
self.makeAnswer() // Create Answer if setRemoteDescription succeeds
} else {
LOG("setRemoteDescription(offer) ERROR: " + error.debugDescription)
}
})
What I feel ? Issue is when third user joins again I set the remote Description with above mentioned code which makes my previous video stops to render sometimes or most of the times.
I looked for solutions and found need to maintain multiple peer connection references, but how? Any help with my requirement will be appreciated.
Just give me clue or sample code will be really great.
In case of multiple user call you should have multiple peerconnections, because it's isn't possible to set different sdps to one pc.
So you can use something like this
var peerConnectionMap = [String: RTCPeerConnection]()
Where String here is some constant user id.
When new user is joined to the room, then you create new pc and store it in this dictionary. Then you exchange with sdps as usual.
Don't forget that you should reuse local audio-video track created when first peerconnection is created.

Disable Realm Sync only for non-premium users

I'm creating an iOS application, where I intend to provide data sync across device feature, only to the premium users. I find Realm Sync as a good solution to keep the local on-device database and cloud MongoDB Atlas in sync. However, I don't want to sync the data of the non-premium users to the cloud database.
I'm enlisting a couple of ways that I can think of to prevent Realm Sync from triggering for non-premium users, but I'm not sure on what is the best way for this problem.
Prevent syncing by leveraging Sync permissions - I can store list of premium user ids and only give sync permissions to those users.
{
"%%user.id": [
"5f4863e4d49bd2191ff1e623",
"5f48640dd49bd2191ff1e624",
"5f486417d49bd2191ff1e625"
]
}
Configure Realm objects on client side i.e. only allow all Realm objects / models if the user is premium.
// Get a configuration to open the synced realm.
var configuration = user.configuration(partitionValue: "user=\(user.id)")
// For non-premium user it would be [User.self]
configuration.objectTypes = [User.self, Project.self]
Realm.asyncOpen(configuration: configuration) { [weak self](result) in /*...*/ }
I'm looking for insights / recommended approach to this problem.
Edit
I've a few additional questions about handling two use cases differently - non-premium one by opening a local only Realm() and the premium one with Realm.asyncOpen().
How to handle a use case when an existing user switches to a premium subscription? Should calling Realm.asyncOpen() suffice or do I need to do any special handling?
I plan to sync all my User (custom document in a collection) records for all users (premium + non-premium). My guess is I should open a normal Realm for all my conent and synced Realm with just [User.self] object in the configuration.
This is super easy to do!
When you only want to work with a local realm, connect to it with no config - like this
let realm = try! Realm()
let someObject = realm.results(SomeObject.self)
or a config that maybe contains a local file name. All of the app data will only be read and written locally with no sync'ing.
When you want to use MongoDB Realm Sync, connect to it like this
let app = App(id: YOUR_REALM_APP_ID)
// Log in...
let user = app.currentUser
let partitionValue = "some partition value"
var configuration = user!.configuration(partitionValue: partitionValue)
Realm.asyncOpen(configuration: configuration) { result in
switch result {
case .failure(let error):
print("Failed to open realm: \(error.localizedDescription)")
// handle error
case .success(let realm):
print("Successfully opened realm: \(realm)")
// Use realm
}
}
and then later with a config
let config = user?.configuration(partitionValue: "some partition")
let realm = try! Realm(configuration: config)
EDIT
Answering the two followup question:
How to handle a use case when an existing user switches to a premium
subscription? Should calling Realm.asyncOpen() suffice or do I need to
do any special handling?
Connecting to MongoDB Realm with the Sync'ding solution will add additional files and start syncing. If this is a new user that's 'premium', theres nothing else to do, other than (initially) ensure your objects are correctly structured with _id and partitionKey properties.
If this user is upgrading from a non-premium local only to a premium that's sync'd you will need to copy your realm objects from the local only realm to a sync'd realm.
There are several ways to to that; probably the simplist is to include code in your app then when upgrading, connects to a sync realm (using .async), then connects to your existing local realm and finally iterate over the objects to copy to the sync'd realm.
Another option is to export the the realm objects as JSON and then write them to the server directly. The next time your app connects with .async, it will force a client reset and download and create the locally sync'd files. There are some tidbits of information that may help with this particular process in the Realm Legacy Migration Guide
I plan to sync all my User (custom document in a collection) records
for all users (premium + non-premium). My guess is I should open a
normal Realm for all my conent and synced Realm with just [User.self]
object in the configuration.
Non-premium users don't sync so they are not really 'users' as such. You wouldn't need to store them or sync them so you really don't need any authentication or store any data on the server - it's just a locally run and used app so there isn't even a 'user' object to worry about. You will need to do that once they upgrade.

How can I persist Session data in a standalone web app after an external launch?

I have an MVC 5 mobile website that I am trying to make a standalone mobile web app running full screen on an iPhone. Everything works well until the app launches an external link that will, for example, launch in Safari. Upon returning to the web app the Session data seems to disappear and a new Session Id is assigned, wiping out any existing trace of previous user progress prior to the external launch. The User Name, however, remains intact and “logged in”. What do I need to do to persist the Session data?
I’ve been at this for hours now, googling and trying different approaches, but to no avail and my head is spinning. A similar post is HERE but my problem is the Session data.
Any help/direction would be greatly appreciated.
UPDATE 1
It seems that this behavior is limited to iOS -- currently testing on 9.3.3. Same behavior whether the "Back to [App] upper left link in the status bar is used or double-tap on the home button to return to WebApp. Android OSs seem to work just fine. Go figure. We are using cookies.
So it was a "Hail-Mary pass" but it worked... just persist the ASP.NET_SessionId cookie in javascript. It may have worked elsewhere but here's what I did:
In _Layout.vbhtml I added this to $(document).ready:
if (window.navigator.standalone || window.matchMedia('(display-mode: standalone)').matches) {
document.cookie = "ASP.NET_SessionId=#(Session.SessionID); " + extendTimeStr(5);
}
along with the function:
function extendTimeStr(extMins) {
var d = new Date();
d.setTime(d.getTime() + (extMins*60*1000));
return "expires="+ d.toUTCString();
}
Magically, it worked! Hope it helps someone.
Update for AspNetCore 2.0:
$(document).ready(function () {
if (('standalone' in window.navigator) && window.navigator['standalone']) {
var cookie = '#(Context.Request.Cookies[".AspNetCore.Identity.Application"])';
document.cookie = ".AspNetCore.Identity.Application=" + cookie + "; " + extendTimeStr(5);
}
})
Thank you #HumbleBeginnings for your excellent and simple solution to a problem I can't find answers to elsewhere!

iOS 7+: Unique identifier per device<->Store-ID (user) combination

I've spent two days no reading and testing as there is a lot of info about this topic.
Unfortunately I've found no solution yet. I can't implement my own authentication as this doesn't help with the issue I want to solve (see Backgrounding at the end of the question).
Here is my current best approach:
I'm generating a UUID thanks to https://stackoverflow.com/a/8677177/1443733 and storing it in the KeyChain as suggested with SwiftKeychainWrapper (https://github.com/jrendel/SwiftKeychainWrapper)
The short nice and sweet code for that is:
let stored = KeychainWrapper.stringForKey("UUID")
if stored != nil {
Helper.log(TAG, msg: "retrieved from keychain: \(stored!)")
} else {
let theUUID = CFUUIDCreate(nil)
let str = CFUUIDCreateString(nil, theUUID)
Helper.log(TAG, msg: "generated UUID: \(str)")
let ret = KeychainWrapper.setString(str, forKey: "UUID")
Helper.log(TAG, msg: "setkeychain: \(ret)")
}
But the UUID stored in the keychain seems to be per device and not per store ID as well.
When I store the UUID like above and login with a different Store ID on the device KeychainWrapper.stringForKey("UUID")still returns the value of the other user.
Isn't their a way to store a value in a store-id keychain?
It seems that I'm so close so I hope someone could point me in the right direction.
If that approach (with a keychain) can't succeed please let me know as well.
I reckon you can ask a different question as well: Is there some cryptic data I can read/generate or a store which changes with the Store Id currently used on a device?
Ohh... and Swift examples preffered ;)
Backgroundinfo:
I use IAPs in my app and want to save the Store-Id of the user once a refresh of the receipt is valid.
On each start of the app I check if the current Store-Id is the same as the saved one. If not I trigger immediately a refresh of the receipt. If it fails I fall back to the free version of the app.
iOS devices do not support multiple users.
If you want to differentiate between users you will have to do that in your app, perhaps with a user login. Then save a UUID per userID in the Keychain.
As NSUserdefaults temporarily stores the UUID.so,after unistalling the app and again installing,the UID changes. So, UUID must be stored in keychain

Azure Storage api doesn't work for asnyc uploads

I am trying to upload so many files via Azure Blob Storage .NET api and using with the current latest version 4.0.1. In ASP.NET MVC application i use async action method to upload via await blobFile.UploadFromStreamAsync but it really doesn't work and even i don't see an exception. It silently stops in that method without success.
But if i change action method to none-async and upload via blobFile.UploadFromStream method then everything to works well. I may uploaded via async way with 1% success rate that means very very low stability.
Do you experience same thing ? Is it bug in Storage Api implementation ?
Here is short example. One is async and the other one is none async action methods. There is no any problem if i upload small files but problem appears on large downloads. In this example UploadBlobSec method upload in short time but UploadBlob takes endless time.
public async Task UploadBlob()
{
var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureStorage"].ConnectionString);
var blobContainer = storageAccount.CreateCloudBlobClient().GetContainerReference("files");
var blobFile = blobContainer.GetBlockBlobReference("song.mp3");
using (var stream = new WebClient().OpenRead("http://apolyonstorage.blob.core.windows.net/files/e8b1a1fa-8791-44dc-92ce-1a67a62f7b0f.mp3"))
{
await blobFile.UploadFromStreamAsync(stream);
}
}
public void UploadBlobSec()
{
var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureStorage"].ConnectionString);
var blobContainer = storageAccount.CreateCloudBlobClient().GetContainerReference("files");
var blobFile = blobContainer.GetBlockBlobReference("song.mp3");
using (var stream = new WebClient().OpenRead("http://apolyonstorage.blob.core.windows.net/files/e8b1a1fa-8791-44dc-92ce-1a67a62f7b0f.mp3"))
{
blobFile.UploadFromStream(stream);
}
}
Code snippet looks fine - although I am not sure what the application around it is doing. Have you turned on server logs to see what is happening server side? For large files you should see the async upload translated into a couple of PutBlocks and then a PutBlockList. If you don't see the PutBlockList them maybe something strange is happening in your application.
Then assuming you do see the operations in the server logs that obviously means the operations are occurring. At that point look at the E2ELatency numbers vs ServerLatency I think you will see a large difference with E2Latency being much higher as it incorporates the time spent client side - and it would be interesting to see if your client network could be contributing to the problem. For example on my connection the e2elatency on the first PutBlock was 1346 ms vs 137 for ServerLatency.
For more information on logging take a look here.
Jason

Resources