This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

ジーズアカデミー Node.js授業4日目

Last updated at Posted at 2017-08-03

前回資料

アンケート結果

Electron感動! nodeschoolの話もうれしかった(連休前なので)!
electron
websocketやwebRCTの話がためになりました。
node school 良さそう。
socket io
Electronの内容が印象に残りました。
Electronはそこそこでいいです。
Electronをもっとやりたかったです。NodeSchoolも
desktopアプリ
Electron
electron!ただ、デスクトップアプリを作るメリットとかがもう少し知りたかった。
socket.ioが良くわかりました。またnodeschoolが知れて良かったです。
コード解説
さらっとでいいので、デプロイ系の手段提供もやってほしい
午前中10分くらい休憩欲しいです。
とりあえず、復習を頑張ります。
electron熱い。データベース触れて欲しい
socket io とても面白かったです! 内容もよく把握できてスラスラ行けたと思います。
Electronを使ってデスクトップアプリを作るのをやりたいです。
electronはそこそこでいいです。
"めっちゃ面白かったです。
のび先生の授業は情報が溢れてて、話も面白いし最高に楽しい!!
分からない言葉や技術、情報ばかりなんですが、そのヒントを元に自分で勉強できるので嬉しいです。
次の授業めっちゃ出たいんですが、YOUTH CAMPでマイクロソフト社に行けるみたいで、行ってみたいのでそっち行ってきます! ビデオ収録しておいてもらえないですかね〜ww"
今日は少し話が分かってきて、とても興味深かったです。知らない知識を教えて頂けるのがとても有難いです。有難う御座います。
時間内に各自が簡単なアプリを作る。任意で発表。
node.jsを本番環境で動かす際の詳細を知りたいです。あとNodeを使った、動的に生成されたサイトコンテンツのスクレイピング。
socket.ioでリアルタイム通信ができたことが楽しかったです。nodeschoolでたくさん勉強したいです。仮想空間での通信に応用できますか?全然イメージつかないです。。。
"次回の授業では、どのWebサービスにもよくある機能で、チャット機能をnode.jsで作れると嬉しいです。例えば、http://chamo-chat.com/ のような機能を自分で構築できれば、これから作る卒業制作などに活かせるのではないかと思います。チャットのやりとりをDBに保存する機能までできればベストですが、やれるところまで、やれたらと思います。

ちなみに、宿題が難しすぎてやばしです。"
  • とりあえず午前10分休憩はいれます。
  • Electron需要高いのでElectronやります。
  • DBまわり、デプロイまわりも触れます

アンサー /参考記事

宿題の確認確認

管理しているFacebook BOTに連絡がきたら表示してくれるデスクトップアプリ

こんなのです。

今回は宿題内容を確認しつつ実装を進めてみましょう。

前半: ElectronでFB監視の常駐アプリを作る

1. 常駐アプリ

こういうのをイメージ

アイコンを用意

どんなものでも大丈夫です。

これを20x20pxのサイズにしてicon.pngとしてルートディレクトリに設置します。

メニューバーに常駐させるミニマム実装

Trayを利用します。

参考 http://qiita.com/midnightSuyama/items/155607cf3ba03c77d3b3

とりあえずの最小構成はこれくらいです。

main.js
'use strict';

const {app,Menu,Tray} = require('electron');
const path = require('path');
let tray = null;

const createTray = () => {
  tray = new Tray('./icon.png');
  const contextMenu = Menu.buildFromTemplate([
    {label: 'Item1', type: 'radio'},
    {label: 'Item2', type: 'radio'},
    {label: 'Item3', type: 'radio', checked: true},
    {label: 'Item4', type: 'radio'}
  ]);
  tray.setToolTip('This is my application.');
  tray.setContextMenu(contextMenu);
}

app.on('ready', createTray);

実行して確認

npm start

2. 終了処理を追加

プログラムの中でapp.quit()を呼び出せばElectronアプリは終了します。

参考: https://github.com/electron/electron/blob/master/docs/api/app.md

ラベルの書き換えと、イベントの追加をします。

'use strict';

const {app,Menu,Tray} = require('electron');
const path = require('path');
let tray = null;

const quit = () => app.quit();

const createTray = () => {
  tray = new Tray('./icon.png');
  const contextMenu = Menu.buildFromTemplate([
    {label: 'Item1', type: 'radio'},
    {label: 'Item2', type: 'radio'},
    {label: 'Item3', type: 'radio', checked: true},
    {label: 'Quit', type: 'radio', click: quit}
  ]);
  tray.setToolTip('This is my application.');
  tray.setContextMenu(contextMenu);
}

app.on('ready', createTray);

実行してみましょう。

Quitをクリックすると、ctrl+cでNode.jsアプリを終了するときと同様にプロセスが終了してるのが分かります。

3. 通知の仕組みを作る

通知はレンダラープロセス側で実装する方法が主流みたいです。

参考: https://electron.atom.io/docs/tutorial/notifications/
参考: http://blog.techium.jp/entry/2016/04/05/091500

renderer.jsに追記

公式にあるようにrenderer.jsに追記します。

renderer.js
let myNotification = new Notification('Title', {
  body: 'Lorem Ipsum Dolor Sit Amet'
})

myNotification.onclick = () => {
  console.log('Notification clicked')
}

main.jsに追記

現状のmain.jsのコードだとレンダラープロセス(BrowserWindow)が無いので追記します。

'use strict';

const {app,Menu,Tray,BrowserWindow} = require('electron');
const path = require('path');
let tray = null,
    mainWindow = null;

const quit = () => app.quit();

const createWindow = () => {
    mainWindow = new BrowserWindow({width: 800, height: 800});
    mainWindow.loadURL('file://' + __dirname + '/index.html');
    mainWindow.on('closed', () => mainWindow = null);
}

const createTray = () => {
  tray = new Tray('./icon.png');
  const contextMenu = Menu.buildFromTemplate([
    {label: 'Item1', type: 'radio'},
    {label: 'Item2', type: 'radio'},
    {label: 'Item3', type: 'radio', checked: true},
    {label: 'Quit', type: 'radio', click: quit}
  ]);
  tray.setToolTip('This is my application.');
  tray.setContextMenu(contextMenu);
  createWindow();
}

app.on('ready', createTray);

実行して確認する

通知がきましたね

ただ、今回は常駐だけしたいのでウインドウがじゃまです。
widthとheightの値を0に指定しておきましょう。

アイコン設定

まずはまた適当な画像をディレクトリに設置します。notify.pngとしました。

renderer.jsを変更します。

renderer.js
let myNotification = new Notification('Title', {
  body: 'メッセージがきたよ!',
  icon: './notify.png',
})

myNotification.onclick = () => console.log('Notification clicked');

補足: メインプロセス側での通知

今回のアプリだとメインプロセス側だけでも通知は作れます。Electron公式に記載されているnode-mac-notifierを利用すると良さそうです。

Advanced Notifications
Later versions of macOS allow for notifications with an input field, allowing the user to quickly reply to a notification. In order to send notifications with an input field, use the userland module node-mac-notifier.

4. socket.ioで外部からのイベントを受け付ける

index.htmlにsocket.io読み込み

ホストは試しにhttps://socketio-chat.now.sh/を指定します。
index.htmlに<script src="https://socketio-chat.now.sh/socket.io/socket.io.js"></script>を追加しましょう。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    <!-- All of the Node.js APIs are available in this renderer process. -->
    We are using Node.js <script>document.write(process.versions.node)</script>,
    Chromium <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
    <script src="https://socketio-chat.now.sh/socket.io/socket.io.js"></script>
  </body>

  <script>
    // You can also require other files to run in this process
    require('./renderer.js')
  </script>
</html>

renderer.jsにsocket.ioとの接続を記述

同様にホストはhttps://socketio-chat.now.sh/を指定します。

renderer.js
// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// All of the Node.js APIs are available in this process.

const HOST = `https://socketio-chat.now.sh/`;
const socket = io(HOST);

socket.on('new message', function (data) {
  console.log(data);
  let myNotification = new Notification('Title', {
    body: `メッセージがきたよ!: ${data.message}`,
    icon: 'notify.png',
  });
  myNotification.onclick = () => console.log('Notification clicked');
});

動作確認

先ほどから指定してるhttps://socketio-chat.now.sh/はsocket.ioのデモサイトです。

アプリを再起動したら https://socket.io/demos/chat/ ここでチャットしてみましょう。

ここのイメージ

5. Facebook メッセンジャーBOTと接続する

ここでのイメージ

自分のサーバが前回までに作ったapp.jsとngrokでたてたFBBOTのプログラムです。

5.1 前回コードおさらい

とりあえず3日目のコードがこちらです。

3日目の内容を思い出しましょう。

前回までのコードをもとに進めます。

天気以外が来たらオーム返しする処理を追加してます。

ちなみに、再度認証する場合はverify.jsとngrokで再認証。

https://developers.facebook.com
サーバー再設定も可能

5.2 socket.ioのインストール

前回のFBBOTにsocket.ioをインストールします。

npm i --save socket.io
package.json
{
  "name": "fbbot2",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.16.2",
    "body-parser": "^1.17.2",
    "express": "^4.15.3",
    "socket.io": "^2.0.3"
  }
}

5.3 読み込み部分の変更

app.js
'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');

const app = express()
app.use(bodyParser());

~~途中省略最下部まで~~

app.listen(3000);

app.js
'use strict';

const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);

const bodyParser = require('body-parser');
const axios = require('axios');

app.use(bodyParser());

~~途中省略最下部まで~~

http.listen(PORT, () => console.log(`listening on *:${PORT}`));

5.4 socket.ioのコネクション部分を追加

app.jsのconst PATH = '/v2.6/me/messages?access_token='+PAGE_ACCESS_TOKEN;の行の下付近に以下のコードを追記

app.js
省略

io.on('connection', (socket) => {
    console.log('a user connected');
    io.sockets.emit('new message',{message: 'FB接続'});
    socket.on('disconnect', () => console.log('user disconnected'));
});

省略

5.5 イベントの発火(emit)部分を追加

app.jsのmessageTextが送られてくる箇所にio.sockets.emit()を追記

Emitの仕方はEmitチートシートを参照

app.js
省略

        else{
            sendButtonMessage(senderID, messageText)
            .then((body)=>{
                console.log('返信完了', body.data);
            }).catch((error) => {
                console.log(error.data);
            });
        }

        io.sockets.emit('new message',{message: messageText}); //この行を追加

 省略

5.6 Electron側の向き先を修正

先ほど指定してたhttps://socketio-chat.now.sh/から自分のサーバに向き先を修正します。

前回に引き続きngrokでサーバーを立てているのでhttps://40a2c4d9.ngrok.ioなどを指定します。

Electronのindex.htmlrenderer.jsに記載したhttps://socketio-chat.now.sh/を自分のサーバーアドレスに変更しましょう。

5.7 確認してみる

こんな感じでFB BOTにメッセージを送るとElectronがSocket.io経由で通知をしてくれました。

完成版コード

6. 補足

基本は、トリガー -> アクションの流れです。今回はアクション部分をプッシュ通知という形で作りました。
トリガーを変えてあげれば、 スマホで写真を撮ったら通知とか、 デバイスでセンサーを取得したら通知とかもできそうですね。(スプラトゥーンのフェス情報の通知とか...)

BaaSっていう手も

後半: もろもろ

1. DBまわり

2. Electronのアプリ配布

(※時間があれば紹介)

3. デプロイ方法

VPSなど

永続化(デーモン化)+ デプロイ(Gitなど)

heloku

now

4. NowでTwitterアプリをデプロイしてみる

(※時間があれば紹介)

まとめ

アンケート

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up