Socket.io Troubles

I am trying to interface with a vendor's api with uses 'socket.io' as an interface process. I had to refractor both libraries and place them into a an uber-jar to avoid the io.py module naming-conflict. Now, when I run a main class on Netbeans, I am able to reach the socket serverio -- great! But when I import the jar into the Gateway and Designer folders, I am able create a socketio object, it just not seem to do anything... it would make method calls and it will not connect. The portion I wrote in Script Console is as close to the Main Class as I wrote in Java and that works.... I am stuck.

from logicz.io.socket.client import IO
from logicz.io.socket.client import Socket
from logicz.io.socket.emitter import Emitter

from java.lang.reflect     import Array
from java.net             import URI
from java.util             import Arrays
from java.util             import ArrayList
from java.util             import HashMap
from java.util             import List
from  java.util         import Map



#----------------------------------------#

# In Java, Emitter.Listener is an Interface Class with one 
# method-- call(Object...args){}


# Inherit class and, presumably, override method
class Listener_Any(Emitter.Listener):
            
    def call(self,*args, **kwargs):        
        print args


class Listener_CONNECT(Emitter.Listener):
    
    def call(self,*args):
        print("CONNECTED!")
        
            
#---------------------------------------#        

if __name__  == "__main__":
    
    
    url = "https://somecompany.com"
    
    # In Java, I used a hashmap successfully
    headers = HashMap()
    headers.put("Authorization",
                "someHasheads234o534nejrgtn")
    headers.put("InstallationId", 
                "adsfasd-sfgthtrherwt-asdfda")
    
        
    # In java:  String[] transport = {"websocket"};
    transport = ArrayList()
    transport.append("websocket")
    
    
    passedInGroupIds = "groupIds=1"
    
    # This builds the options for the socket.io connection
    options = IO.Options().builder()\
                .setForceNew(False)\
                .setMultiplex(True)\
                .setTransports(transport)\
                .setUpgrade(True)\
                .setRememberUpgrade(False)\
                .setPath("/api/oid/v1/")\
                .setQuery(passedInGroupIds)\
                .setExtraHeaders( headers )\
                .setReconnection(True)\
                .setReconnectionAttempts(3)\
                .setReconnectionDelay(1000)\
                .setReconnectionDelayMax(5000)\
                .setRandomizationFactor(0.5)\
                .setTimeout(5000)\
                .build()
    
        
    # Create the connection onject                                                                                            
    socket = IO.socket(URI.create(url), options)
    
    # Define what events to listen to.. here is on-connecction
    socket.on(Socket.EVENT_CONNECT, Listener_CONNECT())
    
    # Define what events to listen to.. here is listen to all events
    socket=socket.onAnyIncoming( Listener_Any() )
        
    # This should activate the socket connection
    socket.connect()

These lines are surely using the wrong syntax. You are calling each of these listener functions rather than passing references to them.

Hello, Kevin! Honored to have your insight!

So, the Emitter.Listener is a Java Interface Class, which needs an method override

 public static interface Listener {

        public void call(Object... args);
    }

In the git-hub library's readme / test-example, the 'socket' object stores these "socket.on.(, <Emitter.Listener>() )" method calls in a collection of Listeners which are someone waiting for those specified events to be generated from the server. Different method overrides seem to be perfectly fine in Netbeans -- here's one variant I have been using with Success

socket.onAnyIncoming(new Emitter.Listener() {
            @Override
           public void call(Object... args) {
               System.out.println("Incoming Message");
              for (int arg = 0;  arg < Array.getLength(args);  arg++){
                    System.out.println(args[arg]);
                    }                                 
               }        });   

Here is what happens when I do not construct the Listener Class...

If I just pass in the default Java Listener interface class, an error is thrown.

Oooh, my mistake. Sorry. It was early and I was on mobile. I see now those are classes implementing an interface and not callback functions.

I wonder if it's working but those callbacks are being made on a different thread and that causes the print statements to not get picked up by the console or something. Try writing to a memory tag in addition to printing?

I just tried this with no change in output -- edit just the socketio reference id is returned in the script console.

When there are object argz in Java (Netbeans):
-- argz0 is the topic and
-- argz[1] is the payload (json)

# Inherit class and, presumably, override method
class Listener_Any(Emitter.Listener):			
	def call(self,*args):			
		system.tag.writeBlocking(["[default]Elevators/Controller/results"], [args[0]])
		print args
		return

class Listener_CONNECT(Emitter.Listener):	
	def call(self,*args):
		print("CONNECTED!")
		return

Thought about doing an writeAnsync but I believe that is the whole point of the Emitter.Listener().call()

I'm not convinced either of these overloads you're attempting to use are actually being called by Jython. Emitter.Listener seems to expect a Java object array; the naive way I would expect that to translate to Jython would be a *args, but Jython might not actually be calling your implementation at all. Try a few different syntaxes for def call, e.g. def call(self), def call(self, args) and see if any of them get called.

I would also use system.util.getLogger to confirm any output from your scripts.

So.... here's an update:

I created my Jython interface class to create the Java objects...

# Define a class that interfaces with the Java Socket.IO library
class SocketIOClient:
	
     def __init__(self, uri, **options):
		
		self.logger = system.util.getLogger("SocketIO")
		
		# Create an IO.Options object
		io_options = IO.Options()
		
		# Convert and set path if provided
		if 'path' in options:
		    io_options.path = options['path']
		
		# Convert and set transports if provided
		if 'transports' in options:
		    java_transports = ArrayList()
		    for transport in options['transports']:
		        java_transports.add(transport)
		    io_options.transports = java_transports.toArray([String]*java_transports.size())
	      
 # blah, blah, blah

and I even wrote my listener classes which should were, in theory, overriding the Java interface class Listener. However, these the Listener method's were never being called by the socketio object... That is, until I embedded the new Listener Class INSIDE my SocketIO class... then everything worked.

# Define a class that interfaces with the Java Socket.IO library
class SocketIOClient:	

	# Define the AnyListener inner class
	class AnyListener(Emitter.Listener):
	    
	    def call(self, args):
	        # Here you can handle any incoming packets
	        # args is an array of objects received in the packet
	      	payload = {}
	      	payload["subscription"] = str(args[0])

I honestly don't know why it worked.. it was a hail-mary. Also, playing around with the args, *args, and **kwargs was helpful! Well @PGriffith , @Kevin.Herron , thank you again for the pointers!

1 Like