Is it possible to cache information for use between Perspective client sessions

I haven't looked into this at all, but thought I'd ask. I want to be able to cache certain things in the client's device such as login information and other configuration they might customise so I can reload it the next time they open the client. This would be mostly relevant to mobile devices.
Is this possible? And if so, how would I do it? And if not, is it technically possible as a feature request?

Even if I write this data into a database table stored on the gateway. Can I get the details about the client such as a unique identifier that would remain constant across sessions? (clearly I have no Web dev experience, as I'm guessing the answer is pretty obvious)

EDIT: looks like I posted about this twice..

It should be possible to use a browser’s local storage, with permission from the user. You could probably do this today with the SDK.

Doing this in a first party way is something we’d like to do, but there’s no timeline or exact feature specification for that yet.
For now, you’d have to either use a custom module or a database, as mentioned.
session.props.device.identifier is a somewhat stable identifier. It’s not guaranteed to be stable, because the browser/mobile device/user could reset their cache/uninstall+reinstall the app, etc and get a new identifier, but it should be reasonably stable.

4 Likes

I currently do this for app config Settings, I keep a session custom prop that contains all the users preferences in an object, bind it to a named query, and then on changes update that json in the database. Works well for most things but credentials are the only place this would fail.

I look forward to seeing that kind of stuff built in, in the meanwhile I typically just require authentication on the project anyway so they don’t have to remember to login and are forced to. Not a perfect solution but it works

Notably this is the main way I handle maintaining a users preferred theme

5 Likes

I'm trying to do the same thing, but keep struggling on the update to the DB. How are you passing the object into the NamedQuery to insert into the DB? I was hoping to just send the JSON of the object, but the change script only seems to give me the qualified object.

I dont still have access to that project, however you should be able to take the currentValue.value and use system.util.jsonEncode()to turn it into a string that will fit in the database

Then bind it to a named query weith the users username as a parameter so when they login it pulls the version from the database

Tried that, but its gets weird…

This is the result in the DB

After running

	data = {'username':self.props.auth.user.userName, 'prefs': currentValue.value }
	system.db.runNamedQuery('ignition/updateUserPrefs', data)

on the change of session.custom.userPrefs

image

Put a system.util.jsonEncode(currentValue.value)

In the place of the current reference to currentValue.value, that should convert it into a string with none of the qualifying properties

To clarify: a JSON string, that when you bind it out afterwards you will want to use jsonDecode to turn back into a dictionary

1 Like

Still cant seem to get this working. If I do the above, the value in the DB becomes NULL.

I found another way, to do this by just using self.custom.userPrefs as the self object is the session object in this scope, BUT, it is a odd object and logs to the DB in the following format

<ObjectWrapper>: {u'subObject': <ObjectWrapper>: {u'key': u'value'}, u'theme': u'dark2', u'hello': u'workld'}

I tried looking at the java docs but I cant seem to find a way to just get this as basic JSON to log to the DB. It is coming across as an ObjectWrapper only.

This seems to work ok, but it only works for a single level object and seems like a hack, I seem to be missing something super simple here, don't know why storing this as JSON is so hard....

keys = self.custom.userPrefs.keys()
	
	prefs = {}
	for key in keys:
		prefs[key] = self.custom.userPrefs[key]
	
	data = {'username':self.props.auth.user.userName, 'prefs': system.util.jsonEncode(prefs) }
	system.db.runNamedQuery('ignition/updateUserPrefs', data)
from com.inductiveautomation.ignition.common import TypeUtilities
jsonStr = str(TypeUtilities.pyToGson(currentValue.value))

Try this?

Close, but still has qualified values for all the submembers....

{"theme":{"value":"light","quality":{"code":0},"timestamp":"Oct 13, 2020, 12:20:31 PM"}}

image

What version are you using, specifically? This area was actively in flux between 8.0.15 -> .16, though I think everything’s supposed to be resolved in 8.0.17/8.1.0 RC3/final.

ahhhh .16 right now Will hold out for .17 to try again.

This still seems to be an issue in 8.0.17, the output json including dictionary keys for each aspect of a qualified value.

1 Like

In the meanwhile this should work for you:

def make_values(obj):
    if hasattr(obj,'iteritems'):
        # dictionary
        ret = {}
        for k,v in obj.iteritems():
            ret[k] = make_values(v.value)
        return ret
    elif hasattr(obj,'__iter__'):
        # list (or the like)
        ret = []
        for item in obj:
            ret.append(make_values(item.value))
        return ret
    else:
        # anything else
        try:
            return obj.value
        except:
            return obj

preferences = make_values(currentValue.value)
2 Likes

Is this a feature that ever made its way to the backlog? While using a database for this is surely possible, it would be great if there was a cleaner first-party implementation of this

It’s still in the “thing we’d like to do” pile, but we don’t have an exact specification for implementation nor timeline for it.