使用 Vapor 构建 Twitter 机器人
教程介绍
更聪明地工作,而不是更努力地工作”这句话现在到处流传。您可能会从经理和销售人员那里听到这句话,但您知道首先说的是工程师吗?
Allen F. Morgenstern 在 1930 年代创造这个术语时可能正在考虑自动化。今天,机器人吸尘器、自动驾驶汽车和数字助理形式的自动化改善了我们的生活,让我们从最乏味和重复的任务中解放出来,腾出时间进行更有趣的活动,比如学习 Swift!
本教程将教您如何像专业人士一样自动化您的 Twitter 状态,从而帮助您更聪明地工作。
您将学习如何:
- 设置Twitter 开发者帐户。
- 使用Twitter API发送推文。
- 使用 Vapor 队列安排推文。
在本教程结束时,您将拥有一个网络应用程序,每天一次向您的帐户发送 Steve Jobs 的名言。
入门
通过单击教程顶部或底部的下载材料下载项目并解压缩。
Twitter API 要求您使用 OAuth1 发出请求,并且启动项目包含所有必要的 OAuth 代码。
通过双击Package.swift在 Xcode 中打开项目。打开后,Swift 包管理器可能需要一些时间来拉取项目中包含的依赖项。
浏览文件夹以熟悉项目并运行它以确保所有内容都能编译。
您将看到以下输出:
[ NOTICE ] Server starting on http://127.0.0.1:8080
成为 Twitter 机器人开发者
Twitter 机器人是在 Twitter 平台上执行任务的简单应用程序。他们可以做很多事情,比如发推文,喜欢推文,甚至收集关于 Twitter 趋势的信息。
公司可能会使用机器人来帮助提供客户支持,而有影响力的人可能会使用它们来安排在一天中的特定时间发布推文。
机器人还可以侦听其他平台上的事件并根据变化采取行动,例如在网站发布新闻文章时发布推文。
甚至还有一个机器人可以生成飞蛾并给它们编造科学名称,@mothgenerator!
在开始使用 Twitter 的 API 发送推文之前,您需要设置您的开发者帐户并生成一些安全密钥。
设置 Twitter 开发者帐户
在 Web 浏览器中登录您的 Twitter 帐户,然后访问:https : //developer.twitter.com/en/apply-for-access。
点击申请开发者账号。您将开始一个简短的设置过程,在此期间您需要回答几个问题。
在第一个屏幕上,选择爱好者▸制作机器人▸入门。
如果您尚未在 Twitter 帐户上提供并验证您的电话号码,则需要在下一个屏幕上提供和验证您的电话号码。
从这一点来看,注册过程很简单。您如何回答问题取决于您自己的偏好以及您计划构建的应用程序和机器人的类型。完成后,您将进入Developer Portal Dashboard。
现在你可以变得更有创意了!
你的第一个 Twitter 应用
在左侧面板中,打开项目和应用程序▸概览。向下滚动并单击+ 创建应用程序。
这是整个教程中最具挑战性的部分:为您的应用命名!
该名称必须是唯一的,以免与平台上已有的名称发生冲突。如果您没有灵感,请将其命名为QuoteBot,并在其后加上一堆随机数。
下一阶段将带您进入密钥和令牌屏幕。将API Key和API Key Secret复制到安全的地方。稍后您将需要这些。
保密。保护他们的安全。
你快到最后一步了。单击屏幕右下角的应用程序设置。向下滚动到应用程序权限,单击编辑并将您的应用程序权限更改为读取和写入。单击保存并在出现的对话框中确认对权限的更改。
使用 Vapor 队列安排推文
在开始本部分之前,请务必仔细阅读此清单以确保您拥有所需的一切:
- 启动项目
- API 密钥
- API 密钥秘密
- 访问令牌
- 访问令牌秘密
Twitter 使用 API Key 和 API Key Secret 来识别您的应用程序。将它们视为您应用的用户名和密码。Access Token 和 Access Token Secret 提供进一步的身份验证,让您的机器人将推文发布到您的个人帐户。
值得庆幸的是,您不需要对这些了解太多,因为启动项目已经为您完成了大部分身份验证工作。
什么是队列?
许多 Web 服务所做的不仅仅是提供网页或响应 API 请求。您有没有想过时事通讯每周如何准时出现在您的收件箱中?控制发送验证码或推送通知的流程如何?
正是这些小工人让这一切发生了,Vapor 内置了它们!
您可以将作业放入队列并安排它们在特定时间或满足特定条件时运行。将它们想象成小工蜂,醒来执行特定任务并在完成后重新入睡。
当然,这是一个简化的解释。如果您想了解更多信息,有一个关于该主题的优秀教程,名为Vapor 和作业队列:入门
您的服务器每天中午都会使用这些小工作人员中的一个向您的个人帐户推文。
Redis 队列驱动程序
有两个驱动程序可用于在 Vapor 中处理队列:Redis和Fluent。Fluent 驱动程序可让您将作业存储在数据库中。由于该项目没有数据库,并且所有引号都只是 Swift 文件中的字符串,因此您将使用 Redis 驱动程序。
启动项目仍然在 Xcode 中打开,导航到Package.swift。在第一个dependencies数组中,添加:
.package(url: "https://github.com/vapor/queues-redis-driver.git", from: "1.0.0")
接下来,将此代码添加到App目标中的依赖项数组。
.product(name: "QueuesRedisDriver", package: "queues-redis-driver")
此代码将QueuesRedisDriver包添加到项目中,并在App目标中设置对它的引用。
保存此文件,Swift Package Manager 将下载并构建 Redis 驱动程序。如果您正确设置了所有内容,您现在将看到四个新包添加到包依赖项列表中。
注意:如果没有自动获取新的依赖项,请选择File ▸ Swift Packages ▸ Reset Package Caches。
推文调度
在 Vapor 中,计划作业是符合ScheduledJob并使用run(context: QueueContext).
要设置计划作业,请在Sources ▸ App 中创建一个名为Jobs的新文件夹。然后在Jobs 中添加一个新的 Swift 文件。将其命名为SendTweetJob.swift并填充它:
import Foundation
import Vapor
import Queues
struct SendTweetJob: ScheduledJob {
// 1
func run(context: QueueContext) -> EventLoopFuture<Void> {
// 2
context.logger.info("Posting Scheduled Tweet")
// 3
return context.eventLoop.makeSucceededFuture(())
}
}
目前这段代码中没有发生很多事情,但它是如何工作的:
该方法在ScheduledJob触发时执行。
在这里,您将日志发送到控制台。您还没有发送任何推文,但您需要此反馈进行测试。
这迫使SendTweetJob总是成功,即使推文未能发送。处理错误超出了本教程的范围。有关更多详细信息,请查看Server-Side Swift with Vapor 的第 4 章。
接下来,打开configure.swift和以下导入:
import QueuesRedisDriver
要设置作业调度,请在configure(_ app: Application)before 中添加以下代码try routes(app):
// 1
try app.queues.use(.redis(url: "redis://127.0.0.1:6379"))
// 2
app.queues.schedule(SendTweetJob())
.everySecond()
// 3
try app.queues.startScheduledJobs()
这是代码分解:
你告诉 Vapor 使用 Redis 来管理它的队列。
您为SendTweetJob上一步中创建的对象设置了计划。在这种情况下,作业每秒运行一次。当需要开始发送推文时,您会将其更改为每日计划。
最后一步告诉 Vapor,所有队列的设置都已完成,它们可以开始运行了!
单击 Xcode 播放按钮构建并运行!
稍等片刻后,您将看到该作业每秒记录到控制台一次:
[ NOTICE ] Server starting on http://127.0.0.1:8080
[ INFO ] Posting Scheduled Tweet
[ INFO ] Posting Scheduled Tweet
有了这些,就可以开始使用 Twitter API 发送一些推文了!
与 Twitter API 交互
您可能会惊讶地发现,官方 Twitter 文档在提到更常见的推文时使用状态更新。因此,端点是您将用来发推文的端点!statuses/update
API 密钥和秘密
打开OAuth.swift并在顶部找到与Authorization Keys相关的四个属性:
let apiKey = "replace with API Key"
let apiSecret = "replace with API Key Secret"
let accessToken = "replace with Access Token"
let accessSecret = "replace with Access Token Secret"
还记得你之前收集的钥匙吗?您现在需要使用它们。如果您丢失了这些密钥,您可以在Twitter 开发者控制台中重新生成它们。
用您的密钥和令牌替换占位符字符串。
管理推文
现在是时候建立一个机制来选择要发推文的引述了。
在Sources ▸ App ▸ Quotes 中,创建一个名为QuoteManager.swift的新文件并添加:
import Foundation
import Vapor
class QuoteManager {
// 1
static let shared = QuoteManager()
// 2
private var quoteBucket = Quotes.steveJobs
// 3
private func nextQuote() -> String {
if quoteBucket.isEmpty {
quoteBucket = Quotes.steveJobs
}
return quoteBucket.removeFirst()
}
// TODO: Add tweetQuote method
}
这是代码分解:
QuoteManager是一个单例,以确保quoteBucket不会在作业之间取消初始化。
它有一份工作将在发送推文时从中提取的报价列表。
此方法删除并返回存储在quoteBucket. 当桶为空时,它将重新填充并再次开始循环。
现在,替换// TODO: Add tweetQuote method为以下内容:
@discardableResult
// 1
func tweetQuote(with client: Client) -> EventLoopFuture<ClientResponse> {
// 2
let nonce = UUID().uuidString
// 3
let timestamp = String(Int64(Date().timeIntervalSince1970))
// 4
let quote = nextQuote()
// TODO: Add OAuth
}
这是代码分解:
run(context: QueueContext)从上一步开始,您可以访问 a QueueContext,其中有一个application.client,您可以在运行 a 时将其传递给此方法ScheduledJob。
该nonce是一次性使用的字符串。在这种情况下,您使用 SwiftUUID来创建它。在实践中,您可以在这里使用任何东西,只要它不会与提交给 Twitter 的任何其他随机数发生冲突。nonce 可以防止人们发送重复的请求。
这会告诉 Twitter 请求的创建时间。Twitter 拒绝任何时间戳过早的请求。
这将删除并返回存储桶中的第一个引号,如果它变空则重新填充它。
您快到了。现在您需要一些身份验证,然后您就可以发推文了 :]
推特 OAuth
找到// TODO: Add OAuth并替换为:
// 1
let signature = OAuth.tweetSignature(nonce: nonce, timestamp: timestamp, quote: quote)
// 2
let headers = OAuth.headers(nonce: nonce, timestamp: timestamp, signature: signature)
// 3
let tweetURI = URI(string: tweetURI.string.appending("?status=\(quote.urlEncodedString())"))
// TODO: post tweet
前两行在 上调用辅助方法OAuth。虽然支持这些方法的代码并不太复杂,但这超出了本教程的范围。如果您想了解有关 Twitter 如何进行身份验证的更多信息,请查看文档。
看看这段代码,你会注意到:
它生成signature使用nonce,timestamp和quote。此方法特定于向statuses/update端点发送 POST 请求,并负责将所有参数组合并转换为单个字符串。
它将signature上一步中的 应用到headers. 请求头有多种用途,包括告诉远程服务器发出请求的设备类型,以及可能存在的数据类型。在这种情况下,此代码所做的只是创建一个授权标头。
在tweetURI有quote附加的网址查询。您可能还熟悉将您发送的内容添加到 POST 请求的正文中,但这就是 Twitter 的工作方式。
您可能已经注意到某些参数出现多次。查看 ,nonce您会看到它用于创建signature和oAuthHeaders。但是如果signature已经包含了,nonce为什么还需要放在标题中呢?
它位于标题中,因此 Twitter 可以确定在离开您的服务器和到达他们的服务器之间没有发生请求篡改。这也解释了为什么quote也是signature.
终于到了发推文的时候了!
发布推文
Vapor 有几种方法可以向另一个服务发出请求。这些可以通过client对象访问。
查找// TODO: post tweet并替换为:
return client.post(tweetURI, headers: headers)
此代码用于client向 发送 POST 请求tweetURI并返回EventLoopFuture
你现在可以发推文了!
要进行测试,请将routes.swift 中的所有代码替换为:
import Vapor
func routes(_ app: Application) throws {
app.get { req -> EventLoopFuture<ClientResponse> in
return QuoteManager().tweetQuote(with: req.client)
}
}
构建并运行。
在服务器运行的情况下,打开终端窗口并使用以下 curl 命令触发推文:
curl http://localhost:8080
转到您的 Twitter 提要并检查该推文是否已发布!
注意:如果您尝试第二次运行该命令,则不会发生任何事情。您的服务器肯定会尝试发送另一条推文,但是因为您没有使用QuoteManager单例,它会以完整的状态再次启动tweetBucket并尝试发送相同的推文两次!这当然是 Twitter 忽略的。
要设置日程安排,请打开SendTweetJob.swift。在 return 语句之前添加这一行run(context: QueueContext):
_ = QuoteManager.shared.tweetQuote(with: context.application.client)
接下来,您需要更改安排时间。切换到configure.swift并交换以下代码:
app.queues.schedule(SendTweetJob())
.everySecond()
和:
app.queues.schedule(SendTweetJob())
.everySecond()
app.queues.schedule(SendTweetJob())
.daily()
.at(.noon)
恭喜!你现在有一个 Twitter 机器人,它会在每天午餐时间代表你发布新的推文!
精品教程推荐
加入我们一起学习SwiftUI
QQ:3365059189
SwiftUI技术交流QQ群:518696470
教程网站:www.openswiftui.com