Skip to content

Conversation

@douglascayers
Copy link
Contributor

@douglascayers douglascayers commented Nov 13, 2025

Background

A variation of #1042 based on the comment thread there about extending the factory function concept further to abstract the Ros class from socket implementations.

Changes

  • Replaces SocketAdapter with Transport, which provide an abstraction over socket implementations (native WebSocket, ws npm module, socket.io, RTC, etc).
  • Removed RTC web socket implementation. Users who need it can provide their own TransportFactory modeled after the WebSocketTransportFactory.
  • Errors when handling socket messages to be parsed into RosbridgeMessage are now emitted by the transport rather than console logged or swallowed. Gives calling code an easier programmatic option to be notified of these issues.
  • Updated type definitions for a few utilities.
  • Add and update tests.
  • Changed event connection to open to be consistent with the underlying socket event type.
  • Ros emits the open, close, and error events as pass-throughs of whatever value the transport emitted (e.g. string, Error, Event, etc)

Example Usage

// -- Example 1 -- //

// Defaults to WebSocket transports
// Uses native WebSocket if available, else the "ws" node module
const ros = new Ros();

// -- Example 2 -- //

// Customize the WebSocket implementation
// This example specifies the handshake timeout
const ros = new Ros({
  transportFactory: async (url: string): ITransport => {
    const socket = new ws.WebSocket(url, {
      handshakeTimeout: 30_000,
    });
    socket.binaryType = "arraybuffer";
    return new WsWebSocketTransport(socket);
  },
});

// -- Example 3 -- //

// Bring your own transport with full control
// over encoding/decoding messages
const MyCustomTransport extends EventEmitter implements ITransport {
  constructor(url: string) {
    // connect to the url however you wish
    // when receive messages from the server,
    // broadcast them via `this.emit("message", ...)`
  }

  send(message: RosbridgeMessage): void {
    // roslib wants to send a message to the server
    // serialize and send the message however you wish
  }

  close(): void {
    // disconnect from the server
  }

  // lifecycle methods to mirror WebSocket spec
  isConnecting(): boolean { ... }
  isOpen(): boolean { ... }
  isClosing(): boolean { ... }
  isClosed(): boolean { ... }
}

const ros = new Ros({
  transportFactory: async (url: string): ITransport => {
    return new MyCustomTransport(url);
  },
});

Copy link
Collaborator

@EzraBrooks EzraBrooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, just some nits

@EzraBrooks
Copy link
Collaborator

btw I'm planning on really highlighting this feature in the 2.0 release notes because it's cool and it will help anyone who was relying on the almost-certainly-unmaintained NodeTCP and RTC transports :)

@EzraBrooks
Copy link
Collaborator

Since this is nearly there, I'm gonna poke at it, if you don't mind. really trying to get 2.0 out the door before I get busy at my new job 😆

@EzraBrooks
Copy link
Collaborator

oop, except this PR doesn't have "allow changes from maintainers" enabled

@EzraBrooks
Copy link
Collaborator

EzraBrooks commented Nov 13, 2025

Here's a proposed change to allow fully lazy-loading ws. With this, once the tests are adjusted to pass, I think we're good to merge.

0001-Move-WsWebSocketTransport-to-lazy-loaded-file.patch

@douglascayers
Copy link
Contributor Author

oop, except this PR doesn't have "allow changes from maintainers" enabled

Sorry about that! I don't even see where I can enable it =/

I'll work on getting the patch applied. Confused why the tests are failing, they all pass locally 🤔

@EzraBrooks
Copy link
Collaborator

Yeah I think it defaults to being turned off when the source branch is from an organization

@EzraBrooks
Copy link
Collaborator

Confused why the tests are failing, they all pass locally

probably need to reinstall deps, since I changed the underlying PNG package

@douglascayers
Copy link
Contributor Author

Confused why the tests are failing, they all pass locally

probably need to reinstall deps, since I changed the underlying PNG package

Yep, thanks, I'm reworking the tests that were mocking pngparse

@douglascayers
Copy link
Contributor Author

Changes pushed, ready for CI to run 😎

@douglascayers
Copy link
Contributor Author

[Vitest] Unexpected .only modifier.

doh, removing that...

Copy link
Collaborator

@EzraBrooks EzraBrooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. will re-run that flaked test. need to figure out what the deal with that is.. it happens like 1% of the time

@EzraBrooks EzraBrooks enabled auto-merge (squash) November 13, 2025 20:25
@EzraBrooks
Copy link
Collaborator

thanks so much for the contribution and sorry for the back-and-forth!

@EzraBrooks EzraBrooks merged commit fb75aa9 into RobotWebTools:develop Nov 13, 2025
13 of 14 checks passed
@douglascayers
Copy link
Contributor Author

Woo hoo! Happy to have contributed, thanks for shepherding this project forward 👏

@douglascayers douglascayers deleted the ros-transport-factory branch November 13, 2025 20:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants