在上一篇文章中,我討論了建立一個GitHub stars 監視器。
在這篇文章中,我想向您展示如何每天了解新星的資訊。
我們將學習:
如何建立通用系統來建立和使用提供者。
如何使用提供者發送通知。
使用不同提供者的不同用例。
Trigger.dev 是一個開源程式庫,可讓您使用 NextJS、Remix、Astro 等為您的應用程式建立和監控長時間執行的作業!
請幫我們一顆星🥹。
這將幫助我們建立更多這樣的文章💖
https://github.com/triggerdotdev/trigger.dev
我們將建立不同的提供者來通知我們何時有新的明星。我們將設定「電子郵件」、「簡訊」、「Slack」和「Discord」通知。
我們的目標是讓每個貢獻者都足夠簡單,以便在未來貢獻更多的提供者。
每個提供者都會有一組不同的參數,有些只有“API 金鑰”,有些則有電話號碼,具體取決於提供者。
為了驗證這些金鑰,讓我們安裝“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」中的任何一個。
選項 - 目前,一個參數是提供者是否處於活動狀態?
驗證 - 在這裡,我們在 .env 檔案中傳遞所需參數的「zod」模式。
run - 實際上用於發送通知。請注意,傳入其中的參數是庫名稱、星星數量以及我們在「validation」中指定的環境變數
然後我們就有了實際的功能:
首先,我們檢查提供者是否處於活動狀態。如果沒有,我們發送一個空函數。
然後,我們驗證並提取我們在模式中指定的變數。如果變數缺少 zod
將發送錯誤並且不會讓應用程式執行。
最後,我們傳回一個函數,該函數會取得庫名稱和星星數量並觸發通知。
在我們的「providers」資料夾中,建立一個名為「providers.ts」的新文件,並在其中新增以下程式碼:
export const Providers = [];
稍後,我們將在那裡加入所有提供者。
本文是上一篇關於建立 GitHub stars 監視器。
編輯檔案 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」的新資料夾
建立一個名為「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 伺服器
點選其中一個頻道的“編輯”
轉到“整合”
點選“建立 Webhook”
點選建立的 webhook,然後點選“複製 webhook URL”
在根專案上編輯“.env”檔案並加入
SLACK_WEBHOOK_URL=<your copied url>
建立一個名為「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 工作區。點擊“建立應用程式”。
在“新增特性和功能”中,按一下“傳入掛鉤”
在啟動傳入 Webhooks 中,將其變更為「開啟」。
按一下「將新 Webhook 新增至工作區」。
選擇您想要的頻道並點選「允許」。
複製 Webhook URL。
在根專案上編輯“.env”檔案並加入
SLACK_WEBHOOK_URL=<your copied url>
您可以使用不同類型的電子郵件提供者。例如,我們將使用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 <[email protected]>",
to: ['[email protected]'],
subject: 'New GitHub stars',
html: `The library ${libName} has ${stars} new stars!`,
});
}
);
如您所見,我們正在使用 registerProvider
建立一個名為 ResendProvider 的新提供程序
我們將名稱設定為“重新發送”
我們將其設定為活動狀態
我們指定需要一個名為「RESEND_API_KEY」的環境變數。
我們使用重新發送庫向自己發送一封包含新星數的電子郵件。
若要取得“RESEND_API_KEY”:
建立一個新帳戶:https://resend.com
前往「API 金鑰」或使用此 URL https://resend.com/api-keys
按一下“+ 建立 API 金鑰”,新增金鑰名稱,選擇“傳送存取”並使用預設的“所有網域”。單擊新增。
複製 API 金鑰。
在根專案上編輯“.env”檔案並加入
RESEND_API_KEY=<your API key>
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「建立」功能發送簡訊。
取得“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