Pusher Channels Swift REST API 库

Build Status Latest Release API Docs Supported Platforms Swift Versions Twitter LICENSE

一个用于与 Pusher Channels HTTP API 交互的 Swift 库。

注册一个 Pusher 帐户,设置一个 Channels 应用,并使用如下所示的应用凭据。

支持的平台

部署目标

安装

要使用 Swift Package Manager 将库集成到您的项目中,您可以在 Xcode 中添加该库作为依赖项 – 请参阅文档。 包仓库 URL 是

https://github.com/pusher/pusher-http-swift.git

或者,您可以将该库作为依赖项添加到您的 Package.swift 文件中。 例如

// swift-tools-version:5.3
import PackageDescription

let package = Package(
    name: "YourPackage",
    products: [
        .library(
            name: "YourPackage",
            targets: ["YourPackage"]),
    ],
    dependencies: [
        .package(url: "https://github.com/pusher/pusher-http-swift.git",
                 .upToNextMajor(from: "1.0.1")),
    ],
    targets: [
        .target(
            name: "YourPackage",
            dependencies: ["Pusher"]),
    ]
)

然后,您需要在任何希望使用该库的源文件中包含一个 import Pusher 语句。

使用

本节介绍如何配置和使用此库,通过 Channels HTTP API 作为 Pusher Channels 应用的接口。

注意

配置

使用 Pusher Channels 应用程序中的凭据来创建一个新的 Pusher 实例,该实例将作为您的 API 客户端

let pusher = Pusher(options: try! PusherClientOptions(appId: 123456,
                                                      key: "YOUR_APP_KEY",
                                                      secret: "YOUR_APP_SECRET",
                                                      encryptionMasterKey: "YOUR_BASE64_ENCODED_MASTER_KEY",
                                                      cluster: "YOUR_APP_CLUSTER"))

注意

触发事件

要在一个或多个频道上触发事件,请使用 trigger(event:callback:) 方法。

单个频道

let publicChannel = Channel(name: "my-channel", type: .public)
let publicEvent = try! Event(name: "my-event",
                             data: "hello world!",
                             channel: publicChannel)

self.pusher.trigger(event: publicEvent) { result in
    switch result {
        case .success(let channelSummaries):
            // Inspect `channelSummaries`
        case .failure(let error):
            // Handle error
    }
}

多个频道

let publicChannelOne = Channel(name: "my-channel", type: .public)
let publicChannelTwo = Channel(name: "my-other-channel", type: .public)
let multichannelEvent = try! Event(name: "my-multichannel-event",
                                   data: "hello world!",
                                   channels: [publicChannelOne,
                                              publicChannelTwo])

self.pusher.trigger(event: publicEvent) { result in
    switch result {
        case .success(let channelSummaries):
            // Inspect `channelSummaries`
        case .failure(let error):
            // Handle error
    }
}

事件批处理

也可以使用 trigger(events:callback:) 方法,通过单个 API 调用发送多个事件(在多租户集群上,每次调用最多 10 个事件)

let publicChannelOne = Channel(name: "my-channel", type: .public)
let publicChannelTwo = Channel(name: "my-other-channel", type: .public)
let eventOne = try! Event(name: "my-event",
                          data: "hello world!",
                          channel: publicChannelOne)
let eventTwo = try! Event(name: "my-other-event",
                          data: "hello world, again!",
                          channel: publicChannelTwo)

self.pusher.trigger(events: [eventOne, eventTwo]]) { result in
    switch result {
        case .success(let channelInfoList):
            // Inspect `channelInfoList`
        case .failure(let error):
            // Handle error
    }
}

排除接收者

在某些情况下,您希望阻止广播事件的客户端接收该事件。 您可以通过指定其 socketId [href="https://pusher.com/docs/channels/server_api/excluding-event-recipients" rel="nofollow" data-turbo="false">https://pusher.com/docs/channels/server_api/excluding-event-recipients] 来实现, 触发事件时

let socketIdToExclude = "123.456"
let publicChannel = Channel(name: "my-channel", type: .public)
let excludedClientEvent = try! Event(name: "my-event",
                                     data: "hello world!",
                                     channel: publicChannel,
                                     socketId: socketIdToExclude)

self.pusher.trigger(event: excludedClientEvent) { result in
    switch result {
        case .success(let channelSummaries):
            // Inspect `channelSummaries`
        case .failure(let error):
            // Handle error
    }
}

在触发事件时获取频道属性 [实验性]

可以使用 Event 上的 attributeOptions 参数来获取有关已触发到的频道的信息。 这适用于两种 trigger(…) 方法

let publicChannel = Channel(name: "my-channel", type: .public)
let publicEvent = try! Event(name: "my-event",
                             data: "hello world!",
                             channel: publicChannel,
                             attributeOptions: [.subscriptionCount])

self.pusher.trigger(event: publicEvent) { result in
    switch result {
        case .success(let channelSummaries):
            // Inspect `channelSummaries`
        case .failure(let error):
            // Handle error
    }
}

注意

let publicChannel = Channel(name: "my-channel", type: .public)
    let publicEvent = try! Event(name: "my-event",
                                    data: "hello world!",
                                    channel: publicChannel)

    let sema = DispatchSemaphore(value: 0)
    pusher.trigger(event: publicEvent) { result in
        switch result {
        case .success(let channelSummaries):
            // Inspect `channelSummaries
        case .failure(let error):
            // Handle error
        }
        sema.signal()
    }
    sema.wait()

验证频道订阅

尝试订阅私有频道或在线频道的用户必须首先通过身份验证。身份验证令牌可以返回给尝试订阅的用户客户端,该客户端需要使用服务器进行身份验证。

私有频道

要验证尝试订阅私有频道用户的身份,可以使用 authenticate(channel:socketId:callback:) 方法

let userSocketId = "123.456"
let privateChannel = Channel(name: "my-channel", type: .private)

self.pusher.authenticate(channel: privateChannel,
                         socketId: userSocketId) { result in
    switch result {
        case .success(let authToken):
            // Inspect `authToken`
        case .failure(let error):
            // Handle error
    }
}

在线频道

要验证尝试订阅在线频道用户的身份,您必须为同一方法提供一个 userData 参数

let userData = PresenceUserAuthData(userId: "USER_ID", userInfo: ["name": "Joe Bloggs"])
let presenceChannel = Channel(name: "my-channel", type: .presence)

self.pusher.authenticate(channel: presenceChannel,
                         socketId: "USER_SOCKET_ID",
                         userData: userData) { result in
    switch result {
        case .success(let authToken):
            // Inspect `authToken`
        case .failure(let error):
            // Handle error
    }
}

验证 Webhook

此库提供了一种方法来验证收到的 webhook 请求是否真实且是从 Pusher 收到的。 由于 webhook 端点可供全球互联网访问,因此验证 webhook 请求是否来自 Pusher 非常重要。 有效的 webhook 包含特殊的标头,其中包含您的应用程序密钥的副本和 webhook 负载(即其正文)的 HMAC 签名

self.pusher.verifyWebhook(request: receivedWebhookRequest) { result in
    switch result {
        case .success(let webhook):
            // Inspect `webhook`
        case .failure(let error):
            // Handle error
    }
}

端到端加密

此库支持私有频道的端到端加密。 这意味着只有您和您连接的客户端才能读取您的消息。 Pusher 无法解密它们。 您可以通过以下步骤启用此功能

  1. 您应该首先设置私有频道。这涉及到在您的服务器上创建一个身份验证端点

  2. 接下来,生成您的 32 字节主加密密钥,将其编码为 Base-64 并将其传递给 PusherClientOptions 初始化器。 这是秘密,您不应该与任何人分享,甚至包括 Pusher。

openssl rand -base64 32
let options = try! PusherClientOptions(appId: 123456,
                                       key: "YOUR_APP_KEY",
                                       secret: "YOUR_APP_SECRET",
                                       encryptionMasterKey: "<MASTER KEY GENERATED BY PREVIOUS COMMAND>",
                                       cluster: "YOUR_APP_CLUSTER")
  1. 您希望使用端到端加密的频道应为 encrypted 类型。

  2. 在您的客户端中订阅这些频道,您就完成了!您可以通过查看 https://dashboard.pusher.com/ 上的调试控制台并查看混乱的密文来验证它是否工作。

重要说明:这不会加密非 encrypted 类型的频道上的消息。

限制:您不能在调用 trigger(event:callback:) 方法时在多个频道上触发单个事件,例如

let publicChannel = Channel(name: "my-channel", type: .public)
let encryptedChannel = Channel(name: "my-other-channel", type: .encrypted)
let event = try! Event(name: "my-event",
                       data: "hello world!",
                       channels: [publicChannel, encryptedChannel])

self.pusher.trigger(event: event]) { result in
    switch result {
        case .success(let channelSummaries):
            // Inspect `channelSummaries`
        case .failure(let error):
            // Handle error
    }
}

理由:此库中的方法直接映射到单个 Channels HTTP API 请求。 如果我们允许在多个频道上触发单个事件(某些加密,某些未加密),则需要两个 API 请求:一个用于将事件加密到加密频道,另一个用于将事件解密到未加密频道。

应用程序状态查询

可以使用该库获取有关 Channels 应用程序当前状态的信息。 这包括占用频道的状态和订阅在线频道的用户。

获取占用频道列表

可以使用 channels(withFilter:attributeOptions:callback:) 方法获取 Channels 应用程序的任何占用频道列表

// Fetching all occupied channels
self.pusher.channels { result in
    switch result {
        case .success(let channelSummaries):
            // Inspect `channelSummaries`
        case .failure(let error):
            // Handle error
    }
}

// Fetching only occupied private channels
self.pusher.channels(withFilter: .private) { result in
    switch result {
        case .success(let channelSummaries):
            // Inspect `channelSummaries`
        case .failure(let error):
            // Handle error
    }
}

// Fetching all occupied presence channels (with user counts)
self.pusher.channels(withFilter: .presence,
                     attributeOptions: .userCount) { result in
    switch result {
        case .success(let channelSummaries):
            // Inspect `channelSummaries`
        case .failure(let error):
            // Handle error
    }
}

获取有关频道的信息

可以使用 channelInfo(for:attributeOptions:callback:) 方法获取有关 Channels 应用程序的频道的信息

// Fetch information for a public channel
let publicChannel = Channel(name: "my-channel", type: .public)
self.pusher.channelInfo(for: publicChannel) { result in
    switch result {
        case .success(let channelInfo):
            // Inspect `channelInfo`
        case .failure(let error):
            // Handle error
    }
}

// Fetch information for a private channel (with subscription count)
let privateChannel = Channel(name: "my-channel", type: .private)
self.pusher.channelInfo(for: privateChannel,
                        attributeOptions: [.subscriptionCount]) { result in
    switch result {
        case .success(let channelInfo):
            // Inspect `channelInfo`
        case .failure(let error):
            // Handle error
    }
}

// Fetch information for a presence channel (with user count)
let presenceChannel = Channel(name: "my-channel", type: .presence)
self.pusher.channelInfo(for: presenceChannel,
                        attributeOptions: [.userCount]) { result in
    switch result {
        case .success(let channelInfo):
            // Inspect `channelInfo`
        case .failure(let error):
            // Handle error
    }
}

注意

获取订阅在线频道的用户列表

可以使用 users(for:callback:) 方法获取 Channels 应用程序的在线频道的订阅用户列表

let presenceChannel = Channel(name: "my-channel", type: .presence)
self.pusher.users(for: presenceChannel) { result in
    switch result {
        case .success(let users):
            // Inspect `users`
        case .failure(let error):
            // Handle error
    }
}

文档

完整的库文档可以在 API 文档中找到。

报告错误和请求功能

报告错误或请求新功能时,请确保使用相关的 issue 模板。 另请先检查是否存在已涵盖您的错误报告或新功能请求的开放 issue。

致谢

该库由 Pusher 拥有和维护。 最初由 Daniel Browne 创建。

它使用来自以下第三方存储库的代码

这些库的各个许可证包含在相应的 Swift 文件中。

许可证

该库是完全开源的,并根据 MIT 许可证发布。 如果您想在自己的项目中使用它,请参阅 LICENSE 了解详细信息。