ElectronでMySQLへ接続するアプリを作る

個人利用のアプリであるならば、データの保管場所はsqliteなどで良いかと思います。しかし、複数名共有して使うデータベースの場合には、やはりMySQLなどのDBサーバが必要になります。中央集権なこのDBがあることで、様々な社内ツールをElectronで実現する事ができます。

相手のサーバにWeb Serverがなくとも、Electron側がそれを担うので、非常に単純な構成でちょっとしたウェブアプリケーション的なクラサバ構築できるのは魅力的です。VBA卒業して挑戦するならElectronは良い選択肢だと思います。ウェブアプリと同じUI表現が利用できますし。

今回は、MySQL接続に加えて、DB接続パスワードなどを安全に格納できるように、keytarモジュールを利用してOS標準のキーストアを使ったセキュリティ対策も実施しておこうと思います。

図:今回作るアプリはこんな感じです

目次

今回使用するモジュール他

Node.jsモジュール

  • keytarモジュール - OS標準のパスワード管理システムを利用して、安全にパスワード等のやり取りをする
  • electron-store - 各種設定情報を格納する為のモジュール
  • Promise-MySQLモジュール - Promiseが使えるMySQLへアクセスする為のモジュール
  • jQueryモジュール - ElectronでjQueryを使えるようにする為のモジュール
  • node-gyp - keytarモジュールをリビルドする為に使用する

HTML側で利用するライブラリ

使用するDBファイルとプロジェクトファイル

また、今回のサンプルアプリで用いたファイル類は以下からダウンロードできます。今回はローカル仮想環境内のMySQLを利用しましたが、Google Cloud SQLへ接続して利用も可能です。Cloud SQLの場合一旦、Cloud Storageにバケットを作成して、SQLファイルを配置しなければ、インポートが出来ないので注意(GB/月あたりの価格: $0.023)。なぜか1回目はインポート失敗するけれど、2回目は成功します。

図:Cloud StorageのバケットからSQLファイルインポート中

図:Cloud SQLにインポートしてみた

事前準備

モジュールを追加する

まずは、プロジェクトファイル作成、package.json作成、index.htmlおよびindex.jsを作成して置きます。ターミナルを起動して以下のコマンドで今回利用する予定のモジュールを入れておきましょう。

promise、promise-mysql、keytarの3つを追加しました。node-gypは最新版からは標準搭載されているので、別途導入不要です。

また、モジュールを追加時に以下のようなエラーに遭遇した場合には、いちどnpm cache clean --forceを実施してキャッシュをお掃除してから再度チャレンジすると良いでしょう。(Unexpected end of JSON input while parsing near)

プロキシーに阻まれて追加できない時

社内でnpmでモジュールを追加する時に、プロキシーに阻まれて(getaddrinfo ENOTFOUNDというエラーがでます)追加できない場合があります。その場合には以下の手順でnpmに対してProxyのセッティングを通しておくと追加が可能です。アドレスはお使いのプロキシーのURLを入力します。

  1. npm config set proxy http://proxy.example.com:8080 を実行する
  2. npm config set https-proxy http://proxy.example.com:8080 を実行する
  3. npm config set registry https://registry.npmjs.org/ を実行する

また、3.にてhttpで追加をしてしまうと、418 I'm a teapot:エラーが出てしまいますので注意が必要です。

keytarについて

最新の環境でのKeytar対応について

2021年3月現在、keytarがネイティブ対応して、以下のようなとっても面倒なkeytarのリビルドが不要になりました。普通にnpm i keytarでインストールすることでリビルドする事なく、そのまま利用可能になっています。

最新のNode.jsとElectron環境でkeytarを動かしてみるテスト

keytarの概要と使い方

現代のOSには、OS標準のパスワード管理の為のセキュリティシステムが用意されています。macOSで言えば「keychain」、Linuxならば「libsecret」や「Gnome Keyring」、Windowsですと「Credential Vault(資格情報マネージャ)」がそれになります、keytarはElectronでセンシティブな情報を扱う場合に、ローカルストレージではなく、こうした管理システムへの情報の登録と呼び出しをサポートする為のモジュールです。

接続パスワードの保管や、OAuth2認証で使うClient_IDとSecretの格納、Access_TokenやRefresh_Tokenの格納などを安全に格納する事が可能で、この手のアプリケーションを作る上では必須とも言える機能ですね。

メソッドもえらくシンプルで

が基本。他に削除、検索のコマンドがあります。但しパスワードの取得だけは少しだけコードが異なります。非同期処理なので、注意してください。

もしくはIPC通信を利用して

といった取り出し方をすると良いでしょう。

Linuxに於けるKeytarの問題点

まだ、Linux上でElectronのビルドを試してはいないのですが、少なくともNode.jsアプリとして、Ubuntu 18.04上でkeytarモジュールを動かす為には、以下のライブラリをインストールしておかなければなりません。

macOSに於けるkeytarの問題点

また、環境によってはそのままだと動かないことがあるので、keytarモジュールをリビルドする必要があります。表示されるエラーは以下のような感じ。electron v4.0.3, keytar 4.3.1でテストしています。

この問題は、素で入れたkeytarがelectronのバージョンに合っていない為に起こる問題で以下のような形でリビルドをすると、osxであれば無事にキーチェーンに資格情報が格納されます。

  1. electronのバージョンを、electron -vで調べておく
  2. 使用している環境が32bit環境下?64bit環境かしらべておく。通常今どきは64bitだと思うので、x64だと思います。
  3. ターミナルを立ち上げて、プロジェクトフォルダの中のnode-modulesフォルダ、さらに其の中のkeytarフォルダに入ります。
  4. 以下のコマンドを実行する(electronのバージョンは4.0.2で、アーキテクチャはx64で指定しています。)

electronで実際にリファレンスに従い、setPasswordをしてみたところキーチェーンに無事に資格情報が格納されました。getPasswordで取り出す事が可能です。

図:keytarをリビルド中

図:zasekiというサービス名にアカウント名とパスワードが格納される

Windowsでkeytarを使う場合

macOSの場合は前項のようにkeytarモジュールをリビルドするだけで利用する事ができました。しかし、問題はWindows。そもそもリビルドするにもビルド環境が必要だったり、リビルドしても動かずに停止してしまったりと、問題解決が非常に大変でした。すごく良いモジュールなのに、この問題が残念ですね。。。ネイティブモジュール特有の問題です。

2020年3月、electron 5.0.0とkeytar4.6.0でも成功したので、Windowsでビルドする場合には、以下の記事を参照してください。

electron@5.0.0でkeytar@4.6.0をWindowsで使う2020年版

以下の記事は古いバージョンでビルドした記録として残しておきます。

結果的には、electronはv3.0.0keytarは4.2.1を利用し、electron-rebuildを使ってのリビルドで使えるようにはなりました。以下に使えるようにする為の手順を残しておきます。参考になったのは、こちらのサイトと、issue議論のサイトissue議論サイト2node-gypインストール方法サイトでした。また、node-gypについてはpython 2.7系に対応している為、3.x系が入っていると具合が悪いです。また、以下の作業は「管理者権限」で行うようにしましょう。

  1. electronは一旦、npm uninstall -g electronでアンインストールする
  2. keytarも一旦、プロジェクトフォルダに入ってから、npm uninstall keytarでアンインストールする(Windowsでは、keytar v4.3.0は問題有り
  3. npm install -g electron@3.0.0でバージョン指定でインストール
  4. keytarをインストールする前に、管理者権限のPowerShellにてnpm install -g windows-build-toolsを実行して、インストールする(結構時間が掛かる)
  5. Visual C++ Buildtoolsをインストールする(Visual Studio 2017相当)。2015だとエラーが出ます。
  6. npm config set msvs_version 2017コマンドを実行
  7. npm config listで現在の設定値を確認できます。
  8. エクスプローラの検索にて、python.exeがある場所を探しだし、npm config set python python.exeのフルパス コマンドを実行する(パスが通って入れば、python2.7でも可)なお、通常はc:¥Users¥ユーザ名¥.windows-build-tools¥python27以下にpython.exeがインストールされています。
  9. npm install -g node-gypで、node-gypをインストール(但し、Node.js最新のNode.jsは初めからバンドルしてるのでこの作業は不要。入れるとオカシナことになります)。
  10. 一旦再起動する
  11. 実はこの時点ではまだnode-gypはエラーになることがあります。正しいnode-gypへのパスが通っていない(間違ったパスが環境変数に登録されている)のです。コントロールパネルのユーザアカウントを開きます
  12. 左サイドの「環境変数の変更」をクリックします。
  13. ユーザ環境変数の中にある「path」をクリックし、編集ボタンをクリック。
  14. 中身をテキストエディタにでもコピーして、npm-lifecycleの文字がある変数の部分だけを削除する
  15. 続けて、同じ所に「;」で繋げて、「C:\Users\ユーザ名\AppData\Roaming\npm」を加える(node-gypを-gでインストールした場合)。いちばん手間のない方法は、electron-rebuildをインストールし、「C:\Users\ユーザ名\AppData\Roaming\npm\node_modules\electron-rebuild\node_modules\.bin」を指定する事。Windows10ではこれで問題なくリビルドできました。他にもしnode-gypらしきものを参照してる環境変数があったら削除しておく。
  16. 13.に15.の内容を上書きして保存する。これでnode-gypコマンドが使えるようになります。
  17. コマンドプロンプトよりnode-gypと打って、Usageなどの使い方に関する項目が表示されればオッケー
  18. npm install -g electron-rebuildで、electron-rebuildをインストール
  19. プロジェクトフォルダに入り、npm install keytar@4.2.1を実行して、ネイティブコンパイルインストールする
  20. この時、node-gypがKeyError '2017'というエラーを吐くことがあります。Windows10 64bitだと問題なかったのですが、Windows8.1で確認。こちらでもissue報告されています。
  21. keytarディレクトリに入り、node-gyp configureを実行する
  22. プロジェクトフォルダ直下に戻る
  23. electron-rebuild -w keytarでリビルドをする。rebuild complateが出れば完了。
  24. これで、Windowsでもkeytarが使えるようになり、アプリが落ちることがなくなりました。
  25. 試しにkeytarを使ってパスワードをセットしてみて、該当の設定がWindows資格情報に入っていれば成功!!

図:Windows-Build-Toolsがやけに時間が掛かる

図:node-gypのパスが間違って登録されているので修正が必要

コマンド:node-gypを実行した結果

コマンド:node-gyp configure実行して成功した様子

コマンド:node-gypでリビルド中の厄介なエラー(Windows8.1で確認)

図:Windowsの資格情報マネージャに登録できた

  • ※keytar4.3.0やelectron4.0.3でもelectron-rebuildをすれば使えるようになるかもしれませんが、試していません。とりあえず、動く環境にたどりつけたので良かったです。
  • ※keytarを使ったアプリをmacOSとWindowsの両方でリリースする場合は、それぞれに環境を作ってビルドするほうが良いと思います。
  • ※64bit Windows上でrebuildした場合、64bit Windows上でしか動作しませんので注意。また、ia32でelectron-packagerでパッケージを作ろうとした場合にも同様のエラーが出ます。

社内で使うと接続が途切れる場合

小さな企業内の場合、せいぜいルーターが1個ある程度の環境なので、普通にサーバを立てれば普通に運用が可能だと思いますが、ある程度の組織の場合、途中に存在するルータ、スイッチその他いろいろなものが入っています。ネットワークの設計上早めにTCPのコネクションを解除するような設定が入っていると、立てたMySQL Serverに他の方が接続できなくなったり、しにくくなったりすることがあります。

そこで、OS側に定期的に生存している旨のパケットを送る設定がありますが、これを少し変更しておくと接続を維持できるようになります。もちろん、OS自体が勝手にスリープしてしまったり、サスペンドしないように設定しておくようにしましょう。今回はUbuntu Linuxをベースに記述します。これらの作業はターミナルとテキストエディタで行います。

logind.confでサスペンドをオフ

geditが起動したら、以下の項目を新規に追記

追記したら再起動すればサスペンドしないようになります。

InterfacesにDNS設定

geditが起動したら以下の項目を新規に追記。すでにあるdns-nameserversはコメントアウト。DNSは社内にあるならそれを指定。

追記したら再起動するだけです。

nsswitch.confでhostsの設定

geditが起動したら以下の項目に編集しなおす。

追記したら再起動するだけです。

resolv.conf関係にDNSを設定

geditが起動したら、以下の項目を追記する

さらに以下のコマンドで編集を行う

起動したら既存のdns-nameserversをコメントアウトして、以下の項目を追記

追記したら再起動するだけです。

sysctl.confでkeepaliveの設定

最後に一番重要な設定。キープアライブの設定とIPv6の設定を行います。UbuntuはIPv6の設定をオフにしておきます。

geditが起動したら以下の項目を追記する

追記したら以下のコマンドで設定を反映する。sysctl -a | grep keepalive_timeは保存した設定を確認するコマンドです。

これで即時にキープアライブとIPv6の設定が反映されます。

仮想環境で構築した場合

仮想環境にMySQLサーバを構築した場合、通常であれば仮想マシン側に固定IPを割り当てて運用するところですが、ネットワークによってはこれが非常に遅く、またブツ切れを招くことがあります。つながったりつながらなかったり・・・

そこで、親機に固定IPを持たせて、仮想マシン側はNAT接続にすると具合がよかったりします。また、その場合親のポートを仮想マシン側へポートフォワーディングさせる設定が必要です。VirtualBoxの場合、NATで接続する場合には簡単に仮想マシン側へポートフォワーディングが可能です。親の3306にアクセスすると、仮想マシン側の3306につながります。

図:ポートフォワーディングで一気にパフォーマンス改善

MySQL側の準備

MySQL Serverのインストール

今回、仮想環境上のLinuxやmacOS上に、MySQL Serverをインストールして開発を行っております。今回はmacOSで以下の手順でインストールしております。以前、XAMPPを使っていた関係で、以前のバージョンのMySQLが残っていたため、トラブルになりつつも、無事にサーバを用意する事ができました。

  1. macOSでのMySQLはHome Brewを使ってのインストールが一般的ですね。まずはターミナルを起動します。
  2. brew updateでアップデートをまずは実行
  3. 続けて、brew install mysqlで本体をインストールします。
  4. 完了したら、mysql_secure_installationコマンドでセットアップを開始するのですが、今回エラーが出ました。「Can't connect to local MySQL server through socket '/tmp/mysql.sock'」
  5. sudo touch /tmp/mysql.sockでソケットファイルをつくってあげる
  6. また、作成したソケットの権限を、sudo chown ユーザ名 /tmp/mysql.sockで変更
  7. mysql_secure_installationコマンドで、セットアップ開始。rootのパスワード設定他、基本的にはYで回答しておけばオッケー。
  8. ERROR! The server quit without updating PID fileというエラーが出る場合には、以下のコマンドを実行して、mysqlを一度再インストールすると良いです。

brew uninstall mysqlでアンインストール可能です。macOSでHomeBrewで入るバージョンは、5.7ではなく8.0系なので注意が必要です。

テーブルの定義

今回は以前、Google Apps Scriptにて作成した座席表アプリを、MySQL + Electronで移植をしてみようと思います。MySQL側では、スプレッドシートで構成したシートレイアウトを元に、予めテーブルを作っておきましょう。自分が用意した構成は以下の通りです。

  1. MySQLに新たなschemeとして「zaseki」を作成
  2. zasekiスキーマに対して、「ユーザ表」と「シートデータ」のテーブルを準備
  3. MySQLにログインするユーザアカウントの作成とパスワードの設定を済ませておく
  4. ユーザ表はuseridとして定義、シートデータはseatとして定義しました。
  5. 2つのテーブルには3.で作ったアカウントでのアクセス権限は付与しておきましょう。

図:新しいテーブルスキーマを作成

図:ユーザ表のテーブル定義

図:シート表のテーブル定義

MySQLのTimeoutを設定等

MySQLを動かすUbuntu上のサーバでいろいろとKeepaliveの設定を行っていても、MySQLにはMySQLのコネクションの処理に関する設定があります。こちらも設定しておくべきでしょう。

skip-resolve-name

my.cnfもしくはmysqld.cnfに対して、skip-resolve-nameの設定を追記します。これは固定IPで運用する場合に設定するもので、DNSでの逆引きを利用しない設定です。少しだけ早くなると同時に余計なDNS参照をする事がなくなります。単純にskip-resolve-nameを追記するだけでオッケーです。

ただしこの設定を追加すると、localhostでの接続ができなくなります。127.0.0.1での接続は可能ですが、MySQL側で例えば、root@localhostでアカウントを作っている場合、接続出来ません。root@127.0.0.1で作成している場合には接続が可能です。

wait_timeout

MySQLに接続する時に用いられる、接続してからの維持時間がコレです。デフォルトでは8時間(28800秒)で設定されています。正直これは長すぎるので、短く設定してみたいと思います。

これを300秒とする場合には、my.cnfもしくはmysqld.cnfに対して、wait_timeout=300を追記するだけです。

ソースコード

ログイン画面の作成(setting.html)

  • メイン画面の子Windowとして呼び出されます。macOSの場合は上からにゅっと出てくるようになるのですが、Windowsの場合はモーダルダイアログとして表示されます。
  • サーバアドレス、使用DB名、ユーザID、パスワードを入力し、メインプロセスのkeytarにて情報をOS管理の資格情報システムに登録します。また、起動時には資格情報システムから呼び出してロードします。
  • 今回の画面のCSSはこちらのサイトのスタイルシートを利用しています。

メイン画面の作成(index.html)

  • メインの座席表を表示するレンダラープロセスのコードです。
  • 座席確保やリリース時に入力するダイアログでの値はLocalstorageに保存されます。画面表示する際には呼び出されます
  • 座席表の基本データはzaseki.htmlに記述してあり、起動時にidがzasekinの場所にロードされます。ロードが完了してから、shapeshifterの適用を行い、またMySQLから現在のシート確保状況データをconnectSQLでロードさせています。
  • 座席のレイアウトや確保対象外とするパネルはzaseki.html側を編集します。nothingが1のものは、確保対象外のパネル(非表示になります)を意味します。cabinetはそもそも椅子ではない場所を意味します。data-ss-colspanは横長のパネルで役員席などに適用する為のものです(横に2パネル消費します)
  • testsync関数では、メインプロセスからの通信を受け取るipcrenderer.onを待機させる為の関数です。各関数はメインプロセスからプッシュされると自動的に応答して処理がなされます。
  • メインプロセス側にデータを送る役目をしてるのが、ipcRenderer.sendでメインプロセス側で受け取ると処理が開始されます。
  • 着席中の人をクリックして、例えばSkype for Businessを起動させて直で連絡させる、なんて機能を付けたい場合は、Skype for BusinessのURLスキーマを使って、単純に<a>タグでURLスキーマをリンクとして張ればOK(例:<A href="sip:yamato.takeru@hogehoge.com?call">Skypeで連絡</A>)

図:タグだけで挙動を制御できるのがElectronの利点ですね

Node.js側コード(index.js)

  • keytar自体はモジュールが動いてくれる状況であれば、OSに合わせてOSに装備されてる資格情報管理システムへパスワードを記録してくれます。
  • 今回、やや冗長なコードの書き方になっています。
  • 接続設定用のsetting.htmlおよびメイン表示用のindex.htmlの2つによるマルチウィンドウ仕様ですが、setting.html側には初期ではhideになるようにし、またindex.htmlの子ウィンドウになるようbrowserwindowにオプション設定を追加してあります。
  • ipcMain.onにてレンダラープロセス側からの通信を待機させてあります。
  • promise-mysqlを利用しているので、同期処理でMySQLへの接続を実現しています。
  • MySQL接続とクエリの処理では、通常のSQL文を使った処理と、where条件に?を使うプレースホルダーを使ったケースの2つで記述をしています。プレースホルダーを使ったほうが引数を渡しやすいですね。SQLインジェクション対策も考えたら、プレースホルダと変数のチェック機能をつけるべきでしょう。
  • keepsheetとrelsheetの2つでは確保状況の確認と実際に値をセットするSQLの2回を連続実行しています。promiseで順番に実行させられるので、コールバック地獄にならず綺麗に書けます。
  • relsheetsqlにてケースによって確保した座席がリリースされない場合があるので修正しました。

機能の追加

2019年8月30日現在、社内向けで作ってる座席表アプリは、更なる機能増強を図り、現在以下のような機能を搭載しています。目的は座ってる場所の把握と、顔と名前が一致しない覚えられないというフリーアドレスならではの問題を解決する為です。

  1. 座席に座ってる人を検索する為の機能(クリックすると座ってる部屋に切り替わり、対象者に★が付く)
  2. Canvas使用時の文字がにじむ現象の修正(高解像度対応
  3. 座席キープ者をクリック時に、詳細な情報をダイアログで表示する機能(写真表示あり)
  4. 人員増加によりメインルームも複雑化した為、全面クリッカブルマップ化を行った。

この増強した中で、1.および3.についての知見をここに残しておこうと思います。

他のウィンドウから他のウィンドウを操作する

Electronで生成したBrowserWindowによるウィンドウはメインプロセス側から操作する事は可能でも、他のBrowserWindowで生成したレンダラプロセス側から操作する事は通常できません。しかし、検索用ウィンドウからメインの座席表の検索と表示の切り替えをしたいと思った場合、「メインプロセスを中継して操作する」ようなコマンドを用意する必要があります。

命令を受けるレンダラプロセス側では、メインプロセスから飛んできた命令について処理をするコマンドをipc通信で待機させておき、飛んできたら処理を実行するよう仕組みを用意しておきます。

  • 対象者が今見ているマップではない場合、マップチェンジを行ってから🌟の描写を行ってる
  • 🌟描写後に、検索窓を閉じたりマップを変更した場合には星をクリアするようにしている。
  • 🌟の描写用に4枚目のcanvasを用いています。

図:ユーザ座標検索窓から座席表メインウィンドウを操作する

キープ者の詳細ダイアログ表示

キープされてる座席をクリックすると、座席のタグに書き込まれているフラグを読み取り、対象者の詳細情報をMySQLから取り出し、モーダルダイアログに表示するようにしています。今回利用させて頂いたモーダルのコード自体は、こちらのサイトを参照してみて下さい。非常に優れたモーダルウィンドウです。

このウィンドウの注意点は以下の通り。

  1. 写真の有無はMySQL側のpict列を参照させ、-1ならば指定のURLからロードする
  2. 写真は人によって縦横サイズが異なる。このような写真を400x400の写真枠内に収まるようにアスペクト比を考慮してリサイズする。
  3. CSSな処理として、人名については写真にオーバーレイさせた位置に表示。
  4. CSSな処理として、社員IDについても、左上にIDとして重ねて表示させる(こちらのCSSを利用させて頂きました)
HTML側コード

CSSコード

図:写真データがある場合はその画像をロードします

外部アクセスでプロキシーを経由させる

自宅や特にプロキシーサーバを設定していないような会社の場合には、この設定は不要ですが、それ相応の企業になると外部へのアクセスはプロキシーサーバ経由でなければさせないようになっていると思います。この場合、メインプロセス、レンダラープロセス共に外部へアクセス出来ないので、例えばレンダラプロセス側でCDNなどのライブラリを読みに行っている場合、取ってくる事ができません。

そこで以下のようなコードを追加する事で、必ず外部アクセスはプロキシーサーバを経由するようにする事が可能です。

図:プロキシー経由させずにDNSエラーが出る

JSONデータをまるっと列に入れ込みたい

MySQL 5.7より、Columnの型に「JSON型」というものが用意されました。予め、テーブルの対象の列の方をJSON型にしておき、入れ込むJSONをJSON.stringifyしておいたものを、普通に入れ込めば入ります。但し、MySQL側で入れることのできるJSONは、いい加減な書式だと弾かれてしまいます。入れることのできるJSONの例は以下の通り

列の名前がMySQLの予約語(tableやらbeforeやら)でなければ、JSON.stringify(jsondata)した値をそのまま、insert intoで流し込むことができるようになります。自分の場合、アプリケーションで編集前のデータを取っておき、編集保存時にログテーブルへとこの編集前データを記録。いざという時には、このログからそのまま復元できるようにアプリに作り込んでいます。

図:beforedata列にJSON値が入った

指定時刻に座席を強制リリース

今回のアプリケーションは、誰かが座席を確保したまま、リリースを忘れると永遠に席を確保された状態になってしまいます。それでは翌日皆が困ることになりますね。そこで、この座席についてkoteiflgが0の値(つまりフリーアドレス席全部)について、すべての座席データを強制リリースさせる為の仕組みが必要になります。

この作業もNode.jsでやらせる事が可能です。MySQL Serverの入ってるマシンにNode.jsをインストールして、座席を強制リリースするSQL文を書いたアプリをサービスとして常駐させて置きます。今回は、Ubuntu Linux 18.04をベースにお話を進めます。

事前準備

electronでもNode.jsを利用しましたが、今回のアプリでもNode.jsを利用します。今回追加で利用するモジュールは以下の通り。クライアントアプリも作れ、サーバサイドも同じ言語で作れるNode.jsの美味しいポイントですね。

これらをnpm installでプロジェクトフォルダ内で実行しインストールしておきましょう。foreverはプログラム中で使うのではなく、外部で利用するものなので、-gオプションでグローバルインストールしましょう。

ソースコード

  • keytarモジュールは今回とくにリビルドせずとも動作しました。electron上で動かす時とは違って素直でした。
  • zaseki_clearというサービス名を自分は使って、資格情報にパスワードを登録しています。初回だけこのパスワード格納の作業が必要です。次回以降はkeytarモジュールが自動で取得してくれます。
  • 座席のクリアは、UPDATE文の発行で処理します。koteiflgが0のレコードを対象にします。
  • node-cronにてCronのように指定時刻に特定のコマンドを実行します。このアプリは一度起動するとシャットダウンされるまで自動で、常駐し続けて動作します。

図:パスワードと鍵にて登録内容を確認できる

デーモン化

今回のこのアプリですが、このままでは、起動する為には手動でコマンド入力が必要です。そこで、このアプリをOS起動時に自動的に起動し常駐させておく仕組みも用意します。foreverモジュールを利用すると、作成したJSファイルをデーモン化して管理することが出来るようになります。複数のNode.jsアプリケーションを起動し常駐させることができ、またスクリプトが落ちた時に自動的に再起動もしてくれます。Node.jsを扱うなら是非入れておきたモジュールの一つです。デーモン化自体は以下のコマンドで可能です

この時、オプションなどを指定することが出来ます。ファイルの指定は拡張子まで含めて行わなければなりません。プロセスは、forever listコマンドで一覧が出てきます。通常はここから、systemdなどに登録してこのスクリプトを自動起動したいところなのですが、今回のスクリプトは、keytarを使ってパスワードを取得する必要があるため、最初の1回はforeverでstartする際にsudoでのログインパスワードを求める画面が出るので、systemdでの自動化が出来ません。

図:デーモン起動時にパス取得の問い合わせが出る

図:forever listで現在のデーモンを確認

そこで利用するのが、gnome-session-properties。これは、Ubuntuが起動後に自動的に起動するアプリケーションを登録しておく為のもので、systemdのような仕組みというより、Windowsのスタートアップフォルダみたいなものです。ここで以下のように登録しておきます。

  1. 右下の●の粒をクリックする
  2. アプリケーション一覧が出てくるので、検索画面でsessionと入れる。「自動起動するアプリケーションの設定」が出てくるので、クリックする
  3. 追加ボタンをクリック
  4. 適当な名前、実行するコマンドの入力(今回はシェルスクリプトを作ってそれを登録してあります)します。
  5. 保存を押して完了

これで、毎回ログイン後に、forever start index.jsの入ったシェルスクリプトが起動し、パスワード入力を求めてきます。パスワードを入れて実行すると、keytarがlibsecretからパスワードを拾ってきてforeverにてindex.jsのアプリが常駐化します。

図:アプリやシェルスクリプトをX起動後に実行します。

きちんとパーミッションやこのシェルスクリプトの内容が正しければ、再起動した直後にforever listコマンドを叩くと、Node.jsアプリのプロセスが出てくるはずです。また、Node.jsのアプリがこけて自動再起動が掛かると、PIDが変わります。

  • どうも、昔はNode.jsは起動しっぱなしだとメモリリークでどんどんメモリを食いつぶすとか、それは直ったといった話があったようです。node –expose_gc setseat.jsといったようなオプションを付けて起動すると良いとかなんとか。
  • 今回のスクリプトは1回手動でパスワード登録が必要になっているので、node index.jsにて起動し、パスワードが無事に登録出来ているかを確認しましょう。次回以降はパスワードを自動でロードされると思います。

指定時刻に自動バックアップ

前項にて指定時刻にて強制リリースをnodeのcronモジュールを利用して実現しました。今回のアプリケーションは基本登録データに対して読み書きはすれど、レコードを追加するアプリケーションではないので、初期バックアップだけできていれば、いざという時は、それを復元することで事足ります。

しかし、社内申請システムのようなデータを蓄積していくタイプのアプリケーションの場合には、これでは困ります。そこで、前回のスクリプトに加え、自動的に外付けHDDにMySQLのDBを自動的にバックアップするシェルスクリプトを実行するコードを追加して利用しています。

自動的にMySQLのデータをDump

このシェルスクリプトは次項のバックアップを実行するnodeのスクリプトから呼び出されるシェルスクリプトです。ファイルを作成したら、適度なアクセス権限を付与しましょう。スクリプト内にパスワードが記載されているので、誰でもアクセスできる状況は好ましくありません。

  • 外付けHDDにSQL形式のファイルがgz圧縮されて生成されます。
  • 今回のスクリプトは全データベースを指定しています。
  • ファイル名には日付が付与されるようにし、10世代管理を行っていますので、過去のファイルは削除されてゆきます。
  • 今回このシェルスクリプトにはdumpman.shというファイル名をつけてあります。

自動的に指定時刻にバックアップするスクリプト

前回作成した自動で強制リリースするスクリプトに追記する形で、以下のコードを付け加えています。シェルスクリプトを実行するだけのものなので、特に追加のモジュールは必要ありません。

標準モジュールの宣言に追加

child_processモジュールは標準装備のモジュールで、Nodeスクリプトからシェルコマンドを実行するために必要なものですので、宣言に追加しておきましょう。

CronJobのOnTickに追加

前回のコードの中にあるOnTickに次項で作成するmysqlexport()を実行するコードを追記します。

dumpman.shを実行する関数を追加

前項で作成したdumpman.shを実行するシェルコマンドを実行するコードをchildProces.execで記述することができます。node.jsからシェルコマンドを実行する時のテクニックです。複数行に渡るコードをこれで記述するのは辛いので、シェルスクリプトにしてそれを単純実行する形にすると楽になります。

実行結果を受け取ることも可能です。

実行ファイルと結果

実行ファイルのダウンロード

今回のファイルをそれぞれの環境でelectron-packagerでビルドしてみました。無事にローカルのMySQLおよびGoogle Cloud SQL、Cloud SQL Proxy経由で接続が成功しました。

図:Windowsでも無事に動きました。

こんな感じに動きます

electronで座席表アプリを作る

関連リンク

ElectronでMySQLへ接続するアプリを作る” に対して2件のコメントがあります。

  1. 通りすがり より:

    Electronでkeytar導入を検討していて見に来たのですが、やっぱりネイティブの機能の特にセンシティブな部分なので修羅の道ですね……。
    OSサイドもセキュリティ周り弄ってくるし、Electronもバージョンアップ激しいので、保守コストなりでエグいことになりそう。
    お疲れ様です……。

  2. akanemaru2017 より:

    各OS用のキーチェーンとも言えるものの読み書きは可能ですが、keytarモジュール自身はNode.js用なので、モジュールのリビルドが上手くいくとは限らないのが・・・この部分だけは別のサーバでも立てて、Node.js経由でやり取りするといった方法ならば緩和できるかなぁとは思います。

    生のままAccess Tokenをローカルに置いておくわけいかないので、苦しいですね。

通りすがり へ返信する コメントをキャンセル

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

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