<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://wiki.socialstack.dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Andythenuge</id>
	<title>SocialStack - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.socialstack.dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Andythenuge"/>
	<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Special:Contributions/Andythenuge"/>
	<updated>2026-10-16T09:05:47Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.36.2</generator>
	<entry>
		<id>https://wiki.socialstack.dev/index.php?title=Websockets&amp;diff=450</id>
		<title>Websockets</title>
		<link rel="alternate" type="text/html" href="https://wiki.socialstack.dev/index.php?title=Websockets&amp;diff=450"/>
		<updated>2023-02-09T16:24:12Z</updated>

		<summary type="html">&lt;p&gt;Andythenuge: /* Sending a message from the server */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Websockets in SocialStack use a non-allocating binary format called bolt in order to be extremely high speed and high throughput, capable of handling over a million messages per second on a single socket link without causing any problems. The server code is in the Api/WebSockets module, and the frontend code is in UI/Functions/WebSocket. Both ends can be setup to create multiple websocket clients or multiple websocket servers but of course a default project creates 1.&lt;br /&gt;
&lt;br /&gt;
Note that the websocket itself does not currently directly support TLS (https), just like the web API as well. Instead that is added by a reverse proxy in front of the API service which is typically [https://www.nginx.com/ nginx] (&amp;#039;&amp;#039;pronounced &amp;quot;Engine X&amp;quot;&amp;#039;&amp;#039;) in most deployments.&lt;br /&gt;
&lt;br /&gt;
= Sending a message from the server =&lt;br /&gt;
&lt;br /&gt;
To send a custom message through the websocket, you&amp;#039;ll need a Writer. Typically these originate from a pool such that they get reused. Here&amp;#039;s an example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
// Import websocket library&lt;br /&gt;
using Api.SocketServerLibrary;&lt;br /&gt;
&lt;br /&gt;
// Get a pooled writer:&lt;br /&gt;
var message = Writer.GetPooled();&lt;br /&gt;
&lt;br /&gt;
// Start writing to it (this is a required call). The number is opcode of the message - that&amp;#039;s effectively the message identifier on the wire.&lt;br /&gt;
message.Start(15);&lt;br /&gt;
&lt;br /&gt;
// Write the contents of the message. See the wiki&amp;#039;s reccommendations for some guidance on this.&lt;br /&gt;
message.WriteUTF8(&amp;quot;Hello world!&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Write a number:&lt;br /&gt;
message.Write((uint)1337);&lt;br /&gt;
&lt;br /&gt;
// Assuming you have a WebSocketClient object:&lt;br /&gt;
// WebSocketClient client;&lt;br /&gt;
client.Send(message);&lt;br /&gt;
&lt;br /&gt;
// You can send the same message to multiple clients if you want.&lt;br /&gt;
// Once you have sent it and you&amp;#039;re done, release it. This returns it back to the pool.&lt;br /&gt;
message.Release();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tips on writing a message ==&lt;br /&gt;
&lt;br /&gt;
* Give yourself some flexibility for making changes to the contents of the message, but you don&amp;#039;t need too much. You can always just send a message with a different opcode as the newer version format.&lt;br /&gt;
* Try to avoid writing strings, particularly things like JSON, as much as possible. Building a typical string on the server is quite expensive for multiple reasons, and if you&amp;#039;re trying to make realtime high throughput sockets then JSON is not going to fit the bill.&lt;br /&gt;
* However, the ToJson method inside all AutoService&amp;#039;s is non-allocating and outputs in to a writer, so it&amp;#039;s ok to use that or any equivalent. It internally uses generated code and custom implementations of number writing to avoid all string concatinations and intermediate allocations.&lt;br /&gt;
* Favour writing value types. Numbers, floats, dates and so on - are all extremely fast, as they effectively go from the stack and straight to the network buffer.&lt;br /&gt;
* WriteCompressed uses a fast compression scheme originally from the MySQL binary protocol which will store a long or ulong in the smallest number of bytes it reasonably can. It&amp;#039;s of course always suggested to make your message as small as you can, but sometimes there are instances where a constant length (in bytes) number is useful, such as a length for the message itself.&lt;br /&gt;
* If you want to write a length for some currently unknown amount of data, first write a 0 as a fixed size value - usually that&amp;#039;s .Write((uint)0) - then write everything you want, then measure the number of bytes written and replace the 0 with the measured size. This avoids needing to create copies of things in memory, and also avoids needing to awkwardly figure out what the length should be by adding things together.&lt;br /&gt;
&lt;br /&gt;
= Receiving the message in the client =&lt;br /&gt;
&lt;br /&gt;
The websocket client library exports a function, registerOpcode, which can be used to register a handler which runs when a message of the given opcode is received. Its job is to then parse the message from the given stream.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import webSocket from &amp;#039;UI/Functions/WebSocket&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
// Registering opcode 15 sent above&lt;br /&gt;
webSocket.registerOpcode(15, (reader) =&amp;gt; {&lt;br /&gt;
&lt;br /&gt;
// Read the string:&lt;br /&gt;
var helloMessage = reader.readUtf8();&lt;br /&gt;
&lt;br /&gt;
// Read the uint:&lt;br /&gt;
var leetNumber = reader.readUInt32();&lt;br /&gt;
&lt;br /&gt;
console.log(helloMessage, leetNumber); // Hello world! and 1337&lt;br /&gt;
&lt;br /&gt;
}, false);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Sending a message from the client =&lt;br /&gt;
&lt;br /&gt;
Like with the server, you&amp;#039;ll need a writer. Note that client to server messages always require a size at the start. The javascript websocket library has a Writer class available, which will also internally take care of that size for you:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
import webSocket from &amp;#039;UI/Functions/WebSocket&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
var writer = new webSocket.Writer(15);&lt;br /&gt;
writer.writeUtf8(&amp;quot;Hello world!&amp;quot;);&lt;br /&gt;
writer.writeUInt32(1337);&lt;br /&gt;
&lt;br /&gt;
// Send it:&lt;br /&gt;
webSocket.send(writer);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Andythenuge</name></author>
	</entry>
</feed>