Skip to main content

WebSocket client

UniversalisWs connects to the Universalis WebSocket (wss://universalis.app/api/ws) and calls your listeners when listings or sales are added or removed. It is in the module universalis-ws.

UniversalisWs ws = UniversalisWs.getDefault()
.itemNameSupplier(Items.create())
.subscribe(Subscriptions.listingAdd().restrict(Worlds.europe().light()))
.subscribe(Subscriptions.salesAdd())
.registerListener(new ListenerAdapter() {
@Override
public void onListingAdd(ListingAddEvent event) {
System.out.println(event.listings().size() + " new listings of " + event.item().name().english());
}
})
.build();

Build the client​

UniversalisWs.getDefault() returns a builder with a connection timeout of 10 seconds. UniversalisWs.websocketBuilder() lets you set up the connection first: SSL (setSSLContext, setSSLSocketFactory), timeouts in milliseconds (setConnectionTimeout, setSocketTimeout), IPv4 and IPv6 (setDualStackMode, setDualStackFallbackDelay), setVerifyHostname and the server names for SNI. Its build() returns the same builder.

Builder methodWhat it does
subscribe(Subscription)Subscribes to a channel. See Subscriptions.
registerListener(EventListener...)Adds listeners for the events.
itemNameSupplier(NameSupplier)Adds names to the items. See Item names. The default adds none.
websocketUrl(String)Connects to another server.
eventThreadPool(ExecutorService)The executor that opens the connection.
build()Starts connecting in the background and returns the client.

build() returns before the connection is open. Call awaitReady() to wait until it is.

Subscriptions​

Subscriptions creates the channels:

MethodEvent
listingAdd()Listings were added.
listingRemove()Listings were removed.
salesAdd()Items were sold.
salesRemove()Deprecated. Sales were removed.

A subscription without a restriction covers every world. Restrict it with restrict(World), restrict(DataCenter) or forRegion(Region). You can call them more than once; the worlds add up. The client subscribes to one channel per world.

Subscription odinSales = Subscriptions.salesAdd().restrict(Worlds.europe().light().odin);

subscribe(Subscription) and unsubscribe(Subscription) on the client change subscriptions while it runs. While the client is connected the change is sent right away. The client keeps the list and subscribes to it again after every reconnect.

Events​

Implement EventListener, or extend ListenerAdapter and override only what you need.

MethodEventHolds
onListingAddListingAddEventitem(), world(), listings()
onListingRemoveListingRemoveEventitem(), world(), listings()
onListingUpdateListingUpdateEventitem(), world(), added(), removed()
onSalesAddSalesAddEventitem(), world(), sales()
onSalesRemoveSalesRemoveEvent (deprecated)item(), world(), sales()

Universalis has no update event. When someone uploads the market board, Universalis removes the old listings and adds the new ones. The client keeps each remove event for 10 seconds. When an add event for the same item on the same world follows, it calls onListingUpdate with the listings that were added and removed. The add and remove events are still delivered on their own.

Listings and sales are the same types as in the REST client.

Listeners run on the thread that reads from the WebSocket. Keep them short, or hand the work to your own executor, so the client keeps up with new messages.

Connection​

When the connection drops, the client connects again after 5 seconds and subscribes again. A failed connection attempt is retried every 5 seconds as well. disconnect() closes the connection and stops reconnecting.

awaitReady() blocks until the client is connected. awaitReady(Duration) waits at most the given time and returns whether the client is connected.