### SwiftNIO Echo Server Source: https://docs.21.dev/data/documentation/event/swifteventvsswiftniovshummingbirdvsnetworkframework An example of an echo server using SwiftNIO's async/await API. Requires setting up a ServerBootstrap and handling incoming connections and data chunks. ```swift let server = try await ServerBootstrap(group: NIOSingletons.posixEventLoopGroup) .childChannelOption(.socketOption(.so_reuseaddr), value: 1) .bind(host: "0.0.0.0", port: 8080) { channel in channel.eventLoop.makeCompletedFuture { try NIOAsyncChannel(wrappingChannelSynchronously: channel) } } try await withThrowingDiscardingTaskGroup { group in try await server.executeThenClose { connections in for try await connection in connections { group.addTask { try await connection.executeThenClose { inbound, outbound in for try await chunk in inbound { try await outbound.write(chunk) } } } } } } ``` -------------------------------- ### Example of Downstream Target Dependencies Source: https://docs.21.dev/data/documentation/event/embeddingclibrariesinswiftpm This example shows how a downstream target, like `libtor` in `swift-tor`, declares its dependencies on products from other packages, such as `libcrypto`, `libssl`, and `libevent`. ```swift // From swift-tor's Package.swift .target( name: "libtor", dependencies: [ .product(name: "libcrypto", package: "swift-openssl"), .product(name: "libssl", package: "swift-openssl"), .product(name: "libevent", package: "swift-event"), ] ) ``` -------------------------------- ### Network.framework Echo Server Source: https://docs.21.dev/data/documentation/event/swifteventvsswiftniovshummingbirdvsnetworkframework An example of an echo server using Apple's Network.framework. It sets up a TCP listener and handles incoming connections, receiving and sending data. ```swift let listener = try NWListener(using: .tcp, on: 8080) listener.newConnectionHandler = { connection in connection.start(queue: .global()) connection.receive(minimumIncompleteLength: 1, maximumLength: 4096) { data, _, _, _ in guard let data = data else { return } connection.send(content: data, completion: .contentProcessed { _ in connection.cancel() }) } } listener.start(queue: .global()) RunLoop.main.run() ``` -------------------------------- ### Hummingbird Echo Server (HTTP POST) Source: https://docs.21.dev/data/documentation/event/swifteventvsswiftniovshummingbirdvsnetworkframework An example of an HTTP server using Hummingbird that echoes the POST request body. This demonstrates Hummingbird's focus on HTTP rather than raw TCP. ```swift let router = Router() router.post("/") { request, _ in let body = try await request.body.collect(upTo: .max) return Response(status: .ok, body: ResponseBody(byteBuffer: body)) } let app = Application(router: router, configuration: .init(address: .hostname("0.0.0.0", port: 8080))) try await app.runService() ``` -------------------------------- ### Swift Package Dependencies for swift-tor Source: https://docs.21.dev/data/documentation/event/choosinglibeventvsevent Example of how to declare dependencies on swift-openssl and swift-event in a Swift package, specifically for a target that requires libcrypto, libssl, and libevent. ```swift dependencies: [ .package(url: "https://github.com/21-DOT-DEV/swift-openssl.git", exact: "0.1.5"), .package(url: "https://github.com/21-DOT-DEV/swift-event.git", exact: "0.2.1"), ], targets: [ .target( name: "libtor", dependencies: [ .product(name: "libcrypto", package: "swift-openssl"), .product(name: "libssl", package: "swift-openssl"), .product(name: "libevent", package: "swift-event"), ], // ... ), ], ``` -------------------------------- ### Swift Package Dependencies for libevent Source: https://docs.21.dev/data/documentation/event/gettingstarted Example of how to include libevent as a dependency in a Swift package's Package.swift file. This is the recommended approach for Swift packages with C sources that need libevent. ```swift // From swift-tor's Package.swift dependencies: [ .package(url: "https://github.com/21-DOT-DEV/swift-openssl.git", exact: "0.1.5"), .package(url: "https://github.com/21-DOT-DEV/swift-event.git", exact: "0.2.1"), ], targets: [ .target( name: "libtor", dependencies: [ .product(name: "libcrypto", package: "swift-openssl"), .product(name: "libssl", package: "swift-openssl"), .product(name: "libevent", package: "swift-event"), ], // ... ), ], ``` -------------------------------- ### Create SocketAddress Instances Source: https://docs.21.dev/data/documentation/event/socketaddress Demonstrates creating SocketAddress instances for IPv4, IPv6, and wildcard addresses. Requires importing the Event framework. The port property returns the port in host byte order. ```swift import Event let loopback4 = try SocketAddress.ipv4("127.0.0.1", port: 8080) let loopback6 = try SocketAddress.ipv6("::1", port: 8080) let wildcard = SocketAddress.anyIPv4(port: 8080) print(loopback4.port) // 8080 ``` -------------------------------- ### Listen for Incoming TCP Connections using Event Source: https://docs.21.dev/data/documentation/event/swifteventvsswiftniovshummingbirdvsnetworkframework Shows how to set up a server socket to listen for incoming TCP connections on a given port. The backlog parameter controls the queue size for pending connections. ```swift Socket.listen(port: 8080, backlog: 128, loop: loop).map { serverSocket in // Server socket is listening print("Listening on port \(serverSocket.localPort)") } ``` -------------------------------- ### Connect to a TCP Server using Event Source: https://docs.21.dev/data/documentation/event/swifteventvsswiftniovshummingbirdvsnetworkframework Demonstrates how to establish a TCP connection to a specified host and port using the Event package's Socket API. Requires an EventLoop to manage the connection. ```swift Socket.connect(to: "example.com", port: 80, loop: loop).map { socket in // Connection established print("Connected to \(socket.remoteAddress)") } ``` -------------------------------- ### Async TCP Server with Event Source: https://docs.21.dev/data/documentation/event/llms.txt Implement an async TCP server using the Event package. Bind to a port and iterate over the 'connections' async stream to handle incoming clients. Each client connection is processed in a separate Task. ```swift import Event let server = try await Socket.listen(port: 8080, backlog: 16, loop: .shared) for try await client in server.connections { Task { do { while true { let chunk = try await client.read(timeout: .seconds(30)) try await client.write(chunk, timeout: .seconds(30)) } } catch SocketError.connectionClosed { // Peer closed cleanly. } try? await client.close() } } ``` -------------------------------- ### Inspect Event Loop Backend Source: https://docs.21.dev/data/documentation/event Create an EventLoop instance and print its backend method. This demonstrates how to determine if the underlying I/O multiplexer is kqueue (on Apple platforms) or epoll (on Linux). ```swift import Event let loop = EventLoop() print(loop.backendMethod) // kqueue (on macOS / iOS / tvOS / watchOS / visionOS) // epoll (on Linux) ``` -------------------------------- ### Declare C Library as SwiftPM Product in Package.swift Source: https://docs.21.dev/data/documentation/event/embeddingclibrariesinswiftpm Expose your C library as a SwiftPM product in `Package.swift` to allow other Swift packages to depend on it directly. This allows for raw C bindings and an idiomatic Swift API. ```swift let package = Package( name: "swift-libfoo", products: [ .library(name: "libfoo", targets: ["libfoo"]), .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "libfoo", /* ... as above ... */), .target(name: "Foo", dependencies: ["libfoo"]), ] ) ``` -------------------------------- ### Async TCP Client with Timeouts Source: https://docs.21.dev/data/documentation/event/llms.txt Establish an async TCP client connection using the Event package. Supports per-operation timeouts, throwing 'SocketError.timeout' on expiry. Demonstrates connecting, writing, reading, and closing the socket. ```swift import Event let socket = try await Socket.connect( to: "127.0.0.1", port: 8080, loop: .shared, timeout: .seconds(5) ) try await socket.write(Data("ping\n".utf8), timeout: .seconds(5)) let reply = try await socket.read(maxBytes: 4096, timeout: .seconds(5)) try await socket.close() ``` -------------------------------- ### SocketAddress Initializers Source: https://docs.21.dev/data/documentation/event/llms-full.txt This section describes the initializers for creating SocketAddress instances, used to represent network addresses. ```APIDOC ## SocketAddress ### Description Represents a network address (IP and port). ### Initializers #### `anyIPv4(port:)` - **Parameters**: - **port** (Int) - The port number. - **Description**: Creates a SocketAddress for any IPv4 address on the specified port. #### `from(storage:length:)` - **Parameters**: - **storage** (UnsafePointer) - Pointer to the socket address structure. - **length** (Int) - The length of the socket address structure. - **Description**: Creates a SocketAddress from a raw socket address structure. #### `ipv4(_:port:)` - **Parameters**: - **_** (String) - The IPv4 address string. - **port** (Int) - The port number. - **Description**: Creates a SocketAddress for a specific IPv4 address and port. #### `ipv6(_:port:)` - **Parameters**: - **_** (String) - The IPv6 address string. - **port** (Int) - The port number. - **Description**: Creates a SocketAddress for a specific IPv6 address and port. #### `port` - **Description**: Gets the port number from the SocketAddress. ``` -------------------------------- ### ServerSocket accept() Source: https://docs.21.dev/data/documentation/event/serversocket Awaits exactly one incoming connection and returns a connected Socket. Use this when your protocol is request/response and you want explicit control over when to service the next connection. ```APIDOC ## ServerSocket accept() ### Description Awaits exactly one incoming connection and returns a connected `Socket`. ### Method `accept()` ### Parameters None ### Response #### Success Response - **Socket** (Socket) - A connected client socket. #### Response Example ``` // Example response structure (actual object will be a Socket instance) { "socket": "connected_socket_object" } ``` ``` -------------------------------- ### Complete Async TCP Echo Server in Swift Source: https://docs.21.dev/data/documentation/event/asynctcpserverinswift This is a full-featured echo server that can be dropped into a Swift package. It demonstrates binding, listening, accepting connections, and handling client data asynchronously. Ensure your package specifies Swift 6.1 and includes 'Event' as a dependency. ```swift import Event @main struct EchoServer { static func main() async { do { // Listen on all interfaces, port 8080, with a backlog of 128. let server = try await Socket.listen(port: 8080) print("Listening on \(server.localPort)") // Accept connections indefinitely. for try await socket in server.connections { // Handle each connection in a new Task. Task { @Sendable in do { // Read and write data until the connection is closed. for try await data in socket.reads() { try await socket.write(data) } } catch { // Handle errors, including connection closure. print("Connection error: \(error)") } } } } catch { // Handle server-level errors. print("Server error: \(error)") } } } ``` -------------------------------- ### Embedding libevent C Library with Event Source: https://docs.21.dev/data/documentation/event/swifteventvsswiftniovshummingbirdvsnetworkframework Illustrates how the Event package allows direct access to the underlying libevent C product, useful for integrating existing C-based networking libraries into SwiftPM projects. ```swift import Event // The 'libevent' product is re-exported by the Event package // for direct use when embedding C libraries. ``` -------------------------------- ### EventLoop Overview Source: https://docs.21.dev/data/documentation/event/eventloop Provides an overview of the EventLoop class, its role in managing asynchronous I/O, and its relationship with libevent. ```APIDOC ## EventLoop A libevent-backed event loop owning an `event_base` for async I/O dispatch. ```swift final class EventLoop ``` ### Overview `EventLoop` wraps libevent’s [`event_base`](https://libevent.org/doc/structevent__base.html) — the per-loop data structure that watches file descriptors for readiness using the platform’s most efficient I/O multiplexer (kqueue on Apple platforms, epoll on Linux, with POSIX `poll(2)` as a fallback). [`Socket`](/documentation/Event/Socket) and [`ServerSocket`](/documentation/Event/ServerSocket) use an `EventLoop` to schedule read- and write-ready callbacks and drive them to completion. ### Shared vs. owned loops Most callers use the [`shared`](/documentation/Event/EventLoop/shared) singleton. Create a dedicated loop only when you need isolation — for example, in tests that must not contend with application traffic, or when you want distinct fd-watch sets per subsystem. The singleton is fine for the common “one loop per process” pattern; it’s not a locking construct and does not synchronize concurrent use from multiple tasks. ### Lifecycle The typical flow is: 1. Acquire a loop (``doc://Event/documentation/Event/EventLoop/shared`` or ``doc://Event/documentation/Event/EventLoop/init()``). 1. Register I/O via ``doc://Event/documentation/Event/Socket`` / ``doc://Event/documentation/Event/ServerSocket`` methods — each method drives the loop internally via ``doc://Event/documentation/Event/EventLoop/runOnce()``. 1. Call ``doc://Event/documentation/Event/EventLoop/run()`` when you want a long-lived event-dispatch loop in a dedicated task, or rely on per-operation ``doc://Event/documentation/Event/EventLoop/runOnce()`` for one-shot use. 1. ``doc://Event/documentation/Event/EventLoop/stop()`` signals ``doc://Event/documentation/Event/EventLoop/run()`` to exit at its next dispatch boundary. ### Backend selection The runtime backend is exposed via [`backendMethod`](/documentation/Event/EventLoop/backendMethod). swift-event asserts at test time that this is `"kqueue"` on Apple platforms and `"epoll"` on Linux — see [Backend and Platforms](/documentation/Event/BackendAndPlatforms) for the full backend story and the reasons Windows IOCP, Solaris `devpoll`/`evport`, and OpenSSL bufferevents are excluded. ### Concurrency Marked `@unchecked Sendable` to permit handoff of ownership across task boundaries. The underlying `event_base` is **not** thread-safe: swift-event does not invoke `evthread_use_pthreads()`, so concurrent calls into a single `EventLoop` from multiple tasks are **undefined behavior at the libevent level**. The invariant is single-owner-per-scope — hand off, do not share. See [Production Considerations](/documentation/Event/ProductionConsiderations) “Concurrency Model” for the full honest description. ``` -------------------------------- ### Socket Methods Source: https://docs.21.dev/data/documentation/event/llms-full.txt This section details the methods for interacting with network sockets, including connecting, listening, reading, and writing data. ```APIDOC ## Socket ### Description Represents a network socket for communication. ### Methods #### `close()` - **Description**: Closes the socket connection. #### `connect(to:loop:timeout:)` - **Parameters**: - **to** (SocketAddress) - The address to connect to. - **loop** (EventLoop) - The event loop to use. - **timeout** (TimeInterval) - The connection timeout. - **Description**: Connects the socket to a specified address with a timeout. #### `connect(to:port:loop:timeout:)` - **Parameters**: - **to** (String) - The host address to connect to. - **port** (Int) - The port to connect to. - **loop** (EventLoop) - The event loop to use. - **timeout** (TimeInterval) - The connection timeout. - **Description**: Connects the socket to a specified host and port with a timeout. #### `listen(on:backlog:loop:)` - **Parameters**: - **on** (String) - The address to listen on. - **backlog** (Int) - The maximum number of pending connections. - **loop** (EventLoop) - The event loop to use. - **Description**: Starts listening for incoming connections on a specified address. #### `listen(port:backlog:loop:)` - **Parameters**: - **port** (Int) - The port to listen on. - **backlog** (Int) - The maximum number of pending connections. - **loop** (EventLoop) - The event loop to use. - **Description**: Starts listening for incoming connections on a specified port. #### `localAddress` - **Description**: Gets the local address of the socket. #### `localPort` - **Description**: Gets the local port of the socket. #### `read(maxBytes:timeout:)` - **Parameters**: - **maxBytes** (Int) - The maximum number of bytes to read. - **timeout** (TimeInterval) - The read timeout. - **Description**: Reads data from the socket with a maximum byte limit and timeout. #### `remoteAddress` - **Description**: Gets the remote address of the socket. #### `remotePort` - **Description**: Gets the remote port of the socket. #### `write(_:timeout:)` - **Parameters**: - **_** (Data) - The data to write. - **timeout** (TimeInterval) - The write timeout. - **Description**: Writes data to the socket with a timeout. ``` -------------------------------- ### Construct Any IPv4 Socket Address Source: https://docs.21.dev/data/documentation/event/gettingstarted Create a `SocketAddress` for binding servers to all available IPv4 interfaces (`0.0.0.0`) on a specific port. This is useful for servers that should listen on all network interfaces. ```swift SocketAddress.anyIPv4(port: 8080) ``` -------------------------------- ### Illustrate TCP Partial Reads Source: https://docs.21.dev/data/documentation/event/partialreadsandmessageframing Demonstrates how TCP can split or coalesce data, leading to unexpected results when receiving data. A single send() may result in multiple recv() calls, or multiple send() calls may be combined into a single recv(). ```swift let chunk1 = try await socket.read() let chunk2 = try await socket.read() ``` -------------------------------- ### Swift Package Manager Target for C Library Source: https://docs.21.dev/data/documentation/event/embeddingclibrariesinswiftpm Define a SwiftPM target for a C library, specifying files to exclude and C compiler settings. Use `exclude` to skip platform-specific source files that might conflict with the host system. `cSettings` can be used to pass defines that would typically be set by a C build system like autoconf. ```swift .target( name: "libfoo", exclude: [ // Sources you don't want compiled (e.g., platform-specific // implementations that conflict with the host's libc): "src/arc4random.c", ], cSettings: [ // Pass any defines the upstream build system would have set: .define("_GNU_SOURCE", .when(platforms: [.linux])), .define("HAVE_CONFIG_H"), ] ) ``` -------------------------------- ### Test C Library Import in SwiftPM Source: https://docs.21.dev/data/documentation/event/embeddingclibrariesinswiftpm This test verifies that a SwiftPM target can successfully import and use a C library. It constructs a C struct, proving that C headers are visible and the linker has resolved symbols. ```swift import XCTest @testable import libevent final class libeventTests: XCTestCase { func testExample() throws { _ = event() // Constructs a libevent `event` struct — proves the C // headers are visible and the linker resolved. } } ``` -------------------------------- ### Socket Class Overview Source: https://docs.21.dev/data/documentation/event/socket Details the Socket class, its role in handling asynchronous I/O, and its different use cases as a TCP client, accepted server connection, or wrapper for existing file descriptors. ```APIDOC ## Socket An async non-blocking TCP socket backed by libevent. ```swift final class Socket ``` ### Overview `Socket` wraps a POSIX file descriptor configured for non-blocking I/O and drives it through an [`EventLoop`](/documentation/Event/EventLoop) so that [`read(maxBytes:timeout:)`](/documentation/Event/Socket/read(maxBytes:timeout:)) and [`write(_:timeout:)`](/documentation/Event/Socket/write(_:timeout:)) resume their callers only when the kernel indicates data readiness. The async surface (`async throws` methods) composes naturally with Swift structured concurrency; the underlying mechanism is libevent callbacks bridging to `CheckedContinuation`s. `Socket` covers three roles: - **TCP client** — acquired via ``doc://Event/documentation/Event/Socket/connect(to:port:loop:timeout:)`` or ``doc://Event/documentation/Event/Socket/connect(to:loop:timeout:)``. - **Accepted server connection** — delivered by ``doc://Event/documentation/Event/ServerSocket/accept()`` or the ``doc://Event/documentation/Event/ServerSocket/connections`` stream. - **Wrapping an existing descriptor** — not exposed publicly (the initializer is `internal`), but used by the library itself when an external fd must be adopted. Server-listener construction lives on [`listen(port:backlog:loop:)`](/documentation/Event/Socket/listen(port:backlog:loop:)) and [`listen(on:backlog:loop:)`](/documentation/Event/Socket/listen(on:backlog:loop:)), which return a [`ServerSocket`](/documentation/Event/ServerSocket) — not a `Socket`. ### Resource ownership A `Socket` owns its descriptor by default: `deinit` calls `close(2)`. The `ownsDescriptor` initializer flag exists so callers can wrap an externally-owned fd without double-close risk; this path is internal today. The single-ownership invariant is a constitution Principle II concern — see [Production Considerations](/documentation/Event/ProductionConsiderations). ### Concurrency Marked `@unchecked Sendable` to permit handoff of ownership across task boundaries. Concurrent I/O on the same `Socket` from multiple tasks (e.g. `read` from one task while `write` from another) is **undefined behavior**: the libevent callback state is not synchronized, and `fd` is mutated unconditionally in `deinit`. Use structured concurrency scopes to bound ownership. See [Production Considerations](/documentation/Event/ProductionConsiderations) “Concurrency Model” for the honest description. ``` -------------------------------- ### Listening on an Ephemeral Port in Swift Source: https://docs.21.dev/data/documentation/event/asynctcpserverinswift To have the kernel assign an ephemeral port for the server, pass `port: 0` to the `listen` function. The assigned port can then be retrieved using the `localPort` property, which is useful for testing scenarios. ```swift let server = try await Socket.listen(port: 0) print("listening on \(server.localPort)") ``` -------------------------------- ### Add Swift Event Package Dependency Source: https://docs.21.dev/data/documentation/event/llms.txt Add the Event package dependency to your Swift project using 'exact:' for pre-1.0 versions. Include the 'Event' product in your target's dependencies. ```swift // Package.swift .package(url: "https://github.com/21-DOT-DEV/swift-event.git", exact: "0.2.1"), .target(name: "", dependencies: [ .product(name: "Event", package: "swift-event"), ]), ``` -------------------------------- ### ServerSocket connections Source: https://docs.21.dev/data/documentation/event/serversocket An AsyncThrowingStream that yields each accepted Socket as it arrives, until the stream is cancelled or errors. Use this for server loops like `for try await client in server.connections { ... }`. ```APIDOC ## ServerSocket connections ### Description An `AsyncThrowingStream` that yields each accepted `Socket` as it arrives, until the stream is cancelled or errors. ### Method `connections` ### Parameters None ### Response #### Success Response - **AsyncThrowingStream** - A stream yielding connected client sockets. #### Response Example ```swift for try await client in server.connections { // Handle client connection } ``` ``` -------------------------------- ### write(_:timeout:) Source: https://docs.21.dev/data/documentation/event/tcpclientforioswithswift Writes all provided data to the socket, waiting until the data is sent or a timeout occurs. ```APIDOC ## write(_:timeout:) ### Description Writes all bytes in `data` to the socket, awaiting write-readiness. This method is used to send data to the remote server. ### Method [Implicitly a method call within the Socket class] ### Parameters #### Path Parameters - **data** (Data) - Required - The data to write to the socket. - **timeout** (TimeInterval) - Optional - The timeout for the write operation. ### Request Example ```swift // Assuming 'socket' is an instance of Socket and is connected let messageToSend = "Hello, server!".data(using: .utf8)! let writeTimeout: TimeInterval = 5.0 // The actual call would be within an async context and might look like: // try await socket.write(messageToSend, timeout: writeTimeout) ``` ### Response #### Success Response - The method returns once all data has been successfully written. #### Response Example ```json { "status": "written" } ``` ### Errors - `SocketError.timeout`: If the write operation exceeds the specified timeout. - `SocketError.connectionClosed`: If the peer closes the connection while data is being written. ``` -------------------------------- ### connect(to:port:loop:timeout:) Source: https://docs.21.dev/data/documentation/event/tcpclientforioswithswift Connects to a remote IPv4 host by its numeric address. This is a fundamental operation for establishing a TCP client connection. ```APIDOC ## connect(to:port:loop:timeout:) ### Description Connects to a remote IPv4 host by numeric address. ### Method [Implicitly a method call within the Socket class] ### Parameters #### Path Parameters - **to** (String) - Required - The IPv4 address of the remote host. - **port** (Int) - Required - The port number of the remote host. - **loop** (EventLoop) - Required - The event loop to use for the connection. - **timeout** (TimeInterval) - Optional - The timeout for the connection attempt. ### Request Example ```swift // Assuming 'socket' is an instance of Socket let remoteAddress = "192.168.1.1" let remotePort = 8080 let connectionTimeout: TimeInterval = 10.0 // The actual call would be within an async context and might look like: // try await socket.connect(to: remoteAddress, port: remotePort, loop: currentLoop, timeout: connectionTimeout) ``` ### Response #### Success Response - The method returns once the connection is established. #### Response Example ```json { "status": "connected" } ``` ### Errors - `SocketError.timeout`: If the connection attempt exceeds the specified timeout. ``` -------------------------------- ### ServerSocket Methods Source: https://docs.21.dev/data/documentation/event/llms-full.txt This section covers the methods related to ServerSocket, which is used for creating and managing server-side network sockets. ```APIDOC ## ServerSocket ### Description Represents a server socket for accepting incoming connections. ### Methods #### `accept()` - **Description**: Accepts a new incoming connection and returns a Socket. #### `close()` - **Description**: Closes the server socket. #### `connections` - **Description**: (Details not provided in source) #### `localAddress` - **Description**: Gets the local address of the server socket. #### `localPort` - **Description**: Gets the local port of the server socket. ``` -------------------------------- ### Pinning Swift Package Dependency with Exact Version Source: https://docs.21.dev/data/documentation/event/productionconsiderations Use `exact:` to pin to a specific version of the swift-event package to prevent unexpected breaking changes from minor version bumps. ```swift .package(url: "https://github.com/21-DOT-DEV/swift-event.git", exact: "0.2.1"), ``` -------------------------------- ### EventLoop Methods Source: https://docs.21.dev/data/documentation/event/llms-full.txt This section details the various methods available on the EventLoop class for managing asynchronous operations, scheduling tasks, and controlling the event loop's execution. ```APIDOC ## EventLoop ### Description Provides methods for managing the event loop, scheduling tasks, and handling signals. ### Methods #### `backendMethod()` - **Description**: (Details not provided in source) #### `init()` - **Description**: Initializes the EventLoop. #### `run()` - **Description**: Starts the event loop and begins processing events. #### `runOnce()` - **Description**: Executes a single iteration of the event loop. #### `schedule(after:_: )` - **Parameters**: - **after** (TimeInterval) - The delay before scheduling the task. - **_** (Closure) - The task to be scheduled. - **Description**: Schedules a task to be executed after a specified delay. #### `shared` - **Description**: Accesses the shared singleton instance of the EventLoop. #### `signalStream(_:)` - **Parameters**: - **_** (Signal) - The signal to stream. - **Description**: Creates a stream for a given signal. #### `sleep(for:)` - **Parameters**: - **for** (TimeInterval) - The duration to sleep. - **Description**: Pauses the current execution for a specified duration. #### `stop()` - **Description**: Stops the event loop. ``` -------------------------------- ### Define C Library Module Map with Shim Header Source: https://docs.21.dev/data/documentation/event/embeddingclibrariesinswiftpm Use a hand-written shim header for the module map to control visibility and ensure compatibility with Swift C++ interop. This pattern avoids issues with `umbrella '.'` or `umbrella header`. The shim header includes all public C headers that Swift consumers should see. ```c module libfoo { requires !cplusplus header "swift-shim.h" export * } ``` ```c #ifndef LIBFOO_SWIFT_SHIM_H #define LIBFOO_SWIFT_SHIM_H #include "foo.h" #include "foo/core.h" #include "foo/ext.h" /* …every public header you want Swift consumers to see… */ #endif ``` -------------------------------- ### EventLoop Source: https://docs.21.dev/data/documentation/event/llms.txt The core event loop that manages asynchronous events. It selects the appropriate backend (kqueue on Apple, epoll on Linux) for optimal performance. ```APIDOC ## EventLoop ### Description Represents the core event loop for managing asynchronous operations. It dynamically selects between `kqueue` on Apple platforms and `epoll` on Linux. ### Methods - `.shared`: Access the shared singleton instance of the `EventLoop`. - `init()`: Initializes a new `EventLoop` instance. - `run()`: Starts the event loop, processing events indefinitely. - `runOnce()`: Processes events a single time and then returns. - `stop()`: Stops the event loop. - `sleep(for: TimeInterval)`: Pauses the event loop for a specified duration. - `schedule(after: TimeInterval, _ closure: @escaping () -> Void)`: Schedules a closure to be executed after a specified delay. - `signalStream(_ stream: AsyncStream)`: Creates a stream that can be signaled to wake up the event loop. ``` -------------------------------- ### Graceful Shutdown with SIGTERM/SIGINT Source: https://docs.21.dev/data/documentation/event/asynctcpserverinswift Implement graceful shutdown by reacting to SIGTERM and SIGINT signals. This pattern closes the listener and cancels the accept-loop task, ensuring all resources are cleaned up properly. ```swift for try await client in server.connections { Task { try await handle(client) } } func handle(_ client: Socket) async throws { // ... handle client connection ... } // Signal handling for graceful shutdown Task { for await _ in EventLoop.shared.signalStream(.sigterm, .sigint) { print("Received shutdown signal, closing listener...") server.close() break } print("Listener closed.") } ``` -------------------------------- ### Construct IPv6 Socket Address Source: https://docs.21.dev/data/documentation/event/gettingstarted Create a `SocketAddress` for an IPv6 endpoint, which also supports IPv4-mapped IPv6 addresses, using a numeric IP address and port. DNS names are not resolved. ```swift SocketAddress.ipv6("::1", port: 8080) ``` -------------------------------- ### Add Event Swift Package Manager Dependency Source: https://docs.21.dev/data/documentation/event/gettingstarted Add the swift-event package as a dependency using `exact:` versioning due to its pre-1.0 status. Import Event in your Swift files to use its functionalities. ```swift // Package.swift .package(url: "https://github.com/21-DOT-DEV/swift-event.git", exact: "0.2.1"), ``` ```swift // Target dependencies .target(name: "", dependencies: [ .product(name: "Event", package: "swift-event"), ]), ``` -------------------------------- ### Construct IPv4 Socket Address Source: https://docs.21.dev/data/documentation/event/gettingstarted Create a `SocketAddress` for an IPv4 endpoint using a numeric IP address and port. This method uses `inet_pton(3)` and does not resolve DNS names. ```swift SocketAddress.ipv4("127.0.0.1", port: 8080) ``` -------------------------------- ### Length-Prefix Framing Helper Extension Source: https://docs.21.dev/data/documentation/event/partialreadsandmessageframing Provides a Swift extension for reading length-prefixed messages from a TCP socket. It handles arbitrary partial reads by looping until the full message is received. ```swift ``` -------------------------------- ### Schedule Fire-and-Forget Timer Source: https://docs.21.dev/data/documentation/event/gettingstarted Schedule a callback to execute after a specified delay using `schedule(after:_:)`. This is a fire-and-forget mechanism suitable for background tasks that should not block the calling task. ```swift loop.schedule(after: .seconds(1)) { print("one second later") } ``` -------------------------------- ### Handle Socket Errors and Closures Source: https://docs.21.dev/data/documentation/event/gettingstarted Use a `do-while` loop with `try-catch` to handle socket read operations, including clean closures, timeouts, and transport-level errors. This pattern avoids explicit observer registration. ```swift do { while true { let chunk = try await socket.read() process(chunk) } } catch SocketError.connectionClosed { // Peer closed cleanly — terminate the read loop. } catch SocketError.timeout { // Optional timeout elapsed — decide whether to retry or give up. } catch SocketError.readFailed(let errno) { // Transport-level failure (e.g. ECONNRESET). The errno payload is from // the failing read(2) syscall; pass through strerror(_:) for a message. log("read failed: \(String(cString: strerror(errno)))") } catch { // Cancellation or unrelated thrown error. throw error } ``` -------------------------------- ### ServerSocket Source: https://docs.21.dev/data/documentation/event/llms.txt Manages TCP server functionality, allowing it to accept incoming client connections. ```APIDOC ## ServerSocket ### Description Provides functionality for creating and managing TCP servers, including accepting new client connections. ### Methods - `accept()`: Asynchronously accepts an incoming client connection, returning a new `Socket`. - `close()`: Closes the server socket, preventing new connections. ### Properties - `.connections`: An `AsyncThrowingStream` that yields new incoming `Socket` instances as clients connect. ``` -------------------------------- ### Loop-Scheduled Timers with EventLoop Source: https://docs.21.dev/data/documentation/event/llms.txt Utilize the EventLoop for scheduling timers. 'sleep(for:)' provides an async sleep, while 'schedule(after:_:) offers a fire-and-forget callback mechanism, both driven by the event loop. ```swift import Event // Async sleep, driven by the loop: await EventLoop.shared.sleep(for: .milliseconds(250)) // Fire-and-forget callback: EventLoop.shared.schedule(after: .seconds(1)) { print("one second later") } ``` -------------------------------- ### Simpler Module Map for Limited Use Cases Source: https://docs.21.dev/data/documentation/event/embeddingclibrariesinswiftpm A simpler module map can be used if the library's public API is reachable through a single umbrella header and no downstream consumer uses Swift C++ interop. However, this form can still cause issues with C++ consumers. ```c module libfoo { requires !cplusplus umbrella header "foo.h" export * } ``` -------------------------------- ### Socket Source: https://docs.21.dev/data/documentation/event/llms.txt Provides asynchronous TCP socket operations, including connecting, listening, reading, and writing data. ```APIDOC ## Socket ### Description Handles asynchronous TCP socket operations, enabling non-blocking network communication. ### Methods - `connect(to: SocketAddress, loop: EventLoop, timeout: TimeInterval)`: Establishes a TCP connection to a specified `SocketAddress`. - `connect(to: String, port: Int, loop: EventLoop, timeout: TimeInterval)`: Establishes a TCP connection to a host and port. - `listen(port: Int, backlog: Int, loop: EventLoop)`: Starts listening for incoming connections on a specified port. - `read(maxBytes: Int, timeout: TimeInterval)`: Reads up to `maxBytes` from the socket. - `write(_ data: Data, timeout: TimeInterval)`: Writes `Data` to the socket. - `close()`: Closes the socket connection. ```