From ccc305b74face1160d9543ecfed112d2818454de Mon Sep 17 00:00:00 2001 From: Andy Ford Date: Thu, 20 Feb 2025 14:33:08 +0000 Subject: [PATCH 1/2] docs: trim readme down to essential information We consider the docs site to be the source of truth for our documentation (outside of inline documentation). This change follows the steps already taken by JS to remove the extra information from the README. --- README.md | 403 ------------------------------------------------------ 1 file changed, 403 deletions(-) diff --git a/README.md b/README.md index 425b535..1ac133a 100644 --- a/README.md +++ b/README.md @@ -81,409 +81,6 @@ environments. To use Chat you must also set a [`clientId`](https://ably.com/docs/auth/identified-clients) so that users are identifiable. -## Connections - -The Chat SDK uses a single connection to Ably, which is exposed via the `ChatClient#connection` property. You can use this -property to observe the connection state and take action accordingly. - -### Current connection status - -You can view the current connection status at any time: - -```swift -let status = await chatClient.connection.status -let error = await chatClient.connection.error -``` - -### Subscribing to connection status changes - -To subscribe to connection status changes, create a subscription with the `onStatusChange` method. You can then iterate over it using its `AsyncSequence` interface: - -```swift -let subscription = chatClient.connection.onStatusChange() -for await statusChange in subscription { - print("Connection status changed to: \(statusChange.current)") -} -``` - -## Chat rooms - -### Creating or retrieving a chat room - -You can create or retrieve a chat room with name `"basketball-stream"` this way: - -```swift -let room = try await chatClient.rooms.get(roomID: "basketball-stream", options: RoomOptions()) -``` - -The second argument to `rooms.get` is a `RoomOptions` argument, which tells the Chat SDK what features you would like your room to use and -how they should be configured. - -You can also use `RoomOptions.allFeaturesEnabled` to enable all room features with the default configuration. - -For example, you can set the timeout between keystrokes for typing events as part of the room options. Sensible defaults for each of the -features are provided for your convenience: - -- A typing timeout (time of inactivity before typing stops) of 5 seconds. -- Entry and subscription to presence. - -Here’s an example demonstrating how to specify a custom typing timeout of 3 seconds: - -```swift -let room = try await chatClient.rooms.get(roomID: "basketball-stream", - options: .init(typing: TypingOptions(timeout: 3.0))) -``` - -In order to use the same room but with different options, you must first `release` the room before requesting an instance with the changed -options (see below for more information on releasing rooms). - -Note that: - -- If a `release` call is currently in progress for the room (see below), then a call to `get` will wait for that to complete before completing - itself. -- If a `get` call is currently in progress for the room and `release` is called, the `get` call will fail. - -### Attaching to a room - -To start receiving events on a room, it must first be attached. This can be done using the `attach` method: - -```swift -try await room.attach() -``` - -### Detaching from a room - -To stop receiving events on a room, it must be detached, which can be achieved by using the `detach` method: - -```swift -room.detach() -``` - -Note: This does not remove any event listeners you have registered and they will begin to receive events again in the -event that the room is re-attached. - -### Releasing a room - -Depending on your application, you may have multiple rooms that come and go over time (e.g. if you are running 1:1 support chat). When you -are completely finished with a room, you may `release` it which allows the underlying resources to be collected: - -```swift -_ = try await rooms.release(roomID: "basketball-stream") -``` - -Once `release` is called, the room will become unusable and you will need to get a new instance using `rooms.get`. - -> [!NOTE] -> Releasing a room may be optional for many applications. If release is not called, the server will automatically tidy up -> connections and other resources associated with the room after a period of time. - -### Monitoring room status - -Monitoring the status of the room is key to a number of common chat features. For example, you might want to display a warning when the room -has become detached. - -### Current status of a room - -To get the current status (and error), you can use the `status` property like this: - -```swift -switch await room.status { - case let .failed(error: error): - // use error - } - ... -} -``` - -### Listening to room status updates - -You can also subscribe to changes in the room status and be notified whenever they happen by creating a subscription using the room’s `onStatusChange` method and then iterating over this subscription using its `AsyncSequence` interface: - -```swift -let statusSubscription = try await room.onStatusChange() -for await status in statusSubscription { - print("Room status: \(status)") -} -``` - -## Handling discontinuity - -There may be instances where the connection to Ably is lost for a period of time, for example, when the user enters a tunnel. In many -circumstances, the connection will recover and operation will continue with no discontinuity of messages. However, during extended -periods of disconnection, continuity cannot be guaranteed and you'll need to take steps to recover messages you might have missed. - -Each feature of the Chat SDK provides an `onDiscontinuity` method. Here you can create a subscription that will emit a discontinuity event on its `AsyncSequence` interface whenever a -discontinuity in that feature has been observed. - -Taking messages as an example, you can listen for discontinuities like so: - -```swift -let subscription = room.messages.onDiscontinuity() -for await discontinuityEvent in subscription { - print("Recovering from the error: \(discontinuityEvent.error)") -} -``` - -## Chat messages - -### Subscribing to incoming messages - -To subscribe to incoming messages you create a subscription for the room `messages` object: - -```swift -let messagesSubscription = try await room.messages.subscribe() -for await message in messagesSubscription { - print("Message received: \(message)") -} -``` - -### Sending messages - -To send a message, simply call `send` on the room `messages` property, with the message you want to send: - -```swift -let message = try await room.messages.send(params: .init(text: "hello")) -``` - -### Retrieving message history - -The messages object also exposes the `get` method which can be used to request historical messages in the chat room according -to the given criteria. It returns a paginated response that can be used to request more messages: - -```swift -let paginatedResult = try await room.messages.get(options: .init(orderBy: .newestFirst)) -print(paginatedResult.items) - -if paginatedResult.hasNext { - let next = try await paginatedResult.next! - print(next.items) -} else { - print("End of messages") -} -``` - -### Retrieving message history for a subscribed listener - -The return value from `messages.subscribe` includes the `getPreviousMessages` -method, which can be used to request historical messages in the chat room that were sent up to the point that a particular listener was subscribed. It returns a -paginated response that can be used to request for more messages: - -```swift -let messagesSubscription = try await room.messages.subscribe() -let paginatedResult = try await messagesSubscription.getPreviousMessages(params: .init(limit: 50)) // `orderBy` here is ignored and always `newestFirst` -print(paginatedResult.items) - -if paginatedResult.hasNext { - let next = try await paginatedResult.next! - print(next.items) -} else { - print("End of messages") -} -``` - -## Online status - -### Retrieving online members - -You can get the complete list of currently online or present members, their state and data, by calling the `presence.get()` method which returns -a list of the presence messages, where each message contains the most recent data for a member: - -```swift -// Retrieve all users entered into presence as an array: -let presentMembers = try await room.presence.get() - -// Retrieve the status of specific users by their clientId: -let presentMember = try await room.presence.get(params: .init(clientID: "clemons123")) - -// To check whether the user is online or not: -let isPresent = try await room.presence.isUserPresent(clientID: "clemons123") -``` - -### Entering the presence set - -To appear online for other users, you can enter the presence set of a chat room. While entering presence, you can provide optional data that -will be associated with the presence message (can be a nested dictionary): - -```swift -try await room.presence.enter(data: ["status": "Online"]) -``` - -### Updating the presence data - -Updates allow you to make changes to the custom data associated with a present user. Common use-cases include updating the user's status: - -```swift -try await room.presence.update(data: ["status": "Busy"]) -``` - -### Leaving the presence set - -Ably automatically triggers a presence leave if a client goes offline. But you can also manually leave the presence set as a result of a UI -action. While leaving presence, you can provide optional data that will be associated with the presence message: - -```swift -try await room.presence.leave(data: ["status": "Bye!"]) -``` - -### Subscribing to presence updates - -You can create a single subscription for all presence event types: - -```swift -let presenceSubscription = try await room.presence.subscribe(events: [.enter, .leave, .update]) -for await event in presenceSubscription { - print("Presence event `\(event.action)` from `\(event.clientId)` with data `\(event.data)`") -} -``` - -## Typing indicators - -> [!NOTE] -> You should be attached to the room to enable this functionality. - -Typing events allow you to inform others that a client is typing and also subscribe to others' typing status. - -### Retrieving the set of current typers - -You can get the complete set of the current typing `clientId`s, by calling the `typing.get` method. - -```swift -// Retrieve the entire list of currently typing clients -let currentlyTypingClientIds = try await room.typing.get() -``` - -### Start typing - -To inform other users that you are typing, you can call the start method. This will begin a timer that will automatically stop typing after -a set amount of time. - -```swift -try await room.typing.start() -``` - -Repeated calls to start will reset the timer, so the clients typing status will remain active. - -### Stop typing - -You can immediately stop typing without waiting for the timer to expire. - -```swift -try await room.typing.start() -// Some short delay - timer not yet expired - -try await room.typing.stop() -// Timer cleared and stopped typing event emitted and listeners are notified -``` - -### Subscribing to typing updates - -To subscribe to typing events, create a subscription with the `subscribe` method. You can then iterate over it using its `AsyncSequence` interface: - -```swift -let typingSubscription = try await room.typing.subscribe() -for await typing in typingSubscription { - typingInfo = typing.currentlyTyping.isEmpty ? "" : "Typing: \(typing.currentlyTyping.joined(separator: ", "))..." -} -``` - -## Occupancy of a chat room - -Occupancy tells you how many users are connected to the chat room. - -### Subscribing to occupancy updates - -To subscribe to occupancy updates, create a subscription by calling the `subscribe` method on the chat room’s `occupancy` member. You can then iterate over it using its `AsyncSequence` interface: - -```swift -let occupancySubscription = try await room.occupancy.subscribe() -for await event in occupancySubscription { - occupancyInfo = "Connections: \(event.presenceMembers) (\(event.connections))" -} -``` - -Occupancy updates are delivered in near-real-time, with updates in quick succession batched together for performance. - -### Retrieving the occupancy of a chat room - -You can request the current occupancy of a chat room using the `occupancy.get` method: - -```swift -let occupancy = try await room.occupancy.get() -``` - -## Room-level reactions - -You can subscribe to and send ephemeral room-level reactions by using the room `reactions` object. -To send room-level reactions, you must be [attached](#attaching-to-a-room) to the room. - -### Sending a reaction - -To send a reaction such as `like`: - -```swift -try await room.reactions.send(params: .init(type: "like")) -``` - -You can also add any metadata and headers to reactions: - -```swift -try await room.reactions.send(params: .init(type: "🎉", metadata: ["effect": "fireworks"])) -``` - -### Subscribing to room reactions - -Subscribe to receive room-level reactions: - -```swift -let reactionSubscription = try await room.reactions.subscribe() -for await reaction in reactionSubscription { - print("Received a reaction of type \(reaction.type), and metadata \(reaction.metadata)") -} -``` - -## Example app - -This repository contains an example app, written using SwiftUI, which demonstrates how to use the SDK. The code for this app is in the [`Example`](Example) directory. - -In order to allow the app to use modern SwiftUI features, it supports the following OS versions: - -- macOS 14 and above -- iOS 17 and above -- tvOS 17 and above - -To run the app, open the `AblyChat.xcworkspace` workspace in Xcode and run the `AblyChatExample` target. If you wish to run it on an iOS or tvOS device, you’ll need to set up code signing. - -## In-depth - -### Channels Behind Chat Features - -It might be useful to know that each feature is backed by an underlying Pub/Sub channel. You can use this information to enable -interoperability with other platforms by subscribing to the channels directly using -the [Ably Pub/Sub SDKs](https://ably.com/docs/products/channels) for those platforms. - -The channel for each feature can be obtained via the `channel` property -on that feature. - -```swift -let messagesChannel = room.messages.channel -``` - -**Warning**: You should not attempt to change the state of a channel directly. Doing so may cause unintended side-effects in the Chat SDK. - -### Channels Used - -For a given chat room, the channels used for features are as follows: - -| Feature | Channel | -| --------- | ------------------------------------ | -| Messages | `::$chat::$chatMessages` | -| Presence | `::$chat::$chatMessages` | -| Occupancy | `::$chat::$chatMessages` | -| Reactions | `::$chat::$reactions` | -| Typing | `::$chat::$typingIndicators` | - ---- - ## Contributing For guidance on how to contribute to this project, see the [contributing guidelines](CONTRIBUTING.md). From 20d5a76b3ceb91275c2003b84bb61f83bc86870b Mon Sep 17 00:00:00 2001 From: Andy Ford Date: Thu, 20 Feb 2025 15:14:58 +0000 Subject: [PATCH 2/2] docs: getting started guide This change includes a basic getting-started guide intended to guide users through their first steps with Ably Chat to sending their first message. This will be replicated in the website dashboard in time. --- README.md | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/README.md b/README.md index 1ac133a..dbf36c7 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,89 @@ environments. To use Chat you must also set a [`clientId`](https://ably.com/docs/auth/identified-clients) so that users are identifiable. +## Getting Started + +At the end of this tutorial, you will have initialized the Ably Chat client and sent your first message. + +First of all, start by creating a Swift project and installing the Chat SDK using the instructions described above. Next, replace the contents of your `main.swift` file with +the following code. This simple script initializes the Chat client, creates a chat room and sends a message, printing it to the console when it is received over the websocket connection. + +```swift +import Ably +import AblyChat +import Foundation + +// Create the Ably Realtime client using your API key and use that to instantiate the Ably Chat client. +let realtimeOptions = ARTClientOptions() +realtimeOptions.key = "" +realtimeOptions.clientId = "ably-chat" +let realtime = ARTRealtime(options: realtimeOptions) +let chatClient = DefaultChatClient(realtime: realtime, clientOptions: nil) + +// Subscribe to connection state changes +let connectionStateSubscription = chatClient.connection.onStatusChange() +Task { + for await stateChange in connectionStateSubscription { + print("Connection status changed: \(stateChange.current)") + } +} + +// Get a chat room for the tutorial - using the defaults to enable all features in the chat room +let room = try await chatClient.rooms.get( + roomID: "readme-getting-started", options: RoomOptions.allFeaturesEnabled) + +// Add a listener to observe changes to the chat rooms status +let statusSubscription = await room.onStatusChange() +Task { + for await status in statusSubscription { + print("Room status changed: \(status.current)") + } +} + +// Attach the chat room - this means we will begin to receive messages from the server +try await room.attach() + +// Add a listener for new messages in the chat room +let messagesSubscription = try await room.messages.subscribe() +Task { + // Subscribe to messages + for await message in messagesSubscription { + print("Message received: \(message.text)") + } +} + +// Send a message +_ = try await room.messages.send( + params: .init(text: "Hello, World! This is my first message with Ably Chat!")) + +// Wait 5 seconds before closing the connection so we have plenty of time to receive the message we just sent +// This disconnects the client from Ably servers +try await Task.sleep(nanoseconds: 5 * NSEC_PER_SEC) +await chatClient.rooms.release(roomID: "readme-getting-started") +realtime.close() +print("Connection closed") +``` + +Now run your script: + +```shell +swift run +``` + +All being well, you should now see the following in your terminal: + +``` +Room status changed: attaching(error: nil) +Connection status changed: connected +Room status changed: attached +Message received: Hello, World! This is my first message with Ably Chat! +Room status changed: releasing +Room status changed: released +Connection closed +``` + +Congratulations! You have sent your first message using the Ably Chat SDK! + ## Contributing For guidance on how to contribute to this project, see the [contributing guidelines](CONTRIBUTING.md).