簡介

在上一篇文章中,我討論了建立一個GitHub stars 監視器。

在這篇文章中,我想向您展示如何每天了解新星的資訊。

我們將學習:

  • 如何建立通用系統來建立和使用提供者。

  • 如何使用提供者發送通知。

  • 使用不同提供者的不同用例。

通知


你的後台工作平台🔌

Trigger.dev 是一個開源程式庫,可讓您使用 NextJS、Remix、Astro 等為您的應用程式建立和監控長時間執行的作業!

 

GiveUsStars

請幫我們一顆星🥹。

這將幫助我們建立更多這樣的文章💖

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 = [];

稍後,我們將在那裡加入所有提供者。


修改 TriggerDev 作業

本文是上一篇關於建立 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」的新資料夾


1. Discord

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”:

  1. 前往您的 Discord 伺服器

  2. 點選其中一個頻道的“編輯”

  3. 轉到“整合”

  4. 點選“建立 Webhook”

  5. 點選建立的 webhook,然後點選“複製 webhook URL”

在根專案上編輯“.env”檔案並加入

SLACK_WEBHOOK_URL=<your copied url>

Spidy


2. Slack

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”:

  1. 使用下列 URL 建立新的 Slack 應用程式:https://api.slack.com/apps?new_app=1

  2. 選擇第一個選項:“從頭開始”

  3. 指定應用程式名稱(任意)以及您想要新增通知的 Slack 工作區。點擊“建立應用程式”。

  4. 在“新增特性和功能”中,按一下“傳入掛鉤”

  5. 在啟動傳入 Webhooks 中,將其變更為「開啟」。

  6. 按一下「將新 Webhook 新增至工作區」。

  7. 選擇您想要的頻道並點選「允許」。

  8. 複製 Webhook URL。

在根專案上編輯“.env”檔案並加入

SLACK_WEBHOOK_URL=<your copied url>

SlackBot


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 <[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”:

  1. 建立一個新帳戶:https://resend.com

  2. 前往「API 金鑰」或使用此 URL https://resend.com/api-keys

  3. 按一下“+ 建立 API 金鑰”,新增金鑰名稱,選擇“傳送存取”並使用預設的“所有網域”。單擊新增。

  4. 複製 API 金鑰。

在根專案上編輯“.env”檔案並加入

RESEND_API_KEY=<your API key>

埃里克·阿拉姆


4.簡訊

Twilio

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”

  1. 在 https://twilio.com 建立一個新帳戶

  2. 標記您要使用它來發送簡訊。

  3. 點選“取得電話號碼”

  4. 複製“帳戶 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>

TwilioSMS


建立新的提供者

正如您所看到的,現在建立提供者非常容易。

您也可以使用開源社群來建立新的提供程序,因為他們只需要在「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


共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。