`Socket.io-client` doesn't work?

Hi,
I’ve set up a bare, local node.js/Socket.IO server, and a Photoshop UXP prototype plugin that loads Socket.io-client and should connect with it.

I can’t make it work: the very same UXP/client code, copied verbatim into a React application connects flawlessly, hence I think that UXP has some incompatibility with Socket.IO. Although it doesn’t fire any error whatsoever (it even logs the io object and the socket).

Is this a known limitation?
Thanks!

Davide

By coincidence either @bootsie123 or @jake-pauls was just showing me some websocket thing this morning…

1 Like

Websockets are OK, it’s Socket.IO that is problematic :slight_smile:

Hi Davide!

Just want to clarify your implementation.

  • How are you ‘requiring’ the socket-io.client package? Through a <script> tag? Or through an npm dependency?
  • Are you running the Socket.IO server that you’re trying to connect to locally?

I recently did create a sample plugin that uses Socket.IO and it’s client library in order to manipulate websockets. The code for my socket.io-client implementation can be found on my branch.

The client side, as you’re also facing, was probably one of the trickier parts in implementing it that I found. If you’re running the socket server locally, you can grab the socket.io-client package from the server, however your code will throw errors if the server isn’t connected. In the end, I just used Webpack to bundle the npm dependency with my code so that it was always there.

That being said, I never had any abnormal behaviour with UXP/Socket.IO that wasn’t due to including the client package, so I’m curious as to what you’re facing.

Let me know! :grinning_face_with_smiling_eyes:

Hi @jake-pauls!
Mine is a React project (bundled with Webpack), which sourcecode is as follows:

import { useEffect, useState } from "react";
const io = require('socket.io-client');
const socket = io('http://localhost:3000');

console.log({io});         // logs it fine
console.log({socket}); // logs it fine too

const App = () => {

  const [isConnected, setIsConnected] = useState(socket.connected);
  const [lastMessage, setLastMessage] = useState(null);

  useEffect(() => {
    try {
      socket.on('connect', () => {
        setIsConnected(true);
        console.log(socket.id)
        socket.emit("hello")
      });
      socket.on('disconnect', () => {
        setIsConnected(false);
      });
      socket.on('message', data => {
        setLastMessage(data);
      });
      return () => {
        socket.off('connect');
        socket.off('disconnect');
        socket.off('message');
      };
    } catch(e) { console.error(e) }
  })

  const sendMessage = () => {
    socket.emit('hello!');
  }

  return (<>
    <sp-heading size="s">Socket.IO</sp-heading>
    <sp-body>Connected: {'' + isConnected}</sp-body>
    <sp-body>Last message: {lastMessage || '-'}</sp-body>
    <sp-button onClick={sendMessage}>Say hello!</sp-button>
  </>)
}
export default App

The server couldn’t be simpler:

const io = require('socket.io')(3000, {
  cors: {
    origin: "*",
    methods: ['GET', 'PUT', 'POST']
  }
});

io.on('connection', socket => {
  console.log(`connect: ${socket.id}`);

  socket.on('hello!', () => {
    console.log(`hello from ${socket.id}`);
  });

  socket.on('disconnect', () => {
    console.log(`disconnect: ${socket.id}`);
  });
});

setInterval(() => {
  io.emit('message', new Date().toISOString());
}, 1000);

Same code in a React app, as expected:

My sad panel instead…

It seems to get both io and the socket correctly, but doesn’t seem willing to connect, I can’t really figure out why…
Do you see anything wrong? Thanks!

Davide

EDIT: I’ve tried both on PS-release and PS-prerelease (with manifest v4 and v5), no luck.

1 Like

Hi @jake-pauls,

It’s the same for me. I tried running your Plugin/Desktop Helper Sample which fails to connect. Ended up using websocket for now, but socket io would be better.

1 Like

Thanks for this @DavideBarranca. I’ll take a look into this today.

Also, thanks for pulling the sample @keer4n. This is the second time that’s happened so I’m going to spend some time and figure out what’s going on. I totally understand the preference for Socket.IO, which was a main reason why I built the sample!

1 Like

Hi everyone,

I recreated a UXP plugin with @DavideBarranca’s React/Socket code and here was my result

Whether its good news or bad news :sweat_smile: the bug wasn’t replicated on my machine. Regarding the Desktop Helper Sample, I also did a clean pull, install, and demo of that and it ran fine. After, I jumped in a call with @bootsie123 and he also was able to install and run both plugins successfully.


@DavideBarranca is there anyway you could run the Socket.IO server with a debug flag? For instance:

DEBUG=socket* node src/index.js       # Or whichever file/method you're running the server from

On my machine it clearly connects and pings the related timestamps every second. I’d be curious to see what the output on your end is doing. :thinking:


As for @keer4n, are you using a Mac? Although I suspect that’s the case, if you do happen to be using Windows, I’d recommend checking out the quick video I made, to really quickly ensure that all the build/setup steps are ok! If it’s still not working on Windows then I can keep diving into it.


However, @bootsie123 and I are thinking this could be a platform issue of some kind, since we were both running Windows 10 and I know both @DavideBarranca and @kerrishotts (who had troubles running the helper sample) are running Mac.

I feel like it’s either a platform specific issue with Socket.IO (which is weird considering it obviously works in a browser on Mac) or its specifically UXP/Mac that is having issues with Socket.IO.

Definitely going to try and spin this up on a Mac soon, but I thought I’d drop an update.

2 Likes

Still no joy…! Arrgh! :slight_smile:

@jake-pauls would you be so kind to zip both the exact uxp plugin and server code you’re using and put it somewhere e.g. GDrive? That’s a mystery! I’ve tried also changing ports, checking the UXP Dev Tool Service port (just in case) but it still doesn’t want to connect, I’m really puzzled…
BTW, is @kerrishotts still unable to run it on Mac?
Thanks for your time, much appreciated Jake!

Davide

SOLVED! :wine_glass:

The trick (at least for me) was to add an explicit transports prop in the options, both on the client and the server.

Phew!

6 Likes

Yes, I’m on mac @jake-pauls, @DavideBarranca solution works for me too. Thanks.

1 Like

WOW! Glad you were able to solve this (apologies for being silent here; had other things to attend to).

I wonder what transports is causing socket.io to do – I wonder if there’s some various discovery mechanisms that are failing on macOS… Glad this works, though – that’s easy enough to doc.

Actually I read that on a few StackOverflow posts, but I was always looking at the Server side code, when I added it on the Client too, confetti fell from the sky :tada:
At the moment I’m using ["websocket", "polling"] — no idea whether adding the latter makes it any better, but it’s free so why not :blush:

1 Like

Glad you got it to work in the end! I finally got a chance to run everything on macOS and it seems like it’s an issue in the way Socket.IO setups up its default transports.

By default io initializes with [ "polling", "websocket" ] as its transports. This means that it will start out with making HTTP requests through polling and then upgrade the connection to websockets if possible.

It seems for some reason on macOS polling results in an HTTP error on the client. I haven’t looked too much into it yet to see where the exact problem lies, but essentially this means that it can’t connect to the server to then establish a websocket connection. However, by setting the transports to [ "websocket" ], you essentially force Socket.IO into only connecting through websockets which bypasses the need for polling.

Looking into this further, it seems it might be an issue with the way Socket.IO sends requests and how UXP handles them. Monitoring localhost with Wireshark reveals that the request itself is failing before it even gets sent. This is particularly weird considering that the URLs are all reachable. Might be something for one of the developers to take a look at in their free time

1 Like

Small update from my previous reply:

After talking with @kerrishotts it looks like it’s part of the security in macOS which causes HTTP requests to localhost to be blocked (which causes polling to error out). If you change the URL from localhost:3000 to 127.0.0.1:3000 everything seems to work fine. Hope this helps!

You’re correct! I would swear that I tried 127.0.0.1 before writing this, but to the best of my recollections I was using 127.0.0.0, silly me… :sweat_smile:
Thanks again,

Davide

@DavideBarranca do you remember what socket.io version you were using? Im kinda in the same situation but your solution didn’t work for me.

I tried this but it doesn’t work. My Socket.IO server and client is 4.7.5

On Windows I reported error with ping/pong messages… if message is empty string it never sends. On MacOS this works. Not sure what Socket.IO sends.

Second issue I reported is missing WebSocket class is missing static constants for socket status. Those are present only on instance of class but not class itself as static properties. So I had to add them to fix it.

Maybe there is more… also check the manifest permissions.

Also if you have plugin installed and you load it additionally in UDT you can have same plugin loaded twice but in UI you see only one of them. Therefore instead of one client you can have two clients and they can fight over the connection if you need 1:1 relation :smiley: