Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions Sources/APNS/APNSBroadcastClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ extension APNSBroadcastClient {
headers.add(name: "authorization", value: token)
}

// Append operation specific HTTPS headers
if let operationHeaders = request.operation.headers {
for (name, value) in operationHeaders {
headers.add(name: name, value: value)
}
}

// Build the request URL
let requestURL = "\(self.environment.url):\(self.environment.port)/1/apps/\(self.bundleID)\(request.operation.path)"

Expand All @@ -165,12 +172,15 @@ extension APNSBroadcastClient {

// Extract request ID from response
let apnsRequestID = response.headers.first(name: "apns-request-id").flatMap { UUID(uuidString: $0) }


// Extract channel ID from response, or from request headers (as 'read' operation doesn't return in payload
let channelID = response.headers.first(name: "apns-channel-id") ?? request.operation.headers?["apns-channel-id"]

// Handle successful responses
if response.status == .ok || response.status == .created {
if response.status == .ok || response.status == .created || response.status == .noContent {
let body = try await response.body.collect(upTo: 1024 * 1024) // 1MB max
let responseBody = try responseDecoder.decode(ResponseBody.self, from: body)
return APNSBroadcastResponse(apnsRequestID: apnsRequestID, body: responseBody)
let responseBody = try? responseDecoder.decode(ResponseBody.self, from: body)
return APNSBroadcastResponse(apnsRequestID: apnsRequestID, channelID: channelID, body: responseBody)
}

// Handle error responses
Expand Down
8 changes: 1 addition & 7 deletions Sources/APNSCore/Broadcast/APNSBroadcastChannel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@
/// Represents a broadcast channel configuration.
public struct APNSBroadcastChannel: Codable, Sendable {
enum CodingKeys: String, CodingKey {
case channelID = "channel-id"
case messageStoragePolicy = "message-storage-policy"
case pushType = "push-type"
}

/// The unique identifier for the broadcast channel (only present in responses).
public let channelID: String?

/// The message storage policy for this channel.
public let messageStoragePolicy: APNSBroadcastMessageStoragePolicy

Expand All @@ -34,14 +30,12 @@ public struct APNSBroadcastChannel: Codable, Sendable {
///
/// - Parameter messageStoragePolicy: The storage policy for messages in this channel.
public init(messageStoragePolicy: APNSBroadcastMessageStoragePolicy) {
self.channelID = nil
self.messageStoragePolicy = messageStoragePolicy
self.pushType = "LiveActivity"
}

/// Internal initializer used for decoding responses that include channel ID.
public init(channelID: String?, messageStoragePolicy: APNSBroadcastMessageStoragePolicy, pushType: String = "LiveActivity") {
self.channelID = channelID
public init(messageStoragePolicy: APNSBroadcastMessageStoragePolicy, pushType: String = "LiveActivity") {
self.messageStoragePolicy = messageStoragePolicy
self.pushType = pushType
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extension APNSBroadcastClientProtocol {
public func create(
channel: APNSBroadcastChannel,
apnsRequestID: UUID? = nil
) async throws -> APNSBroadcastResponse<APNSBroadcastChannel> {
) async throws -> APNSBroadcastResponse<EmptyPayload> {
let request = APNSBroadcastRequest<APNSBroadcastChannel>(
operation: .create,
message: channel,
Expand Down
14 changes: 11 additions & 3 deletions Sources/APNSCore/Broadcast/APNSBroadcastRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,18 @@ public struct APNSBroadcastRequest<Message: Encodable>: Sendable where Message:
/// The path for this operation.
public var path: String {
switch self {
case .create, .listAll:
case .create, .delete, .read, .listAll:
return "/channels"
case .read(let channelID), .delete(let channelID):
return "/channels/\(channelID)"
}
}

/// HTTP Headers for this operation.
public var headers: [String: String]? {
switch self {
case .delete(let channelID), .read(channelID: let channelID):
return ["apns-channel-id": channelID]
default:
return nil
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions Sources/APNSCore/Broadcast/APNSBroadcastResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ public struct APNSBroadcastResponse<Body: Decodable>: Sendable where Body: Senda
/// The request ID returned by APNs.
public let apnsRequestID: UUID?

/// The channel ID returned by APNs.
public let channelID: String?

/// The response body.
public let body: Body
public let body: Body?

public init(apnsRequestID: UUID?, body: Body) {
public init(apnsRequestID: UUID?, channelID: String?, body: Body?) {
self.apnsRequestID = apnsRequestID
self.channelID = channelID
self.body = body
}
}
Loading