A .NET server SDK for interacting with the Sockudo WebSocket server HTTP API. Publish events, authorize channels, handle webhooks, and query application state from your .NET applications.
- .NET 6+
- .NET Standard 2.0
- Installation
- Getting started
- Configuration
- Triggering events
- Authenticating channel subscription
- End-to-end encryption
- Querying application state
- Webhooks
- License
Install-Package SockudoServer
dotnet add package SockudoServerThe minimum configuration required to use the Sockudo object are the three constructor arguments that identify your app: app id, app key, and app secret.
using Sockudo;
var options = new SockudoOptions
{
Host = "127.0.0.1",
Port = 6001,
Encrypted = false,
};
var sockudo = new Sockudo(APP_ID, APP_KEY, APP_SECRET, options);For best practice, create a Sockudo singleton and reuse it across your application.
Note: The Host property overrides the Cluster property. If Host is set, Cluster is ignored.
In addition to the three app identifiers, you can specify other options via SockudoOptions:
| Property | Type | Description |
|---|---|---|
Host |
String | The Sockudo server host name, excluding the scheme; for example, "127.0.0.1". Overrides Cluster if specified. |
Port |
Integer | The HTTP API port. If Encrypted is true, defaults to 443. If Encrypted is false, defaults to 80. |
Encrypted |
Boolean | Indicates whether calls to the HTTP API use HTTPS. Default: false. |
Cluster |
String | The server cluster name. Overridden by Host if both are set. |
BatchEventDataSizeLimit |
Nullable Integer | Optional client-side size limit for event data. If specified, events exceeding this threshold throw before the request is sent. Normally 10KB. |
EncryptionMasterKey |
Byte Array | Optional 32-byte key for end-to-end encryption of private channels. |
RestClientTimeout |
TimeSpan | HTTP API request timeout. Default: 30 seconds. |
To trigger an event on one or more channels use the TriggerAsync method.
ITriggerResult result = await sockudo.TriggerAsync("channel-1", "test_event", new
{
message = "hello world"
}).ConfigureAwait(false);ITriggerResult result = await sockudo.TriggerAsync(
new string[]
{
"channel-1", "channel-2"
},
"test_event",
new
{
message = "hello world"
}).ConfigureAwait(false);var events = new[]
{
new Event { Channel = "channel-1", EventName = "event-1", Data = "hello world" },
new Event { Channel = "channel-2", EventName = "event-2", Data = "my name is bob" }
};
ITriggerResult result = await sockudo.TriggerAsync(events).ConfigureAwait(false);Rather than relying on the server to reject oversized messages, you can validate client-side before sending:
var sockudo = new Sockudo(Config.AppId, Config.AppKey, Config.AppSecret, new SockudoOptions
{
Host = Config.HttpHost,
BatchEventDataSizeLimit = SockudoOptions.DEFAULT_BATCH_EVENT_DATA_SIZE_LIMIT, // 10KB
});
try
{
var events = new[]
{
new Event { Channel = "channel-1", EventName = "event-1", Data = "hello world" },
new Event { Channel = "channel-2", EventName = "event-2", Data = new string('Q', 10 * 1024 + 1) },
};
await sockudo.TriggerAsync(events).ConfigureAwait(false);
}
catch (EventDataSizeExceededException eventDataSizeError)
{
// Handle the error when event data exceeds 10KB
}Pass an ITriggerOptions with a SocketId to prevent the triggering client from also receiving the event:
ITriggerResult result = await sockudo.TriggerAsync(channel, eventName, data, new TriggerOptions
{
SocketId = "1234.56"
}).ConfigureAwait(false);Attach an idempotency key so the server deduplicates events on retries:
ITriggerResult result = await sockudo.TriggerAsync(channel, eventName, data, new TriggerOptions
{
IdempotencyKey = "unique-key-for-this-event"
}).ConfigureAwait(false);Return the authentication token to the client requesting subscription:
var auth = sockudo.Authenticate(channelName, socketId);
var json = auth.ToJson();The json can then be returned to the client, which uses it to validate the subscription.
For presence channels, include user identity data:
var channelData = new PresenceChannelData
{
user_id = "unique_user_id",
user_info = new
{
name = "Jane Smith",
role = "admin",
}
};
var auth = sockudo.Authenticate(channelName, socketId, channelData);
var json = auth.ToJson();This library supports end-to-end encryption of private channels. Only you and your connected clients can read the messages.
Encrypted channels must be prefixed with private-encrypted-. Only private channels can be encrypted.
-
Set up private channel authentication on your server.
-
Generate a 32-byte master encryption key. Store this securely and never share it.
byte[] encryptionMasterKey = new byte[32]; using (RandomNumberGenerator random = RandomNumberGenerator.Create()) { random.GetBytes(encryptionMasterKey); }
-
Pass the key to the SDK constructor:
var sockudo = new Sockudo(Config.AppId, Config.AppKey, Config.AppSecret, new SockudoOptions { Host = "127.0.0.1", Port = 6001, EncryptionMasterKey = encryptionMasterKey, }); await sockudo.TriggerAsync("private-encrypted-my-channel", "my-event", new { message = "hello world" }).ConfigureAwait(false);
-
Subscribe to these channels in your client. Only the client (with the matching key) can decrypt the messages.
Query the state of your Sockudo application using GetAsync or the typed helper methods.
IGetResult<ChannelsList> result = await sockudo.GetAsync<ChannelsList>("/channels");or
IGetResult<ChannelsList> result = await sockudo.FetchStateForChannelsAsync<ChannelsList>();Filter by prefix:
IGetResult<ChannelsList> result = await sockudo.FetchStateForChannelsAsync<ChannelsList>(new
{
filter_by_prefix = "presence-"
}).ConfigureAwait(false);IGetResult<object> result = await sockudo.GetAsync<object>("/channels/my_channel");or
IGetResult<object> result = await sockudo.FetchStateForChannelAsync<object>("my_channel");IGetResult<object> result =
await sockudo.FetchUsersFromPresenceChannelAsync<object>("my_channel");IGetResult<object> page =
await sockudo.FetchHistoryForChannelAsync<object>(
"my_channel",
new { limit = 50, direction = "newest_first" });
IGetResult<object> nextPage =
await sockudo.FetchHistoryForChannelAsync<object>(
"my_channel",
new { cursor = "opaque-cursor-from-previous-page" });IGetResult<object> presencePage =
await sockudo.FetchPresenceHistoryForChannelAsync<object>(
"presence_my_channel",
new { limit = 50, direction = "newest_first" });
IGetResult<object> presenceNextPage =
await sockudo.FetchPresenceHistoryForChannelAsync<object>(
"presence_my_channel",
new { cursor = "opaque-cursor-from-previous-page" });
IGetResult<object> presenceSnapshot =
await sockudo.FetchPresenceSnapshotForChannelAsync<object>(
"presence_my_channel",
new { at_serial = 4 });Sockudo sends webhooks based on your application's configuration. Validate and consume them as follows:
// HTTP_X_PUSHER_SIGNATURE from HTTP header
var receivedSignature = "value";
// Body of the HTTP request
var receivedBody = "value";
var sockudo = new Sockudo(...);
var webHook = sockudo.ProcessWebHook(receivedSignature, receivedBody);
if (webHook.IsValid)
{
// Dictionary<string,string>[]
var events = webHook.Events;
foreach (var webHookEvent in webHook.Events)
{
var eventType = webHookEvent["name"];
var channelName = webHookEvent["channel"];
// Additional keys may be present depending on the event type
}
}
else
{
// Inspect webHook.ValidationErrors to diagnose the problem
}This code is free to use under the terms of the MIT license.