Dean151/swift-server-socket.io
Socket.IO v5 protocol implementation in Swift
Status
The current implementation includes:
- Socket.IO v5 namespace connect/disconnect flow
- event and acknowledgement packets
- binary event and binary acknowledgement packet encoding/decoding
- namespace-scoped rooms with
join,leave, andleaveAll - fluent broadcasting with
to,excluding, andsocket.broadcast - a pluggable adapter layer with a built-in
InMemoryAdapter - cluster-aware broadcasting with
local,fetchSockets, remote socket control, andserverSideEmit - an optional Redis-backed cluster coordinator for horizontal scaling
- Engine.IO-style polling and WebSocket transport support
- a Swift-first API with raw
SocketIOValueaccess and typedCodablehelpers
Installation
Add the package dependency to your Package.swift:
.package(url: "https://github.com/thomasauger/swift-server-socket.io.git", exact: "5.0.0-beta.1")Then depend on the SocketIO product:
.product(name: "SocketIO", package: "swift-server-socket.io")For Redis-backed horizontal scaling, also depend on:
.product(name: "SocketIORedisAdapter", package: "swift-server-socket.io")Quick Start
import SocketIO
@main
struct App {
static func main() async throws {
let server = Server(
port: 3000,
configuration: .init(
heartbeat: .init(
pingTimeout: .milliseconds(200),
pingInterval: .milliseconds(300),
connectTimeout: .milliseconds(1_000)
),
transport: .init(maxPayload: 1_000_000)
)
)
server.onConnection { socket in
await socket.emit("auth", arguments: [socket.handshake.auth ?? .null])
socket.on("message") { event, _ in
await socket.emit("message-back", arguments: event.arguments)
}
socket.on("message-with-ack") { event, ack in
try? await ack?.send(arguments: event.arguments)
}
await socket.join("chat")
await socket.broadcast.to("chat").emit("joined", arguments: [.string(socket.id)])
}
let custom = server.namespace("/custom")
custom.onConnection { socket in
await socket.emit("auth", arguments: [socket.handshake.auth ?? .null])
}
await server.to("chat").emit("server-ready", arguments: [.bool(true)])
try await server.run()
}
}Use a custom adapter by providing namespace settings in ServerConfiguration:
let configuration = ServerConfiguration(
namespaces: .init(
adapterFactory: { _ in InMemoryAdapter() }
)
)Use the Redis coordinator to enable cross-node broadcasts and server-side events:
import SocketIO
import SocketIORedisAdapter
let cluster = RedisClusterCoordinator(
nodeID: "api-1",
configuration: try .init(url: "redis://127.0.0.1:6379")
)
let server = Server(
port: 3000,
configuration: .init(
cluster: .init(coordinator: cluster)
)
)Cluster-aware APIs include:
server.local,namespace.local, andsocket.broadcast.localfetchSockets()RemoteSocketoperations:emit,join,leave, anddisconnectserverSideEmit(...)with optional acknowledgement collection
When deploying multiple Socket.IO nodes behind a load balancer, sticky sessions are still required for Engine.IO polling and transport upgrades.
Development
Run the Swift test suite:
swift testRun the Docker-based protocol tests:
docker compose run --build --rm socket-test npm testReferences
- Socket.IO protocol specification: <https://github.com/socketio/socket.io-protocol>
- Socket.IO website: <https://socket.io/>
Package Metadata
Repository: Dean151/swift-server-socket.io
Stars: 1
Forks: 0
Open issues: 0
Default branch: 5.x
Primary language: swift
License: MIT
Topics: http, server, server-side-swift, socket-io-server, swift, swift-nio, web, web-server, websocket
README: README.md