heroku + electron でニコニコメソッドを作ってみました。その２（ルーム分け機能追加）

# はじめに
* [heroku + electron でニコニコメソッドを作ってみました。](https://qiita.com/UC-SADA/items/b8021ba4679731796cb9)でプレゼンテーションをインタラクティブにできるツールを作りましたが、機能を少し追加しました。

# 追加機能
* ルーム分け　：　コントローラからの入力を指定されたディスプレーのみに送信する機能。

# どんなものか使ってみたい方は（64bit windows PC限定ですが）
* https://github.com/UC-SADA/package_file のgithubからzipをダウンロード
* 解凍後「nicoG_1_3-win32-x64」⇒「nicoG_1_3.exe」ファイルを実行。
* 下記ウィンドウが表示された、好きなルーム名を入力して　ボタンをクリック。

![ルーム_ウィンドウ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319430/11da5664-f08a-44a2-348e-d8155da66b3e.png)

* コントローラーウィンドウが起動します。

![コントローラー_ウィンドウ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319430/5dcc9c84-0a67-d32e-e922-7043a2e8e0d7.png)

* 見えてませんが、透明なスクリーンが表示されているので、コントローラーのボタンをクリックしたり、テキスト入力するとスタンプが表示されたりニコニコの弾幕的な奴が流れます。

![niconico.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319430/1486521a-a436-a27e-f089-c83cfc05eb93.png)

* 終了するときは実行ファイルを閉じつつ、タスクマネージャーで「nicoG_1_3.exe」を終了させてください。

# 実装内容
* 事前準備については[「その１」](https://qiita.com/UC-SADA/items/b8021ba4679731796cb9)を参考にしてください。
* 今回からテンプレートにjade を使って書いてみました。
* heroku側の実装内容については　[nico-chat-heroku_ver2](https://github.com/UC-SADA/nico-chat-heroku_ver2)にソースコードをアップしています。
* electron側の実装内容については　[niconico-Display](https://github.com/UC-SADA/niconico-Display)にソースコードをアップしています

## heroku 側の実装内容
### index.js
``` index.js
"use strict";
const createError = require('http-errors');
const path = require('path');
const express = require('express');
const app = require('express')();
const http = require('http').Server(app);
module.exports.io = require('socket.io')(http);
const extend = require('util')._extend
const cookieParser = require('cookie-parser');
const session = require("express-session");
const logger = require('morgan');

http.listen(process.env.PORT || 2525, function(){
  console.log("PORT : " + (process.env.PORT || 2525));
});

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser("secret","mycom_secret_key"));
app.use(session({key:"session_id"}));
// Router
const indexRouter = require('./routes/index');
const nicoRouter = require('./routes/nico');
const displayRouter = require('./routes/display');
const controllerRouter = require('./routes/controller');

app.use('/', indexRouter);//TOPページ
app.use("/public",express.static(path.join(__dirname, 'public')));//ニコニコするJavascriptを格納。
app.use('/nico', nicoRouter); //ニコニコの処理
app.use('/display', displayRouter); //このURLをelectronの透明スクリーンで表示
app.use('/controller', controllerRouter); //このURLが配布用に
```
ここまではほぼExpressのテンプレート通りで各処理ごとにapp.useに割り当て。
### nico
/:room_id/:name　を追加してルーム名ごとの割り振り
app.io.to(req.params.room_id).emit('like', msg)　でルームにメッセージ送信
socket.join(room);　後述、Display画面のルーム指定に使います。

``` rutes/nico.js
var express = require('express');
var router = express.Router();
var app = require("../index");
var extend = require('util')._extend;

app.io.sockets.on('connection', function(socket) {
  socket.on('client_to_server_join', function(room) {
      socket.join(room);
  });
  router.get('/like/:room_id/:name', function (req, res) {
    const msg = extend({}, req.query);
    app.io.to(req.params.room_id).emit('like', msg);
    res.end();
  });
  router.get('/comment/:room_id/:name', function(req, res) {
    const msg = extend({}, req.query);
    app.io.to(req.params.room_id).emit('comment', msg);
    res.end()
  });
});

module.exports = router;
```

### controller
/:room_id/:name　をコントローラ画面にも追加。
room : req.params.room_id,
name : req.params.name,
でjadeに受け渡し、

```rutes/controller.js
router.get('/:room_id/:name', function(req, res, next) {
  var msg = req.params.name + "さんで<BR>" + "「" + req.params.room_id + "」ルームにログインしています。";
  res.render("controller",{
    room:req.params.room_id,
    name:req.params.name,
    msg : msg
  });
});
```
.jadeの中で
`#{room}/#{name}` で受け取り　nico.js に受け渡し

``` views/controller.jade
function handleSubmit (form) {
  const action = $(form).attr('action')
  const params = $(form).serialize()
  const url = `${action}/#{room}/#{name}/?${params}`
  console.log(url)
  $.get(url)
  .fail(function () {
  alert('failed to send message.')
  });
}
function like (type) {
  const url = `/nico/like/#{room}/#{name}/?image=${type}`
  console.log(url)
  $.get(url)
    .fail(function () {
      alert('failed to like.')
  })
}
```
### Display
/:room_id/:name　をDisplay画面にも追加。
room : req.params.room_id,
name : req.params.name,
でjadeに受け渡し、

```rutes/controller.js
router.get('/:room_id/:name', function(req, res, next) {
  var room = req.params.room_id
  var name = req.params.name
  res.render("display",{
    room:room,
    name:name
  });
});
```
.jadeの中で
socket.emit("client_to_server_join", "#{room}");　でルームの指定

```views/controller.jade
script(type='text/javascript').
  var socket = io.connect();
  socket.emit("client_to_server_join", "#{room}");
  socket.on('comment', function(msg){
      handleComment (msg) ;
    });
  socket.on('like', function(msg){
      handleLike (msg) ;
    });
```
できたらコマンドプロンプト画面でheroku側のディレクトリまで移動し下記コマンドで起動

```bush
$ node index
```

## electron 側の実装内容
### index
ルーム名を入力する簡単なwindowを作成。

```index.js
"use strict";
const electron = require('electron');
const elc_app = electron.app;
let inputWindow;

elc_app.on('ready', function (event) {
  inputWindow = new electron.BrowserWindow({
      width: 300,
      height: 180,
  });
  inputWindow.loadURL('file://' + __dirname + '/input.html');
});
```
input.htmlの中で
ルーム名をテキスト入力してボタンを押したら
　win.loadURL("https://nico-chat.herokuapp.com/display/" + room)　というURLの透明スクリーンのブラウザで起動し
　win2.loadURL("https://nico-chat.herokuapp.com/controller/" + room);　というURLを普通のブラウザで起動
　window.close();　　でインプットウィンドウを閉じる。
localhostで動かす場合はそれぞれ、
　win.loadURL("localhost:2525/display/" + room)
　win.loadURL("localhost:2525/controller/" + room)
に変更

```input.html
<html>
<head>
  <meta charset="UTF-8">
  <title>Room</title>
</head>
<body>
  <p>開くルームを入力してください。</p>
  <input type="text" id="room">
  <button id="nico-window">Open niconico-Display</button>
  <script>
  const electron = require("electron")
  const BrowserWindow = require('electron').remote.BrowserWindow
  const path = require('path')
  const nicoWindowBtn = document.getElementById('nico-window')
  let win
  let win2

  // ボタンクリック時に、レンダラープロセスから別ウィンドウを表示
  nicoWindowBtn.addEventListener('click', function(event) {
    var room = document.getElementById('room').value
    var size = electron.screen.getPrimaryDisplay().size;
    win = new BrowserWindow({
      left: 0,
      top: 0,
      width: size.width,
      height: size.height,
      frame: false,
      show: true,
      transparent: true,
      resizable: true,
      webPreferences: {nodeIntegration: false}
    });
    win.setIgnoreMouseEvents(true);
    win.maximize();
    win.setAlwaysOnTop(true);
    win.loadURL("https://nico-chat.herokuapp.com/display/" + room)
//　　win.loadURL("localhost:2525/display/" + room)　
    win2 = new BrowserWindow({
        left: 0,
        top: 0,
        width: 400,
        height: size.height,
        frame: true,
        show: true,
        transparent: false,
        resizable: true,
        webPreferences: {nodeIntegration: false}
    });
    win2.loadURL("https://nico-chat.herokuapp.com/controller/" + room);
//　　win.loadURL("localhost:2525/controller/" + room)　
    window.close();
  })
  </script>
</body>
<html>
```
できたらコマンドプロンプト画面でelectron側のディレクトリまで移動し下記コマンドで起動

```bush
$ electron .
```