WebSocket Transport

WebSocket is the default transport for Altruist. It runs on top of the HTTP server using ASP.NET Core's WebSocket middleware.

Configuration

altruist:
  server:
    http:
      host: "0.0.0.0"
      port: 8080
    transport:
      codec:
        provider: json
      websocket:
        enabled: true
        path: /ws

Note:

WebSocket shares the HTTP port. The path property defines the URL path for WebSocket upgrade requests. You can run WebSocket alongside TCP and/or UDP — see Server Setup for multi-transport configuration.

Connection Flow

  1. Client opens a WebSocket connection to ws://host:port/ws
  2. Server accepts and creates a WebSocketConnection with a unique clientId
  3. The connection is assigned to a default waiting room
  4. Any OnConnectedAsync hooks on matching portals are called
  5. Client sends JSON/MessagePack packets with an event field
  6. Server routes to the matching [Gate] handler
  7. On disconnect, OnDisconnectedAsync hooks fire

Client Example (JavaScript)

const ws = new WebSocket('ws://localhost:8080/ws');

ws.onopen = () => {
  // Send a handshake event
  ws.send(JSON.stringify({
    messageCode: 4,
    event: "handshake"
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};

// Send a chat message
ws.send(JSON.stringify({
  messageCode: 4,
  event: "chat",
  text: "Hello server!"
}));

Authentication

WebSocket connections can be authenticated using the Shield system. Apply [Shield] to your portal:

[Portal("/ws")]
[Shield(typeof(JwtAuth))]
public class SecurePortal : Portal { ... }

The client must include a valid JWT in the Authorization header during the WebSocket handshake:

const ws = new WebSocket('ws://localhost:8080/ws', {
  headers: { 'Authorization': 'Bearer <token>' }
});

Multiple Routes

You can have portals on different WebSocket paths:

[Portal("/game")]   // ws://host:port/ws/game
public class GamePortal : Portal { ... }

[Portal("/chat")]   // ws://host:port/ws/chat
public class ChatPortal : Portal { ... }

Note:

All portals marked with the same [Shield] type on the same path share the same authentication. Portals on the same path must either all be shielded with the same type, or all be unshielded.