Google Cloud FunctionsでパスワードPDFを作る【GAS】

前回の記事で、Google Apps ScriptからGoogle Cloud Storageへのファイルのアップロードを実現しました。しかし、目的はパスワード付PDFを作ること。そのためにはまだいくつものハードルがあります。

今考えているのは、スプレッドシートのID、Access Token、設定パスワードをなげて、Google Cloud Functions上 の関数でPDFを生成。そのPDFを続けて、パスワード付PDFに変換し、Google Cloud Storageに格納。それをGAS側へ返却するというプランです。今回はその中間である、「Cloud StorageにあるPDFをパスワード付PDFにして、Cloud Storageに格納する」という処理を、Cloud Functionsで実装してみました。

事前準備

Cloud Storage

今回の処理で必要な手順は以下の通り。

  1. Cloud Storage(バケットの名前は、drive2gcsにしておきました)に、フォルダ(publicという名前にしました)を作成する
  2. 1.のフォルダの中に、テスト用のPDFを1個だけアップロードします(test.pdfという名前ににしました)。

Cloud Storage側はこれだけです。

Cloud Functions

Cloud Functions側の準備もシンプルです。事前にサービスアカウントの作成が必要ですので、作成をしておきましょう。前回の記事で作成について触れています。もちろん請求先アカウントの設定も必要です。

  1. 関数を作成する
  2. 割当メモリは512MB、トリガーはHTTPとしました。ランタイムはNode.js V8を選んでいます。
  3. リージョンは、デフォルトのus-central1にしてあります。
  4. 関数名は、encryptPDFという名前にしました。しかし、実際に呼び出す関数はコードの中にある「passpdf」になりますので、注意。
  5. Cloud Functions上では、npmでインストールではなく、package.jsonに記述すると裏でモジュールを用意してくれます。ですので、以下のような記述を追加しました。追加モジュールは2個です。
  6. hummus-recipeは、PDFをパスワード付にするだけでなく、様々な加工のできるスグレモノです。
  7. google-cloud/storageは、Google作成のNode.jsからCloud Storageへのアクセスを容易にするモジュールです。
  8. 実行する関数名は、passpdfとして設定しました。
{
  "name": "sample-http",
  "version": "0.0.1",
  "dependencies": {
    "hummus-recipe": "^1.8.9",
    "@google-cloud/storage": "^2.5.0"
  }
}

コード:package.jsonには以上のような記述を追加

Cloud Functionsの仕様と料金

Cloud Functionsでは、一時的に利用するディレクトリとして、/tmpが用意されています。また、料金はCloud Storageに加えて、こちらの料金表が適用されます。但し月間呼び出し回数が200万回以下の場合には、無料で利用できます。お得ですね。コンピューティング時間による金額は請求されますが、今回の設定ですと、100ms = $0.000000925となっています。

/tmpのサイズは自分で設定したメモリサイズの中から利用されます。あまり大量に生成すると、メモリが枯渇しますので注意が必要なのと、少ないリソースで設定してしまうと、関数の実行も遅くなってしまうので、注意。

実行中のデバッグやログは、Stack Driver Loggingが利用されます。

コードと実行

ソースコード

メイン画面の編集をクリックするとソースコードなどを編集可能です。インラインエディタ以外にも、ファイルをアップロードで環境を作ることも可能です。

今回これでCloud Functions側の実装が完了したので、GAS側から受け付ける為の改造を追加して完了になりますが、まだハードルが少しある(このままでは、最低3回はGAS側でUrlfetchAppを実行しなければならないので、これを1回で済ますようにするには、まだロジックが必要)。

//標準モジュールの読み込み
var fs = require('fs');

//追加モジュールの読み込み
const HummusRecipe = require('hummus-recipe');
const {Storage} = require('@google-cloud/storage');

//バケットとtmpフォルダの指定
const gcs = new Storage();
const bucket = gcs.bucket('drive2gcs');
const tempFilePath = "/tmp/"

//呼び出す関数の設定
exports.passpdf = (req, res) => {
  //GCSのファイル読み込み
  var file = bucket.file("/public/test.pdf");

  new Promise(function(resolve, reject) {
    //ファイルダウンロード
    file.download({
      destination: tempFilePath + "test2.pdf"
    }).then(()=>{
      resolve("OK");
    });

  }).then((result) => {
    //ダウンロード完了
    console.log(result);
    
    //パスワード化を実施する
     passwordpdf(function (ret){
    	//パスワード化完了
        console.log(ret);
        
       //GCSへアップロードする
       var options = {
          destination: "/public/output.pdf"
       };
       
       bucket.upload(tempFilePath + "output.pdf", options, function(err, file) {
            console.log("File Uploaded");
       }).then(()=>{
       		return;
       });
     });
  }).then((result) => {
       //ファイルサイズを取得する
       var stat = fs.statSync(tempFilePath + "output.pdf");
       console.log(stat.size + "バイト");
       let message = req.query.message || req.body.message || stat.size + "バイト";
       res.status(200).send(message);  
  });
}

//PDFにパスワード化を実施する
function passwordpdf(callback){
    const pdfDoc = new HummusRecipe(tempFilePath + "test2.pdf", tempFilePath + "output.pdf");

    var ret = pdfDoc.encrypt({
                        userPassword: '123',
                        ownerPassword: '123',
                        userProtectionFlag: 4
                    }).endPDF(function(ret){
            //5秒間スリープを入れる
                        sleep(5000, function() {
                            callback("Encryption End");
                        });
                    });
}

//sleep関数
function sleep(waitSec, callback) {
    setTimeout(callback, waitSec);
}
  • 冒頭でバケットやtmpなどの指定を行っておきます。
  • 実際にパスワードPDFを作成するのはpasswordpdf関数になります。
  • passpdf関数がメインの関数となり、これを呼び出します。
  • GCSからファイルをtmpフォルダにダウンロード、パスワード付与、アップロード、ファイルサイズ取得までが一連の流れです。
  • ダウンロードした時のファイル名は、test2.pdfという名称にしています。
  • Node.jsですのでそのまま記述してしまうと、非同期に進んでしまいますので、Promiseで同期的に実行させる必要があります。
  • また、PDF生成時に5秒間のsleepを入れています。時々生成前にPDFのアップロードまで進んでしまう事があったので、そのための処置です。
  • pdfDoc.encryptメソッドにてパスワードを付与しています。ここで設定したパスが開くときのパスワードになります。
  • Bufferではなくローカル(tmp以下のフォルダ内)のファイルへアクセスが必要なので、HummusRecipeの引数では、ダウンロードしたファイルパスと出力時のファイルパスを入れてます。
  • output.pdfとしてパスワード付PDFがtmpに作成されます。
  • bucket.uploadにて作成したPDFファイルをGCSにアップロードさせています。

図:メインの編集画面

実行してみる

コードを記述したら、

  1. メイン画面の一番下にある「デプロイ」をクリックする
  2. モジュールの準備やコードの精査などが開始されます。問題がある場合にはエラー表示がなされ、ログはStackDriver Loggingに記録されています。
  3. 完全に完了すると、待機する状態になります。
  4. 完全に完了したら、トリガーをクリックし、URLが表示されるのでクリックすると作動します。
  5. 今回のプログラムでは、最後にPDFのファイルサイズを返しています(毎回ちょっとずつ、ファイルサイズが違うけれど、きちんと開けています)。
  6. きちんと実行が完了すると、GCS側のバケット内にoutput.pdfが生成されます(少し時間差があります)。

図:実行したらきちんとファイルがアップされてました。

図:きちんとパスワード付きになってるのを確認

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)