BETA

ファイルが更新されたらメールで教えてくれる助手を作ってみた(nodemon)

投稿日:2019-12-10
最終更新:2019-12-10

はじめに

家のPCで”あるパラメータ”を探していて、日中は講義やら研究室やらにこもってしまうので、その間に家のPCがパラメータを探し終えたかどうかそわそわして中々集中できませんでした。

そこで、パラメータが見つかり次第ファイルを更新するので、そのファイルが更新されたらメールで教えてくれる助手を作ってみました。

大体の流れ

上で説明しているように、ファイル更新をトリガーにしてメールを送信するのを目的としています。また外出時にもファイルの中身が見れるように、メール送信時にファイルをクラウド上にあげてもらいます。

使用したツール当

使用したツール等を簡単に説明します。

1. nodemon (公式: https://nodemon.io/)

以前も紹介しました (以前: ホットリロードで毎回ビルドする方法(nodemon))。
簡単に言うと、フォルダを監視して変更され次第コマンドを叩いてくれます。

今回はこれを監視役として使います。

2. fs

これはJS(TS)のファイルを操作するライブラリです。フォルダの中のファイルを拾ってもらいます。

3. Firebase (Cloud Storage)

更新されたファイルの転送先のクラウドストレージです。選んだ理由としては、個人的に慣れていたからです。今回はストレージのみを使用します。

4. nodemailer

Gmailを送信するためのライブラリです。非常に楽に送信できたので助かりました。

ディレクトリ構成とソースコード

実装したコード等を具体的に紹介しますが、firebaseのconfigファイル等のファイルは見せられないので、Githubには公開していません。

ディレクトリ構成

|  
|--node_modules  
|--src  
|  |--utils  
|  |  |--firebase.ts  
|  |  |--config.json  
|  |  
|  |--assistant.ts  
|  |--getFile.ts  
|  |--mailer.ts  
|  |--uploader.ts  
|--nodemon.json  
|--package.json   

各コードを紹介していきます。

firebase.ts

firebaseのCloud Storageにアクセスする為のtsファイルです。storageBucketに自分のCloudStorageのフォルダパスを入力します

import * as firebase from 'firebase-admin'  

const serviceAccount = require('./config.json')  

firebase.initializeApp({  
  credential: firebase.credential.cert(serviceAccount),  
  storageBucket: 'XXXXXXXXXX.appspot.com'  
})  

export const bucket = firebase.storage().bucket()  

getFile.ts

対称のディレクトリにあるファイル名を全て取得してくれるtsファイルです。
取得したいファイル(例:.txtのみにしたい等)が具体的に決まっている場合はここでフィルターをかけるといいかもしれません。

import * as fs from 'fs'  

export const getFileList = (folderPath: string) => {  
  let fileList: string[] = []  
  fileList = fs.readdirSync(folderPath)  
  fileList = fileList.map(file => folderPath + file)  
  return fileList  
}  

mailer.ts

メールタイトルと本文を入力するだけでメールを送信してくれるtsファイルです。
sender側のアカウントにここでログインしているので、アカウントの「安全性の低いアプリのアクセス」をオンにしておく必要があります。

import * as mailer from 'nodemailer'  

const senderEmail = '[email protected]'  
const senderPass = 'SENDERPASS'  
const receiverEmail = '[email protected]'  

const smtpConfig = {  
  host: 'smtp.gmail.com',  
  port: 465,  
  secure: true,  
  auth: {  
    user: senderEmail,  
    pass: senderPass  
  }  
}  

export const mailSend = (title: string, text: string) => {  
  const smtp = mailer.createTransport(smtpConfig)  
  const mailOptions = {  
    from: senderEmail,  
    to: receiverEmail,  
    subject: title,  
    html: text  
  }  

  smtp.sendMail(mailOptions, (err, info) => {  
    if (err) {  
      console.log(err)  
    } else {  
      console.log(`Message sent: ${mailOptions.subject}`)  
    }  
    smtp.close()  
  })  
}  

uploader.ts

さっき設定したCloud Storageに保存するtsファイルです。アップロードするファイルパスを送るだけで送ってくれます。

import { bucket } from './utils/firebase'  

export const uploadFile = (filePath: string) => {  
  try {  
    bucket.upload(filePath)  
    console.log('The file was updated successfully')  
  } catch (err) {  
    console.log(err)  
  }  
}  

assistant.ts

全体の処理をしてくれるメインファイルです。gmailには簡単なHTMLが埋め込めるとの事なので、アップロードしたファイルをリスト形式<li>でおくってます。

import { mailSend } from './mailer'  
import { getFileList } from './getFile'  
import { uploadFile } from './uploader'  

const message = (fileList: string[]) => {  
  const filesText = fileList.map(file => {  
    return `<li>${file}</li>`  
  })  

  return `  
    <h1>ファイル更新されました</h1>  
    <h3>以下のファイルが更新されました。https://console.firebase.google.com/u/0/project/XXXXXXXXXXX/storage/XXXXXXXXXXX.appspot.com/files~2F を確認してください。</h3>  
    <div style="margin: 0.5rem;">  
        ${filesText}  
    </div>  
    `  
}  

const report = () => {  
  // 監視対象のフォルダ  
  const targetFolder = './targetFolder/'  
  // 対称のフォルダにあるファイルを取得  
  const fileList = getFileList(targetFolder)  
  // ファイルを全てCould Storageにアップロード  
  fileList.forEach(file => {  
    console.log({ file })  
    uploadFile(file)  
  })  
  // 完了メールを送る。  
  mailSend('ファイルが更新されました。', message(fileList))  
}  

report()  

report()で対称のフォルダにあるファイルを取得 -> Could Storageにアップロード -> メールを送信をしています。

つまり、監視対象のフォルダが変更され次第このファイルを呼び出せばいいわけですね。

package.json

意外と大事なファイルで、scriptsにコマンドを設定しておくとこの環境元で実行してくれます。

{  
  "name": "myAssistant",  
  "version": "1.0.0",  
  "description": "",  
  "main": "index.js",  
  "scripts": {  
    "report": "ts-node ./src/assistant.ts",  
    "start": "nodemon"  
  },  
  "keywords": [],  
  "author": "",  
  "license": "ISC",  
  "dependencies": {  
    "@types/nodemailer": "^6.2.2",  
    "firebase-admin": "^8.8.0",  
    "nodemailer": "^6.3.1",  
    "nodemon": "^2.0.1",  
    "ts-node": "^8.5.4",  
    "typescript": "^3.7.2"  
  }  
}  

scriptsを見るとわかりますが、reportでさっきのassistant.tsを呼び出して、startnodemonを呼び出すことができるようにしています。

nodemon.json

フォルダーを監視して実行してくれる設定ファイルです。

{  
    "watch": ["./targetFolder/"],  
    "ext": "*",  
    "exec": "npm run report"  
}  

watchに監視対象のフォルダ、execに変更時に実行するコマンドを設定します。

実行例

監視対象フォルダは相対パスでも絶対パスでも可能です。今回はCドライブ直下にtargetというフォルダを作成してやってみます。

./nodemon.jsonassistant.tsの監視対象フォルダに設定している箇所をC:\\target\\に変更します。

そして、コンソールでnodemonを実行します。./package.jsonで設定しているstartを叩きます。

$ npm run start  

するとnodemonでassistant.tsが一度呼び出されます。次に試しに監視対象フォルダであるC:\\target\\に新しくtestfile.txtというファイルを作成すると...

> [email protected] report C:\Users\hogehoge\Documents\workspace\myAssistant  
> ts-node ./src/assistant.ts  

{ file: 'C:\\target\\testfile.txt' }  
The file was updated successfully  
Message sent: ファイルが更新されました。  
[nodemon] clean exit - waiting for changes before restart  

そしてメールが届き

こんなふうに更新されたファイルと保存先のurlまで表示してくれます。

今はファイル作成のときに実行されましたが、もちろんファイル更新時にも実行してくれます。testfile.txtに"END"と文字を入力して保存すると、同様のメールが届きurlにあるCloud Storageを見てみると...

変更が更新されているのが確認できましたので、これで終わります。

さいごに

助手の名前や本文を変えたり、メールではなくLINEにしたり色々楽しめそうではありますが、時間に余裕がないのでこれで満足しておきます...

出力先のディレクトリを一般向けにしてオープンソースとして公開するという方法もありそうですね。

参考

Qiita - Node.jsでGmailを送信 @hanuman6

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@syakooのブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう