読者です 読者をやめる 読者になる 読者になる

Calmery.me

みっかぼうずにならないようがんばる

サイバー防犯ボランティアでアプリを作った

CyberVolunteer GitHub JavaScript Patchworks Twitter Electron Spotlight Node.js

前回のサイバー防犯ボランティア九州フォーラムで発表した通り,最低限の機能を持ったアプリケーションを今月中に公開することができた.
calmery.hatenablog.com
明日から少しの間はゆっくり寝れる.開発の時間が短すぎたり色々問題が起こったりとそこそこ時間がかかってしまった.情報を共有するためのサーバの実装まで間に合わなかったのが心残り.近いうちに実装したいと思う.

疲れた.あとアプリケーションの見た目を作ってくれる人を探したい.今回は見た目も頑張ったがもうやりたくない.次回は情報の共有と検索の強化に努める.隠語のリストなどまだ実装してない部分が多い為これも近いうちに実装したい.現在三人でアプリケーション,サーバ,ライブラリと別れて作業している.時間があれば問題はないだろうけど辛い.そろそろ人を増やしたい.

開発環境

現在は NodeJS v5.10.0 と npm 3.8.3 を使用して開発を進めている.拡張を進めるにあたって以下のようにレポジトリを取得する.よくよく見てみると README には Node v4.4.7 LTS を入手と書いていた.動くのでどちらでもいいかも.

calmery:git calmery$ git clone https://github.com/calmery/spotlight.git
Cloning into 'spotlight'...
remote: Counting objects: 107, done.
remote: Compressing objects: 100% (81/81), done.
remote: Total 107 (delta 40), reused 67 (delta 15), pack-reused 0
Receiving objects: 100% (107/107), 473.23 KiB | 376.00 KiB/s, done.
Resolving deltas: 100% (40/40), done.
Checking connectivity... done.
calmery:git calmery$ cd spotlight
calmery:spotlight calmery$ npm install
spotlight@0.1.0 /Users/calmery/Git/spotlight
├─┬ electron@0.4.1 
├─┬ express@4.14.0 
├─┬ express-session@1.14.0 
├─┬ passport@0.3.2 
├─┬ passport-twitter@1.0.4 
├─┬ socket.io@1.4.8 
└── twitter@1.3.0 

中身はこうなっている.

├── config
│   └── config.js
├── icon.ico
├── index.js
├── library
│   ├── electron.js
│   ├── express.js
│   └── twitter.js
├── node_modules
├── package.json
├── spotlight.icns
├── spotlight.iconset
└── view
    ├── edit.html
    ├── index.html
    ├── information.html
    ├── list.html
    ├── newUser.html
    ├── resources
    │   ├── css
    │   ├── font
    │   └── js
    ├── search.html
    ├── setting.html
    ├── setup.html
    └── vote.html

恐い人たちから何だこの構成はと怒られそうだが大目に見ていただきたい.

実行

Electron を使用して動かす.このままでは動かないのでさらに必要なモジュールを入手する.

$ npm install -g electron-prebuilt
$ npm install -g electron-packager

これでアプリケーションを実行できる.場所によって引数を変えて実行する.

$ electron .

開発

まず library だがここにモジュールごとに処理を分けている.次に view には実際に表示に利用する html がある.どれがどれに対応しているかは express.js のルーティングを見ていただければわかる.

実際の実装だが表示を行う html ファイルと NodeJS は socket.io を使って通信を行うようにしている.またユーザの登録とアプリケーションの利用で起動時にルーティングを分けている.これはもともと Web 上に登録ページを作ってそこからアプリケーションのユーザ登録をするはずだったが,登録ページの作成が間に合わず,期間ギリギリでユーザ登録をアプリケーションに後付けで実装したためこうなってしまった.あと検索結果をファイルとして書き出してしまっていること,ファイル名の指定方法によってはいろいろ危ないことがある.

...
var error
fs.writeFile( __dirname + '/data/result/' + data.name + '.json', JSON.stringify( data.data ), function( err ){
    if( err ) error = true
...

この辺りがとても危ない.近いうちに修正する.保存のとき,名前に「../」とかつけちゃダメ.あとファイルを書き出して保存するかわりに SQLite3 を使いたい.初めは使うつもりだったが調べてみると SQLite3 をインストールする必要があるだとかないだとか.自分は入っていて動作するがアプリケーションとして配布したときに動かなかったら意味がない.試す時間が惜しかったので今回はそのまま.インストールする必要がないのであれば利用したい.もしインストールする必要がある場合で使用できないときでももっといい方法を考えたい.

実際にアプリケーションとして書き出す方法は後述するが,ここでハマったので書いておく.初めルーティング部分に渡す関数で以下のように指定していた.

function( request, response ){
    response.sendfile( __dirname + '/../view/index.html' )
}

だが electron-packager を利用し書き出した後に実際に実行してみると以下のように出てうまく動かなかった.

ForbiddenError: Forbidden
   at SendStream.error (/Users/calmery/Cyber/node_modules/send/index.js:275:31)
   at SendStream.pipe (/Users/calmery/Cyber/node_modules/send/index.js:508:12)
   at sendfile (/Users/calmery/Cyber/node_modules/express/lib/response.js:1051:8)
   at ServerResponse.res.sendfile (/Users/calmery/Cyber/node_modules/express/lib/response.js:481:3)
   at ServerResponse.eval [as sendfile] (eval at wrapfunction (/Users/calmery/Cyber/node_modules/depd/index.js:413:5), <anonymous>:4:11)
   at fn (/Users/calmery/Cyber/library/express.js:32:26)
   at Layer.handle [as handle_request] (/Users/calmery/Cyber/node_modules/express/lib/router/layer.js:95:5)
   at next (/Users/calmery/Cyber/node_modules/express/lib/router/route.js:131:13)
   at Route.dispatch (/Users/calmery/Cyber/node_modules/express/lib/router/route.js:112:3)
   at Layer.handle [as handle_request] (/Users/calmery/Cyber/node_modules/express/lib/router/layer.js:95:5)

調べてみると絶対パスで指定すればいいような感じ.いやなってそうだけどと思いつつ node.js - Express res.sendfile throwing forbidden error - Stack Overflow を見て path.resolve で囲ったらいけた.

function( request, response ){
    response.sendfile( path.resolve( __dirname + '/../view/index.html' ) )
}

配布

electron-packager を使用しアプリケーションとして書き出す.アイコンは OS ごとに決まった形で指定する必要がある.

$ electron-packager . SpotlightBeta --platform=win32,darwin --arch=x64 --version=1.2.4

OS X の場合は少し面倒だった.nulab さんの記事,Electronアプリをプロダクトとして「正しく」リリースするために必要な3つのこと | ヌーラボ
Macアプリの.icnsを作るときのメモ - Qiita を参考にするといいがアイコンとする画像をサイズごとに用意しコマンドで icns に変換する.面倒くさい.

calmery:spotlight calmery$ iconutil -c icns spotlight.iconset
calmery:spotlight calmery$ electron-packager . Spotlight --platform=darwin --arch=x64 --version=1.2.4 --overwrite --icon=spotlight.icns
The strict-ssl parameter is deprecated, use download.strictSSL instead
Packaging app for platform darwin x64 using electron v1.2.4
Wrote new app to /Users/calmery/spotlight/Spotlight-darwin-x64

Windows の場合は単純に ico に変換すればいい.アイコンの関係上,まとめて書き出すのはあまり良くないような気がする.