WebSocketActors is a client/server communications library that allows an iOS, macOS, tvOS, or watchOS app to communicate with a server on the internet using Swift's distributed actor system. It's a streamlined alternative to writing a server using Swagger/OpenAPI and then implementing your client app on top of that API. With WebSocketActors, you can make Swift function calls directly between your client and server.
This library is based on Apple's TicTacFish sample code, but adds features like:
- Simultaneous connections to multiple servers & clients
- Automatic reconnection after network failures
- Server calls to client actors (server push)
- Logging with SwiftLog
Add the package https://github.com/samalone/websocket-actor-system
to your
Xcode project, or add:
.package(url: "https://github.com/samalone/websocket-actor-system.git", from: "1.0.0"),
to your package dependencies in your Package.swift
file. Then add:
.product(name: "WebSocketActors", package: "websocket-actor-system"),
to the target dependencies of your package target.
In your shared library, import WebSocketActors
and define your distributed
actors.
import Distributed
import WebSocketActors
extension NodeIdentity {
public static let server = NodeIdentity(id: "server")
}
extension ActorIdentity {
public static let greeter = ActorIdentity(id: "greeter", node: .server)
}
public distributed actor Greeter {
public typealias ActorSystem = WebSocketActorSystem
public distributed func greet(name: String) -> String {
return "Hello, \(name)!"
}
}
In your server code, start the server in the background and make sure the server keeps running.
func main() async throws {
let address = ServerAddress(scheme: .insecure, host: "localhost", port: 8888)
let system = WebSocketActorSystem(id: .server)
try await system.runServer(at: address)
_ = system.makeLocalActor(id: .greeter) {
Greeter(actorSystem: system)
}
while true {
try await Task.sleep(for: .seconds(1_000_000))
}
}
On the client, connect to the server and call the remote actor.
func receiveGreeting() async throws {
let address = ServerAddress(scheme: .insecure, host: "localhost", port: 8888)
let system = WebSocketActorSystem()
try await system.connectClient(to: address)
let greeter = try Greeter.resolve(id: .greeter, using: system)
let greeting = try await greeter.greet(name: "Alice")
print(greeting)
}
The documentation for WebSocketActors includes both API documentation and getting-started articles:
For a basic example of writing a client/server app using WebSocketActors, see my Monotonic project. It implements a simple iOS app that displays a counter above an "Increment" button. Clicking the increment button bumps the counters on all client apps connected to the server in real time.
- Introducing Swift Distributed Actors from the Swift Blog.
- Introducing Distributed Actors from Apple's DistributedCluster documentation
- Meet distributed actors in Swift from WWDC 2022
- Apple's documentation on the Distributed module.
- Apple's TicTacFish sample code