Logging out of perspective session with perspective.SessionInfo and perspective.logout

Hi all,

I'm currently working on a timer script that checks to see if the users that are logged into sessions exist in the database user-source and if they don't force a logout of that session.

currently this is the code I have in the scripting library:

def checkUser():
	logger = system.util.getLogger("checkUser")
	#Run a named query and store the dataset result
	ds = system.db.runNamedQuery("Admin_user/get_userInfo/get_allUserNames", {})
		
	#Convert the dataset result into a list
	usersList = ds.getColumnAsList(ds.getColumnIndex('username'))
	
	#Iterate through the list and pre-process all the names in the list for accurate comparison 
	for indx, val in enumerate(usersList):
		usersList[indx] = val.strip().lower()
		#logger.info(str(val))
		
	loggedInUsers = system.perspective.getSessionInfo()
	logger.info(str(loggedInUsers))
	loggedInUserNames = []
	for indx, val in enumerate(loggedInUsers):
	    loggedInUserNames.append(loggedInUsers[indx]['username'])
	
	logger.info(str(loggedInUserNames))
	for indx, name1 in enumerate(loggedInUserNames):
		if loggedInUsers[indx]['username'] not in usersList:
			forceRemove = loggedInUsers[indx]['id']
			forceRemovePage = loggedInUsers[indx]['pageIds']
			system.perspective.logout(sessionId = forceRemove, pageId = forceRemovePage, message = "Please Contact Admin about new username for : " + str(name1))
	

I'm uncertain how to fix the errors its giving me.
The current error is:

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 2, in File "", line 80, in checkUser at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:57) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.logout(PerspectiveScriptingFunctions.java:475) at jdk.internal.reflect.GeneratedMethodAccessor356.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Page "["2e36985f"]" not found.
at org.python.core.Py.JavaError(Py.java:547)
at org.python.core.Py.JavaError(Py.java:538)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:192)
at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:552)
at org.python.core.PyObject.__call__(PyObject.java:400)
at org.python.pycode._pyx9591.checkUser$2(:76)
at org.python.pycode._pyx9591.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyBaseCode.call(PyBaseCode.java:119)
at org.python.core.PyFunction.__call__(PyFunction.java:406)
at org.python.pycode._pyx9590.f$0(:2)
at org.python.pycode._pyx9590.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyCode.call(PyCode.java:18)
at org.python.core.Py.runCode(Py.java:1687)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:803)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:823)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:751)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:804)
at com.inductiveautomation.ignition.common.script.TimerScriptTask.run(TimerScriptTask.java:90)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.python.core.PyException: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Page "["2e36985f"]" not found.
... 26 common frames omitted
Caused by: java.lang.IllegalArgumentException: Page "["2e36985f"]" not found.
at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:57)
at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120)
at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47)
at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.logout(PerspectiveScriptingFunctions.java:475)
at jdk.internal.reflect.GeneratedMethodAccessor356.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
... 23 common frames omitted

Hopefully there is a simple solution to this issue.

Thank you,

Cam

That message suggests that the problem is at line 80 but you've only pasted 25 lines so I'm guessing it's a gateway script with more lines above or below it. Which is line 80?

The page not found suggests a system.perspective.closePage or similar being passed an invalid page ID.

Line 80 is:

system.perspective.logout(sessionId = forceRemove, pageId = forceRemovePage, message = "Please Contact Admin about new username for : " + str(name1))

Thats what I was thinking too but im grabbing the Page ID's right from the system.perspective.getSessionInfo() so am I using the wrong values?

I notice from the manual page that it returns,
pageIds - An array of page IDs that are currently open in the Session.

Are you handling the array correctly? (I don't know enough to say.)

I dont know enough to say either but I'll try and pass them in a different way I guess.

What if you just... Don't pass a page id? You're trying to end the whole session, so which page it is shouldn't matter.

Sessions may have multiple page IDs, so the pageIds attribute of the Session object is a list.
These lines

forceRemovePage = loggedInUsers[indx]['pageIds']
system.perspective.logout(sessionId = forceRemove, pageId = forceRemovePage, message = "Please Contact Admin about new username for : " + str(name1))

are attempting to supply a list of page id strings when the function expects a singular string.
The relevant part of the error message is this: java.lang.IllegalArgumentException: Page "["2e36985f"]" not found. See how the list of pageId strings is being cast as a string? The back-end is trying to act on that page, while an id of "2e36985f" exists, no id of "["2e36985f"]" does.

As @PGriffith suggested, you can just omit the pageId argument entirely, as that function doesn't really make use of the argument anyway.

Fair enough. I edited the code to be:

system.perspective.logout(sessionId = [forceRemove], message = "Please Contact Admin about new username for : " + str(name1))

However I'm now getting a 'UUID string too large' Error.

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 2, in File "", line 87, in checkUser at java.base/java.util.UUID.fromString(Unknown Source) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.getSession(AbstractScriptingFunctions.java:91) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:118) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.logout(PerspectiveScriptingFunctions.java:475) at jdk.internal.reflect.GeneratedMethodAccessor448.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: UUID string too large
at org.python.core.Py.JavaError(Py.java:547)
at org.python.core.Py.JavaError(Py.java:538)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:192)
at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:552)
at org.python.core.PyObject.__call__(PyObject.java:400)
at org.python.pycode._pyx9950.checkUser$2(:81)
at org.python.pycode._pyx9950.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyBaseCode.call(PyBaseCode.java:119)
at org.python.core.PyFunction.__call__(PyFunction.java:406)
at org.python.pycode._pyx9949.f$0(:2)
at org.python.pycode._pyx9949.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyCode.call(PyCode.java:18)
at org.python.core.Py.runCode(Py.java:1687)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:803)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:823)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:751)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:804)
at com.inductiveautomation.ignition.common.script.TimerScriptTask.run(TimerScriptTask.java:90)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.python.core.PyException: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: UUID string too large
... 26 common frames omitted
Caused by: java.lang.IllegalArgumentException: UUID string too large
at java.base/java.util.UUID.fromString(Unknown Source)
at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.getSession(AbstractScriptingFunctions.java:91)
at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:118)
at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47)
at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.logout(PerspectiveScriptingFunctions.java:475)
at jdk.internal.reflect.GeneratedMethodAccessor448.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
... 23 common frames omitted

You don't want those square brackets.
system.perspective.logout(sessionId = forceRemove, message = "Please Contact Admin about new username for : " + str(name1))

system.perspective.logout(sessionId = forceRemove, message = "Please Contact Admin about new username for : " + str(name1))

is giving me this error:

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 2, in File "", line 87, in checkUser at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:64) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.logout(PerspectiveScriptingFunctions.java:475) at jdk.internal.reflect.GeneratedMethodAccessor448.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: No perspective page attached to this thread.
at org.python.core.Py.JavaError(Py.java:547)
at org.python.core.Py.JavaError(Py.java:538)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:192)
at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:552)
at org.python.core.PyObject.__call__(PyObject.java:400)
at org.python.pycode._pyx9954.checkUser$2(:81)
at org.python.pycode._pyx9954.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyBaseCode.call(PyBaseCode.java:119)
at org.python.core.PyFunction.__call__(PyFunction.java:406)
at org.python.pycode._pyx9953.f$0(:2)
at org.python.pycode._pyx9953.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyCode.call(PyCode.java:18)
at org.python.core.Py.runCode(Py.java:1687)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:803)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:823)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:751)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:804)
at com.inductiveautomation.ignition.common.script.TimerScriptTask.run(TimerScriptTask.java:90)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.python.core.PyException: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: No perspective page attached to this thread.
... 26 common frames omitted
Caused by: java.lang.IllegalArgumentException: No perspective page attached to this thread.
at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:64)
at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120)
at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47)
at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.logout(PerspectiveScriptingFunctions.java:475)
at jdk.internal.reflect.GeneratedMethodAccessor448.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
... 23 common frames omitted

This is strange to me, because in the sessionInfo function it is printing that the user I want removed is in the list of online users with the correct session ID I'm passing it.

u'id': '2cabd449-52e1-4cbb-bdb7-08e274025e97', u'username': 'test_one', u'authorized': True

Well, that's unfortunate. Turns out logout requires a page context (you can omit the session; it'll be retrieved from the page), specifically because (as far as I can tell from the code) it has to tell each running page "hey, log out now".

I got it to work.

    logger = system.util.getLogger("checkUser")
	#Run a named query and store the dataset result
	ds = system.db.runNamedQuery("Admin_user/get_userInfo/get_allUserNames", {})
		
	#Convert the dataset result into a list
	usersList = ds.getColumnAsList(ds.getColumnIndex('username'))
	
	#Iterate through the list and pre-process all the names in the list for accurate comparison 
	for indx, val in enumerate(usersList):
		usersList[indx] = val.strip().lower()
		
	loggedInUsers = system.perspective.getSessionInfo()
	loggedInUserNames = []
	for indx, val in enumerate(loggedInUsers):
	    loggedInUserNames.append(loggedInUsers[indx]['username'])
	
	for indx, name1 in enumerate(loggedInUserNames):
		if loggedInUsers[indx]['username'] not in usersList:
			forceRemoveSession = loggedInUsers[indx]['id']
			forceRemovePage = loggedInUsers[indx]['pageIds']
			for indx, page in enumerate(forceRemovePage):
				try:
					system.perspective.logout(sessionId = forceRemoveSession, pageId = forceRemovePage[indx], message = "Please Contact Admin about new username for : " + str(name1))
				except:
					logger.info("Tried to remove user: Failed")

The function seems to want both the session ID and page ID. Without both you get "Not perspective thread" errors.

1 Like