# Socket.io Troubles

**URL:** <https://forum.inductiveautomation.com/t/socket-io-troubles/81542>\
**Category:** Ignition\
**Tags:** scripting\
**Created:** [November 6, 2023, 12:44pm UTC](https://forum.inductiveautomation.com/t/socket-io-troubles/81542 "2023-11-06T12:44:32Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![rayerbear](https://avatars.discourse-cdn.com/v4/letter/r/b3f665/32.png) [@rayerbear](https://forum.inductiveautomation.com/u/rayerbear)\
**Post date:** [November 6, 2023, 12:44pm UTC](https://forum.inductiveautomation.com/t/socket-io-troubles/81542/1 "2023-11-06T12:44:32Z")

</div>

I am trying to interface with a vendor's api with uses '[socket.io](http://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.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/a/8/a8e7c483430a3899617ae15e80f72b1475eebe60.png)

```auto
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()

```

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [November 6, 2023, 1:12pm UTC](https://forum.inductiveautomation.com/t/socket-io-troubles/81542/2 "2023-11-06T13:12:16Z")

</div>

> [@rayerbear](#):
>
> ```auto
> # 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() )
> 
> ```

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

---

<div class="post-metadata">

**Author:** ![rayerbear](https://avatars.discourse-cdn.com/v4/letter/r/b3f665/32.png) [@rayerbear](https://forum.inductiveautomation.com/u/rayerbear)\
**Post date:** [November 6, 2023, 1:42pm UTC](https://forum.inductiveautomation.com/t/socket-io-troubles/81542/3 "2023-11-06T13:42:45Z")

</div>

Hello, Kevin! Honored to have your insight!

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

```auto
 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

```auto
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...

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/2/d/2df88cb3eec014d97c9d3e2de74fed415601d095.png)

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

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [November 6, 2023, 1:44pm UTC](https://forum.inductiveautomation.com/t/socket-io-troubles/81542/4 "2023-11-06T13:44:11Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![rayerbear](https://avatars.discourse-cdn.com/v4/letter/r/b3f665/32.png) [@rayerbear](https://forum.inductiveautomation.com/u/rayerbear)\
**Post date:** [November 6, 2023, 6:04pm UTC](https://forum.inductiveautomation.com/t/socket-io-troubles/81542/5 "2023-11-06T18:04:25Z")

</div>

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)

```auto
# 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()

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 6, 2023, 6:51pm UTC](https://forum.inductiveautomation.com/t/socket-io-troubles/81542/6 "2023-11-06T18:51:11Z")

</div>

> [@rayerbear](#):
>
> ```auto
> # 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!")
> 
> ```

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.

---

<div class="post-metadata">

**Author:** ![rayerbear](https://avatars.discourse-cdn.com/v4/letter/r/b3f665/32.png) [@rayerbear](https://forum.inductiveautomation.com/u/rayerbear)\
**Post date:** [November 9, 2023, 12:09am UTC](https://forum.inductiveautomation.com/t/socket-io-troubles/81542/7 "2023-11-09T00:09:02Z")

</div>

So.... here's an update:

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

```auto
# 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.

```auto
# 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 @paul-griffith , @Kevin.Herron , thank you again for the pointers!
