Skip to content

Commit

Permalink
add _Presence type
Browse files Browse the repository at this point in the history
  • Loading branch information
grdsdev committed Dec 29, 2023
1 parent c4e1910 commit 363e426
Show file tree
Hide file tree
Showing 8 changed files with 360 additions and 213 deletions.
88 changes: 58 additions & 30 deletions Examples/SlackClone/MessagesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ final class MessagesViewModel {
let channel: Channel
var messages: [Message] = []
var newMessage = ""
var presences: [UserPresence] = []

let api: MessagesAPI

Expand All @@ -41,53 +42,70 @@ final class MessagesViewModel {
func startObservingNewMessages() {
realtimeChannelV2 = supabase.realtimeV2.channel("messages:\(channel.id)")

let changes = realtimeChannelV2!.postgresChange(
let messagesChanges = realtimeChannelV2!.postgresChange(
AnyAction.self,
schema: "public",
table: "messages",
filter: "channel_id=eq.\(channel.id)"
)

let presenceChange = realtimeChannelV2!.presenceChange()

observationTask = Task {
try! await realtimeChannelV2!.subscribe()

for await change in changes {
do {
switch change {
case let .insert(record):
let message = try await self.message(from: record)
self.messages.append(message)

case let .update(record):
let message = try await self.message(from: record)

if let index = self.messages.firstIndex(where: { $0.id == message.id }) {
messages[index] = message
} else {
messages.append(message)
}
await realtimeChannelV2!.subscribe()

let state = try? await UserPresence(userId: supabase.auth.session.user.id, onlineAt: Date())

case let .delete(oldRecord):
let id = oldRecord.oldRecord["id"]?.intValue
self.messages.removeAll { $0.id == id }
_ = await realtimeChannelV2!.status.values.first { $0 == .subscribed }

if let state = try? AnyJSON(state).objectValue {
await realtimeChannelV2!.track(state: state)
}

default:
break
Task {
for await change in messagesChanges {
do {
switch change {
case let .insert(record):
let message = try await self.message(from: record)
self.messages.append(message)

case let .update(record):
let message = try await self.message(from: record)

if let index = self.messages.firstIndex(where: { $0.id == message.id }) {
messages[index] = message
} else {
messages.append(message)
}

case let .delete(oldRecord):
let id = oldRecord.oldRecord["id"]?.intValue
self.messages.removeAll { $0.id == id }

default:
break
}
} catch {
dump(error)
}
} catch {
dump(error)
}
}

Task {
for await change in presenceChange {
let presences = try change.decodeJoins(as: UserPresence.self)
self.presences = presences
}
}
}
}

func stopObservingMessages() {
Task {
do {
try await realtimeChannelV2?.unsubscribe()
} catch {
dump(error)
}
observationTask?.cancel()
await realtimeChannelV2?.untrack()
await realtimeChannelV2?.unsubscribe()
}
}

Expand Down Expand Up @@ -138,6 +156,11 @@ final class MessagesViewModel {
}
}

struct UserPresence: Codable {
var userId: UUID
var onlineAt: Date
}

struct MessagesView: View {
@Bindable var model: MessagesViewModel

Expand All @@ -159,6 +182,11 @@ struct MessagesView: View {
.padding()
}
.navigationTitle(model.channel.slug)
.toolbar {
ToolbarItem(placement: .principal) {
Text("\(model.presences.count) online")
}
}
.onAppear {
model.loadInitialMessages()
model.startObservingNewMessages()
Expand Down
1 change: 1 addition & 0 deletions Sources/Auth/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Foundation
@_spi(Internal) import _Helpers

public typealias AnyJSON = _Helpers.AnyJSON
public typealias JSONObject = _Helpers.JSONObject

public enum AuthChangeEvent: String, Sendable {
case initialSession = "INITIAL_SESSION"
Expand Down
18 changes: 11 additions & 7 deletions Sources/Realtime/CallbackManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ final class CallbackManager: @unchecked Sendable {
}

func triggerPresenceDiffs(
joins: [String: Presence],
leaves: [String: Presence],
joins: [String: _Presence],
leaves: [String: _Presence],
rawMessage: RealtimeMessageV2
) {
let presenceCallbacks = mutableState.callbacks.compactMap {
Expand All @@ -118,11 +118,15 @@ final class CallbackManager: @unchecked Sendable {
}
return nil
}
presenceCallbacks.forEach { $0.callback(PresenceActionImpl(
joins: joins,
leaves: leaves,
rawMessage: rawMessage
)) }
presenceCallbacks.forEach {
$0.callback(
PresenceActionImpl(
joins: joins,
leaves: leaves,
rawMessage: rawMessage
)
)
}
}

func reset() {
Expand Down
Loading

0 comments on commit 363e426

Please sign in to comment.