iT邦幫忙

2023 iThome 鐵人賽

DAY 24
1

https://ithelp.ithome.com.tw/upload/images/20230917/20119486oXxAz6M18V.png

前言

前一面我們對於伺服器有基本概念後,接下來當然是要實際部署專案到伺服器上囉~

Zeabur

Zeabur 是一個 PaaS 平台,何謂 PaaS 呢?Platform as a service 中文又稱平台即服務。

有點模糊吧?那我舉個例子來講好了,假設你今天要蓋一個房子好了,那你需要什麼呢?當然是地基、水泥、磚頭、木頭等等,更不用說你還需要去設計房子的樣子,這些都是你需要做的事情。

而 PaaS 概念就跟請一個專業的建築公司來蓋一樣,因為這間建築公司本身就有提供相對應得服務,例如:設計、施工、材料等等,你只需要跟他們說你要蓋什麼樣的房子,他們就會幫你蓋好,這就是 PaaS 的概念。

所以以這個概念來講,你代表著開發者,而建築公司則代表著PaaS 平台,而房子則代表著專案,你只需要專注於專案的開發,而不需要去擔心伺服器的問題,這就是 PaaS 的好處。

常見的 PaaS 平台非常多,例如...先前轉成收費的 Heroku 就是一個 PaaS 平台,因此我們不用過度的去擔心伺服器的問題,只需要註冊帳號、建立專案、部屬專案就好了,非常的方便呢!

而 PaaS 平台核心理念在於抽象化你原有在伺服器上複雜管理工作,讓你可以更專注於專案上的開發,因此對於新手、小白等開發者,其實是非常的方便的。

Note
當然,也有所謂的 Iass(Infrastructure as a Service)與 SaaS(Software as a Service),但這兩個東西就不是我們這邊要講的了,有興趣的話可以自行去查詢看看。

那麼為什麼我會選擇 Zeabur 呢?因為 Zeabur 是台灣的 PaaS 平台,當然要支持一下本土的平台,而且 Zeabur 也有提供免費的方案(每個月 5 美金),更不用說非常的方便,所以我們就來使用 Zeabur 來部屬我們的專案吧!

部署

接下來我會全程一步一步帶著你將前一篇的專案部屬到 Zeabur 上,當然你也可以自己先試試看,如果有問題的話再回來看看這篇文章。

首先底下我提供相對應的指令以及預期要部署的程式碼,確保你我之間的程式碼是一致的,這樣才能夠順利的部屬。

mkdir example-discord-bot-crawler
cd example-discord-bot-crawler
npm init -y
touch index.js
touch register.js
touch crawler.js
touch postCron.js
touch .env
npm i discord.js cheerio dotenv cron

.env:

// .env
# .env
DISCORD_TOKEN=
DISCORD_CLIENT_ID=
DISCORD_CHANNEL_ID=

index.js:

// index.js
require('dotenv').config();

const crawler = require('./crawler');
const postCron = require('./postCron');

const {
  Client,
  GatewayIntentBits,
  Partials,
  Events,
} = require('discord.js');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
  partials: [
    Partials.Channel,
  ],
});

client.once(Events.ClientReady, () => {
  console.log('Ready!');
  postCron(client).start();
});

client.on(Events.InteractionCreate, async (interaction) => {
  if (interaction.commandName === 'blog') {
    const data = await crawler();
    const randomIndex = Math.floor(Math.random() * data.length);
    const randomData = data[randomIndex];
    await interaction.reply(`隨機推薦一篇 Ray 的文章:[${randomData.title}](${randomData.url})`);
  }
});

client.login(process.env.DISCORD_TOKEN);

postCron.js:

// postCron.js
const cron = require('cron');

const crawler = require('./crawler'); // 引入爬蟲程式碼

const postCron = (client) => {
  const job = new cron.CronJob('* * * * *', async () => {
    // 呼叫爬蟲程式碼,並取得資料
    const data = await crawler();
    // 依據資料長度隨機產生一個索引值
    const randomIndex = Math.floor(Math.random() * data.length);
    // 依照隨機產生的索引值取得資料
    const randomData = data[randomIndex];
    // 取得頻道
    const channel = client.channels.cache.get(process.env.DISCORD_CHANNEL_ID);
    // // 發送訊息
    await channel.send(`每日晚間九點隨機推薦 Ray 的一篇文章:[${randomData.title}](${randomData.url})`);
  });
  
  return job;
}


module.exports = postCron;

crawler.js:

// crawler.js
const cheerio = require('cheerio');

const getData = async (url) => {
  try {
    const response = await fetch(url);
    const data = await response.text();
    return data;
  } catch (error) {
    console.log(error);
  }
}

const crawler = async () => {
  const target = 'https://israynotarray.com/'; // 目標網址
  const html = await getData(target);

  const $ = cheerio.load(html);

  const postTitleLink = $('.post-title-link');

  const data = [];

  postTitleLink.each((index, element) => {
    const title = $(element).text();
    const url = $(element).attr('href');
    data.push({
      title,
      url: `${target}${url}`, // 補上網域
    });
  });

  return data;
}

module.exports = crawler;

register.js:

// register.js
require('dotenv').config(); // 引入 dotenv

const {
  REST,
  Routes
} = require('discord.js');

const list = [
  {
    name: 'blog',
    description: '取得首頁第一頁隨機文章',
  },
];

const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);

const registerCommands = async (commands) => {
  try {
    console.log('Started refreshing application (/) commands.');

    await rest.put(Routes.applicationCommands(process.env.DISCORD_CLIENT_ID), { body: commands });

    console.log('Successfully reloaded application (/) commands.');
  } catch (error) {
    console.error(error);
  }
}

registerCommands(list)

最後有一件事情很重要,你必須要修改一下 package.json,增加 "start" 的指令,因為 Zeabur 會依照這個指令來啟動專案,所以你必須要增加這個指令。

{
  "name": "example-discord-crawler",
  // ... 略過其他程式碼
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  // ... 略過其他程式碼
}

接下來請你將此專案部署到 GitHub Repositories 上,因為 Zeabur 會需要你的 GitHub Repositories 來部屬專案,所以請先將專案部署到 GitHub Repositories 上,這個部署過程我就不額外說明了,除此之外 Zeabur 也是使用 GitHub 註冊並登入的,所以 GitHub 你是必須要有的。

Note
如果你是第一次使用 GitHub 的話,你可以參考我這一篇「使用 SSH 連接/上傳到你的 GitHub(Ed25519)」來設定,並挑戰嘗試將專案部署到 GitHub Repositories 上

這邊也提醒一下,請不要將 .env 上傳到 GitHub Repositories 上,因為裡面包含了你的 Discord Token,如果上傳到 GitHub Repositories 上,那麼你的 Discord Token 就會被公開,這樣的話你的 Discord Bot 就會被其他人操控,所以請務必記得將 .env 加入到 .gitignore 中。

接下來我們就來到 Zeabur 這個平台,由於 Zeabur 是使用 GitHub 註冊並登入的

https://dash.zeabur.com/login

所以你可以直接使用 GitHub 登入

https://ithelp.ithome.com.tw/upload/images/20230917/20119486GebV8azhGZ.png

登入成功後,你會直接進入到 Zeabur 的控制台,接下來你可以點擊畫面上的「建立專案」按鈕來建立專案

https://ithelp.ithome.com.tw/upload/images/20230917/20119486E0iYfLOrSD.png

接下來你會需要選擇專案的地區,這邊我們就選「Taiwan」(題外話:Zeabur 主機位於 GCP 台灣機房)

https://ithelp.ithome.com.tw/upload/images/20230917/20119486AfrX46YcQk.png

接著你就可以看到剛剛建立的專案

https://ithelp.ithome.com.tw/upload/images/20230917/20119486WWS7Y2jizl.png

點一下它就可以看到這個專案的資訊,先讓我用一張圖介紹說明一下:

https://ithelp.ithome.com.tw/upload/images/20230917/20119486TV1UOU6GsQ.jpg

專案設定方面我就不特別介紹了,讓你自行點進去摸索就好。

那麼我們就先來部署自己的服務(專案),點一下建立服務,你會看到 Git、Marketplace 這兩個選項,這邊我們選 Git,因為我們要部署 GitHub 上的專案

https://ithelp.ithome.com.tw/upload/images/20230917/20119486f2xBo8iCFC.png

接著選擇你要部署的專案就可以了

https://ithelp.ithome.com.tw/upload/images/20230917/20119486JlspbqkTji.jpg

整個部署過程大概需要 1~2 分鐘

https://ithelp.ithome.com.tw/upload/images/20230917/20119486OfgAOOofrE.png

你可以點擊「Log」來查看部署的過程

https://ithelp.ithome.com.tw/upload/images/20230917/20119486BfD2dYO5XV.png

https://ithelp.ithome.com.tw/upload/images/20230917/20119486XPVGMEX17R.jpg

不意外,你應該會發現 Log 出現錯誤

https://ithelp.ithome.com.tw/upload/images/20230917/20119486vjE0gi5rDO.png

因為我們並沒有填寫 Env 的關係,回到專案主控台下方有一個環境變數,點一下編輯環境變數,你就可以無痛把 .env 的內容直接貼上囉!

https://ithelp.ithome.com.tw/upload/images/20230917/20119486nyxlTqOpXT.jpg

儲存後,按一下專案的 ReDeploy 就可以恢復正常哩~

ReDeploy

接著你回到 Discord 上面,應該就會看到你的 Discord Bot 已經上線了,而且你也可以嘗試輸入 /blog 來測試看看,應該就會看到你的 Discord Bot 回覆你一篇文章囉!

關於自動註冊指令

最後也補充一個點一下,也就是關於註冊指令的部分,我們前面有新增一個檔案叫做 register.js,這個檔案的用途就是用來註冊指令的,那麼為了確保指令是最新的,我們可以透過 npm scripts 的指令來註冊指令,這樣就不用每次都要手動註冊指令囉~

{
  "name": "example-discord-crawler",
  // ... 略過其他程式碼
  "scripts": {
    "postinstall": "node register.js",
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1",
    "register": "node register.js"
  },
  // ... 略過其他程式碼
}

其他服務

當然還有很多服務可以使用,例如我先前介紹過的...

之前也有寫過 Zeabur 的文章

這幾個我試用下來,我個人是滿推薦使用 Zeabur 的,雖然只能建立一個專案,但一個專案內是可以部署相當多的服務的,更不用說又有免費的五美金額度可以使用,更不用說官方文件其實非常齊全且相關人員都會第一時間盡可能協助解決問題,所以基本上是非常推薦的。

----- 底下是業配開始線 -----

那麼如果你覺得試用下來相當不錯的話,你可以再付費時填寫我的兌換碼:

israynotarray

你可以免費獲得一個月的開發者方案唷!

而 Zeabur 的計費方式你可以參考他們官方文件:

收費方式

----- 以上業配結束線 -----

那麼這一篇也差不多了,我們下一篇見哩~


上一篇
Day23 - 關於伺服器
下一篇
Day25-Google Extension
系列文
《Node.js 不負責系列:把前端人員當作後端來用,就算是前端也能嘗試寫的後端~原來 Node.js 可以做這麼多事~》31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言