作成: Lab3期 2017/7/21
ちなみにLAB2期の3日目はこんな感じだったみたい
アンケート結果
左: 1回目 <-> 右: 2回目
コードのレビューもあって楽しかったです。
昨夜、復習、予習をしておいたので、ある程度ついていくことはできました。ES2015の授業の時はわからなかったことが、今になって色々わかってきたので嬉しいです。来週が楽しみです。ありがとうございました。
nodeに興味持てました!色々作ってみたくなりました!
次回はボット以外でお願いします!笑
ハンズオン+解説の組み合わせは楽しい!
面白かった。ソースコードのレビューとか講評とかあると嬉しいです。
少しコード自体の理解ができてない気がします。
最後の方スピードが上がって付いていくのギリギリでした!
宿題の答え合わせ
リッチテキスト利用+応用課題(expressとaxios)
npm i --save express body-parser axios
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const app = express()
app.use(bodyParser());
const PORT = process.env.PORT || 3000;
const PAGE_ACCESS_TOKEN = 'とーくん';
const BASEURL = 'https://graph.facebook.com';
const PATH = '/v2.6/me/messages?access_token='+PAGE_ACCESS_TOKEN;
const sendButtonMessage = (recipientId, messageText) => {
const postDataStr = JSON.stringify({
recipient: { id: recipientId },
message: {
attachment: {
type: "template",
payload: {
template_type: "button",
text: "What do you want to do next?",
buttons: [{
type: "web_url",
url: "https://petersapparel.parseapp.com",
title: "Show Website"
},{
type: "postback",
title: "Start Chatting",
payload: "USER_DEFINED_PAYLOAD"
}]
}
}
}
});
return axios.request({
method: 'post',
baseURL: BASEURL,
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'Content-Length': Buffer.byteLength(postDataStr),
'Accept': 'application/json'
},
url: PATH,
data: postDataStr
});
}
app.get('/',(req, res) => res.send(text));
// POST /login gets urlencoded bodies
app.post('/', (req, res) => {
if (!req.body) return;
const data = req.body;
const event = data.entry[0].messaging[0];
if (data.object === 'page' && event.message) {
//メッセージ受信時の処理
const senderID = event.sender.id;
const messageText = event.message.text;
if(messageText === ''){
console.log('メッセージが取得できない');
return;
}
console.log("Message data: ", event.message);
sendButtonMessage(senderID, messageText)
.then((body)=>{
console.log('返信完了');
console.log(body);
}).catch((error) => {
console.log(error.data.error);
console.log(error.data);
});
}else{
console.log("Webhook received unknown event: ", event);
}
res.send('success');
})
app.listen(3000);
こんな感じ
非同期処理の復習
↑のコードに天気機能を組み合わせてみましょう
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const app = express()
app.use(bodyParser());
const PORT = process.env.PORT || 3000;
const PAGE_ACCESS_TOKEN = 'とーくん';
const BASEURL = 'https://graph.facebook.com';
const PATH = '/v2.6/me/messages?access_token='+PAGE_ACCESS_TOKEN;
const sendButtonMessage = (recipientId, messageText) => {
const postDataStr = JSON.stringify({
recipient: { id: recipientId },
message: {
attachment: {
type: "template",
payload: {
template_type: "button",
text: messageText,
buttons: [{
type: "web_url",
url: "https://petersapparel.parseapp.com",
title: "Show Website"
},{
type: "postback",
title: "Start Chatting",
payload: "USER_DEFINED_PAYLOAD"
}]
}
}
}
});
return axios.request({
method: 'post',
baseURL: BASEURL,
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'Content-Length': Buffer.byteLength(postDataStr),
'Accept': 'application/json'
},
url: PATH,
data: postDataStr
});
}
app.get('/',(req, res) => res.send(text));
// POST /login gets urlencoded bodies
app.post('/', (req, res) => {
if (!req.body) return;
const data = req.body;
const event = data.entry[0].messaging[0];
if (data.object === 'page' && event.message) {
//メッセージ受信時の処理
const senderID = event.sender.id;
const messageText = event.message.text;
if(messageText === ''){
console.log('メッセージが取得できない');
return;
}
if(messageText === '天気'){
const URL = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=400040';
axios.get(URL)
.then((response) => {
console.log(response.data.description.text);
console.log("Message data: ", event.message);
sendButtonMessage(senderID, response.data.description.text)
.then((body)=>{
console.log('返信完了');
console.log(body);
}).catch((error) => {
console.log(error.data.error);
console.log(error.data);
});
})
.catch((error) => {
console.log(error);
});
}
}else{
console.log("Webhook received unknown event: ", event);
}
res.send('success');
})
app.listen(3000);
変更点は天気というテキストを受け取ったらweather.livedoor.com
にリクエストを飛ばして、その結果をBOTがしゃべるテキストにいれこんでいる点
コールバック地獄を見直す
もとのコード
省略
if(messageText === '天気'){
const URL = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=400040';
axios.get(URL)
.then((response) => {
console.log(response.data.description.text);
console.log("Message data: ", event.message);
sendButtonMessage(senderID, response.data.description.text)
.then((body)=>{
console.log('返信完了');
console.log(body);
}).catch((error) => {
console.log(error.data.error);
console.log(error.data);
});
})
.catch((error) => {
console.log(error);
});
}
省略
Promiseでthen繋ぎ
省略
if(messageText === '天気'){
const URL = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=400040';
axios.get(URL)
.then((response) => {
return sendButtonMessage(senderID, response.data.description.text)
})
.then((body)=>{
console.log('返信完了', body.data);
}).catch((error) => {
console.log(error.data);
});
}
省略
Async/Await
省略
if(messageText === '天気'){
(async () => {
const URL = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=400040';
const response = await axios.get(URL);
const body = await sendButtonMessage(senderID, response.data.description.text);
console.log('返信完了', body.data);
})()
.catch((error) => {
console.log(error.data);
});
}
省略
Promise化してくれるやつ
リアルタイム通信/Socket.io
リアルタイム通信技術
- ポーリング
- WebSocket
- WebRTC
- MQTT
いまさら聞けないWebSocketとSocket.IOの基礎知識&インストール (1/2)
Socket.io
- WebSocketを使いやすく
- ひと世代築いたライブラリ
- クロスブラウザ
- ルーム機能などの拡張
触ってみよう/チャット作り
mkdir mychat
cd mychat
npm init -y
npm i --save socket.io express
1. app.jsの作成
'use strict';
const app = require('express')();
const http = require('http').Server(app);
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.send('<h1>Hello world</h1>');
});
http.listen(PORT, () => {
console.log(`listening on *:${PORT}`);
});
2. 確認 localhost:3000
3. index.htmlを読み込むようにする
変更
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
4. index.htmlの作成
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
5. app.jsにsocket.ioのコードを追加
'use strict';
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
});
http.listen(PORT, () => {
console.log(`listening on *:${PORT}`);
});
6. index.htmlにコード追記
</body>
の直前に追記しましょう。
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
7. クライアント/サーバーの接続確認
ここで一旦リアルタイム通信っぽいのができるはずです。
8. 接続が切れた時の処理
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
9. フォームから送信時の処理
index.htmlを編集
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$(function () {
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
});
</script>
10. サーバー側も受信時の処理
- app.js
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('chat message', (msg) => {
console.log(`message: ${msg}`);
});
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
11. 複数人に情報を発信/ブロードキャスト
- app.js
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
console.log(`message: ${msg}`);
});
- index.html
<script>
$(function () {
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
});
</script>
12. ブラウザを複数開いて確認
ほかのサーバーに接続してみる
- index.htmlを変更
<script src="/socket.io/socket.io.js"></script>
↓
<script src="https://4f20dd49.ngrok.io/socket.io/socket.io.js"></script>
- index.htmlを変更2
var socket = io();
↓
var socket = io('http://4f20dd49.ngrok.io');
すると...
こんなイメージ
Electronでデスクトップアプリを作ってみよう
Electronとは
はろーElectron
試してみよう。
Clone the Quick Start repository
$ git clone https://github.com/electron/electron-quick-start
Go into the repository
$ cd electron-quick-start
$ ls
LICENSE.md index.html package.json
README.md main.js renderer.js
Install the dependencies and run
$ npm install && npm start
表示されました?
ファイルの確認
表側
- index.html
- renderer.js
裏側
- main.js
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>.
</body>
<script>
// You can also require other files to run in this process
require('./renderer.js')
</script>
</html>
適当にいじってみよう。
<style>
body{
background-color: red;
}
</style>
とか
- ちゃっとっぽい見栄えとか
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
基本Webサイトと同じ感覚で作れる
main.jsを確認
const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow
const path = require('path')
const url = require('url')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({width: 800, height: 600})
// and load the index.html of the app.
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
NodeSchool
- Node.jsの授業
npm install -g learnyounode
- Electronの授業
npm install -g elementary-electron
- NodeBots
アンケート
宿題
管理しているFacebook BOTに連絡がきたら表示してくれるデスクトップアプリ
ヒント: 前回のFacebook メッセンジャーBOT
、今回やったSocekt.io
とElectron
を組み合わせるとできます。