🚀 发送新星通知的 4 大方法⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️
TL;DR
TL;DR
在上一篇文章中,我讨论了如何创建GitHub 星星监控器。
在本文中,我将向您展示如何每天获取新星星的信息。
我们将学习:
- 如何构建通用系统来创建和使用提供程序。
- 如何使用提供程序发送通知。
- 使用不同提供商的不同用例。
您的后台工作平台🔌
Trigger.dev 是一个开源库,可让您使用 NextJS、Remix、Astro 等为您的应用程序创建和监控长时间运行的作业!
请帮我们点个星🥹。
这有助于我们创作更多类似的文章💖
让我们开始吧🔥
我们将创建不同的提供商,以便在有新星出现时通知我们。我们将设置Email
、SMS
、Slack
和Discord
通知。
我们的目标是让每个贡献者都能在未来轻松地贡献更多服务。
每个提供商都会有一组不同的参数,有些只有参数API keys
,有些只有电话号码,具体取决于提供商。
为了验证这些密钥,让我们安装zod
;它是一个定义模式并根据模式检查数据的很棒的库。
您可以通过运行以下命令开始:
npm install zod --save
完成后,创建一个名为 的新文件夹providers
,然后在其中创建一个名为 的新文件register.provider.ts
。
这是该文件的代码:
import {Schema} from "zod";
export function registerProvider<T>(
name: string,
options: {active: boolean},
validation: Schema<T>,
run: (libName: string, stars: number, values: T) => Promise<void>
) {
// if not active, we can just pass an empty function, nothing will run
if (!options.active) {
return () => {};
}
// will validate and remove unnecessary values (Security wise)
const env = validation.parse(process.env);
// return the function we will run at the end of the job
return async (libName: string, stars: number) => {
console.log(`Running provider ${name}`);
await run(libName, stars, env as T);
console.log(`Finished running provider ${name}`);
}
}
代码并不多,但可能有点复杂。
我们首先创建一个名为 的新函数registerProvider
。该函数具有一个泛型类型T
,这基本上是我们所需的环境变量。
然后我们还有 4 个参数:
- 名称 - 可以是
Twilio
、Discord
、Slack
或 中的任意一个Resend
。 - 选项 - 目前,一个参数是提供商是否处于活动状态?
- 验证 - 在这里,我们
zod
在 .env 文件中传递所需参数的模式。 - run - 它实际上用于发送通知。请注意,传递给它的参数是库名称、星数以及我们在
validation
然后我们有实际的功能:
首先,我们检查服务提供者是否处于活动状态。如果不是,则发送一个空函数。
然后,我们验证并提取我们在模式中指定的变量。如果变量缺失,zod
则会发送错误,并且不会让应用程序运行。
最后,我们返回一个获取库名称和星星数量并触发通知的函数。
在我们的文件夹中providers
,创建一个名为的新文件providers.ts
并在其中添加以下代码:
export const Providers = [];
稍后,我们将在那里添加所有提供商。
修改 TriggerDev 作业
本文是上一篇关于创建GitHub 星星监视器的文章的延续。
编辑该文件jobs/sync.stars.ts
,在文件底部添加如下代码:
const triggerNotification = client.defineJob({
id: "trigger-notification",
name: "Trigger Notification",
version: "0.0.1",
trigger: invokeTrigger({
schema: z.object({
stars: z.number(),
library: z.string(),
providerNumber: z.number(),
})
}),
run: async (payload, io, ctx) => {
await io.runTask("trigger-notification", async () => {
return Providers[payload.providerNumber](payload.library, payload.stars);
});
}
});
此项工作获取星号、库名称和提供商编号,并从先前定义的提供商触发针对特定提供商的通知。
现在,让我们继续修改,getStars
在函数末尾添加以下代码:
for (let i = 0; i < Providers.length; i++) {
await triggerNotification.invoke(payload.name + '-' + i, {
library: payload.name,
stars: stargazers_count - payload.previousStarCount,
providerNumber: i,
});
}
这将触发每个图书馆的通知。
完整页面代码:
import { cronTrigger, invokeTrigger } from "@trigger.dev/sdk";
import { client } from "@/trigger";
import { prisma } from "../../helper/prisma";
import axios from "axios";
import { z } from "zod";
import {Providers} from "@/providers/providers";
// Your first job
// This Job will be triggered by an event, log a joke to the console, and then wait 5 seconds before logging the punchline.
client.defineJob({
id: "sync-stars",
name: "Sync Stars Daily",
version: "0.0.1",
// Run a cron every day at 23:00 AM
trigger: cronTrigger({
cron: "0 23 * * *",
}),
run: async (payload, io, ctx) => {
const repos = await io.runTask("get-stars", async () => {
// get all libraries and current amount of stars
return await prisma.repository.groupBy({
by: ["name"],
_sum: {
stars: true,
},
});
});
//loop through all repos and invoke the Job that gets the latest stars
for (const repo of repos) {
await getStars.invoke(repo.name, {
name: repo.name,
previousStarCount: repo?._sum?.stars || 0,
});
}
},
});
const getStars = client.defineJob({
id: "get-latest-stars",
name: "Get latest stars",
version: "0.0.1",
// Run a cron every day at 23:00 AM
trigger: invokeTrigger({
schema: z.object({
name: z.string(),
previousStarCount: z.number(),
}),
}),
run: async (payload, io, ctx) => {
const stargazers_count = await io.runTask("get-stars", async () => {
const {data} = await axios.get(`https://api.github.com/repos/${payload.name}`, {
headers: {
authorization: `token ${process.env.TOKEN}`,
},
});
return data.stargazers_count as number;
});
await io.runTask("upsert-stars", async () => {
await prisma.repository.upsert({
where: {
name_day_month_year: {
name: payload.name, month: new Date().getMonth() + 1, year: new Date().getFullYear(), day: new Date().getDate(),
},
}, update: {
stars: stargazers_count - payload.previousStarCount,
}, create: {
name: payload.name, stars: stargazers_count - payload.previousStarCount, month: new Date().getMonth() + 1, year: new Date().getFullYear(), day: new Date().getDate(),
},
});
});
for (let i = 0; i < Providers.length; i++) {
await triggerNotification.invoke(payload.name + '-' + i, {
library: payload.name,
stars: stargazers_count - payload.previousStarCount,
providerNumber: i,
});
}
},
});
const triggerNotification = client.defineJob({
id: "trigger-notification",
name: "Trigger Notification",
version: "0.0.1",
trigger: invokeTrigger({
schema: z.object({
stars: z.number(),
library: z.string(),
providerNumber: z.number(),
})
}),
run: async (payload, io, ctx) => {
await io.runTask("trigger-notification", async () => {
return Providers[payload.providerNumber](payload.library, payload.stars);
});
}
});
现在,有趣的部分🎉
让我们继续创建我们的提供商!
首先创建一个名为providers/lists
1. Discord
创建一个名为的新文件discord.provider.ts
并添加以下代码:
import {object, string} from "zod";
import {registerProvider} from "@/providers/register.provider";
import axios from "axios";
export const DiscordProvider = registerProvider(
"discord",
{active: true},
object({
DISCORD_WEBHOOK_URL: string(),
}),
async (libName, stars, values) => {
await axios.post(values.DISCORD_WEBHOOK_URL, {content: `The library ${libName} has ${stars} new stars!`});
}
);
如您所见,我们正在使用registerProvider
来创建一个名为 DiscordProvider 的新提供程序
- 我们将名称设置为
discord
- 我们将其设置为活跃
- 我们指定我们需要一个名为的环境变量
DISCORD_WEBHOOK_URL
。 - 我们使用 Axios 的简单 post 命令将信息添加到检查中。
要得到DISCORD_WEBHOOK_URL
:
- 前往您的 Discord 服务器
- 点击其中一个频道的编辑
- 前往
Integrations
- 点击
Create Webhook
- 点击创建的 webhook,然后点击
Copy webhook URL
编辑我们.env
的根项目上的文件并添加
SLACK_WEBHOOK_URL=<your copied url>
2. Slack
创建一个名为的新文件slack.provider.ts
并添加以下代码:
import {object, string} from "zod";
import {registerProvider} from "@/providers/register.provider";
import axios from "axios";
export const SlackProvider = registerProvider(
"slack",
{active: true},
object({
SLACK_WEBHOOK_URL: string(),
}),
async (libName, stars, values) => {
await axios.post(values.SLACK_WEBHOOK_URL, {text: `The library ${libName} has ${stars} new stars!`});
}
);
如您所见,我们正在使用registerProvider
来创建一个名为 SlackProvider 的新提供程序
- 我们将名称设置为
slack
- 我们将其设置为活跃
- 我们指定我们需要一个名为的环境变量
SLACK_WEBHOOK_URL
。 - 我们使用 Axios 的简单 post 命令将信息添加到检查中。
要得到SLACK_WEBHOOK_URL
:
- 使用以下 URL 创建一个新的 Slack 应用程序:https://api.slack.com/apps? new_app=1
- 选择第一个选项:“从头开始”
- 输入一个应用程序名称(任意),并在 Slack 中指定您想要添加通知的工作区。点击
Create App
。 - 在“添加特性和功能”中,点击
Incoming hook
- 在激活传入 Webhook 中,将其更改为“开”。
- 点击“将新的 Webhook 添加到工作区”。
- 选择您想要的频道并点击“允许”。
- 复制 webhook URL。
编辑我们.env
的根项目上的文件并添加
SLACK_WEBHOOK_URL=<your copied url>
3. 电子邮件
您可以使用不同类型的电子邮件提供商。例如,我们将使用Resend来发送电子邮件。
为此,让我们在项目上安装重新发送:
npm install resend --save
创建一个名为的新文件resend.provider.ts
并添加以下代码:
import {object, string} from "zod";
import {registerProvider} from "@/providers/register.provider";
import axios from "axios";
import { Resend } from 'resend';
export const ResendProvider = registerProvider(
"resend",
{active: true},
object({
RESEND_API_KEY: string(),
}),
async (libName, stars, values) => {
const resend = new Resend(values.RESEND_API_KEY);
await resend.emails.send({
from: "Eric Allam <eric@trigger.dev>",
to: ['eric@trigger.dev'],
subject: 'New GitHub stars',
html: `The library ${libName} has ${stars} new stars!`,
});
}
);
如您所见,我们正在使用registerProvider
创建一个名为 ResendProvider 的新提供程序
- 我们将名称设置为
resend
- 我们将其设置为活跃
- 我们指定我们需要一个名为的环境变量
RESEND_API_KEY
。 - 我们使用 Resend 库向我们自己发送一封包含新星星数量的电子邮件。
要得到RESEND_API_KEY
:
- 在以下网址创建新帐户:https://resend.com
- 转到
API Keys
或使用此 URL https://resend.com/api-keys - 点击“+ 创建 API 密钥”,添加密钥名称,选择“发送访问权限”,并使用默认的“所有域”。点击“添加”。
- 复制 API 密钥。
编辑我们.env
的根项目上的文件并添加
RESEND_API_KEY=<your API key>
4. 短信
SMS 稍微复杂一些,因为它们需要多个变量。
为此,让我们在项目上安装 Twilio:
npm install twilio --save
创建一个名为的新文件twilio.provider.ts
并添加以下代码:
import {object, string} from "zod";
import {registerProvider} from "@/providers/register.provider";
import axios from "axios";
import client from 'twilio';
export const TwilioProvider = registerProvider(
"twilio",
{active: true},
object({
TWILIO_SID: string(),
TWILIO_AUTH_TOKEN: string(),
TWILIO_FROM_NUMBER: string(),
TWILIO_TO_NUMBER: string(),
}),
async (libName, stars, values) => {
const twilio = client(values.TWILIO_SID, values.TWILIO_AUTH_TOKEN);
await twilio.messages.create({
body: `The library ${libName} has ${stars} new stars!`,
from: values.TWILIO_FROM_NUMBER,
to: values.TWILIO_TO_NUMBER,
});
}
);
如您所见,我们正在使用registerProvider
来创建一个名为 TwilioProvider 的新提供程序
- 我们将名称设置为
twilio
- 我们将其设置为活跃
- 我们指定需要的环境变量:
TWILIO_SID
、、和TWILIO_AUTH_TOKEN
TWILIO_FROM_NUMBER
TWILIO_TO_NUMBER
- 我们使用 Twilio
create
功能发送短信。
得到TWILIO_SID
、和TWILIO_AUTH_TOKEN
TWILIO_FROM_NUMBER
TWILIO_TO_NUMBER
- 在https://twilio.com创建新帐户
- 标记您想使用它来发送短信。
- 点击“获取电话号码”
- 复制“帐户 SID”、“授权令牌”和“我的 Twilio 电话号码”
编辑我们.env
的根项目上的文件并添加
TWILIO_SID=<your SID key>
TWILIO_AUTH_TOKEN=<your AUTH TOKEN key>
TWILIO_FROM_NUMBER=<your FROM number>
TWILIO_TO_NUMBER=<your TO number>
创建新的提供商
如您所见,现在创建提供程序非常容易。
您还可以使用开源社区来创建新的提供商,因为他们只需要在providers/list
目录中创建一个新文件。
最后要做的是编辑您的providers.ts
文件并添加所有提供商。
import {DiscordProvider} from "@/providers/list/discord.provider";
import {ResendProvider} from "@/providers/list/resend.provider";
import {SlackProvider} from "@/providers/list/slack.provider";
import {TwilioProvider} from "@/providers/list/twilio.provider";
export const Providers = [
DiscordProvider,
ResendProvider,
SlackProvider,
TwilioProvider,
];
随意创建更多推送通知、网络推送通知、应用内通知等提供程序。
你就完成了🥳
让我们联系吧!🔌
作为开源开发者,我们诚邀您加入我们的 社区 ,贡献力量并与维护人员互动。欢迎访问我们的 GitHub 代码库 ,贡献代码并创建与 Trigger.dev 相关的问题。
本教程的源代码可以在这里找到:
https://github.com/triggerdotdev/blog/tree/main/stars-monitor-notifications
感谢您的阅读!
文章来源:https://dev.to/triggerdotdev/top-4-ways-to-send-notifications-about-new-stars-1cgb