Help us understand the problem. What is going on with this article?

Node.jsとChrome拡張機能を使ってリアルタイムで通知を出す

More than 5 years have passed since last update.

Node.jsとChromeの拡張機能を組み合わせることでサイト上で何かが起こった時にリアルタイムに通知を出す事ができるようになります。

例えば・・・

  • サイトで何かしらの申し込みがあった時にチームメンバーにお知らせをしたい
  • サイトでデイリーの目標CV数に到達したときにお知らせをしたい

などなど、、、

とりあえず今回はGitLabを使ってマージしたときにポップアップで通知がでるようなものを作成したいと思います。毎回ポップアップがでるのは鬱陶しい!という方はアイコンのバッチを変えたりとかでもいいと思います。

本当は拡張機能を公開とかできればいいんですが、お金かかるし、そこまで作り込んでいないので、断念。

超簡単な図

スクリーンショット 2014-11-25 22.58.45.png

リクエストを受け付けるNode.jsサーバを用意

リクエストを受け付けるNode.jsサーバを用意します。
今回は

  • node.js v0.10.26
  • express 4.9.0

です。

環境構築方法は下記のQiitaとか参考にしてみてください。
注意点としてはexpressのバージョンが3系と4系で大分違うので、
Googleで検索してヒットした記事通りにやってもうごかん!っていうことになります。

Node.jsのインストール
http://qiita.com/takashibagura/items/5b67126072c159bf0f9e

http://qiita.com/uemura/items/a9183ffcec2b185c4c6e

Expressのインストール
http://qiita.com/pakiln/items/826a9199697576e2e24a

Express 4系についてのまとめ
http://qiita.com/zaru/items/68b4f64c1f0d10b6a27e

サーバサイドのソースコード

なんか必要ないところいっぱいあると思いますが、あまり気にせず・・・

全部app.jsにぶち込んでます。

app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var http = require('http');
var app = express();

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


//===========================
//ルーティング
app.post('/', function(req, res) {
    var commits = req.param('commits');
    var commit_message = "";
    for(var i=0; i<commits.length; i++) {
        //マージのcommitメッセージはなくす
        if(commits[i]['message'].indexOf('Merge branch') < 0 ) {
            console.log(commits[i]['message']);
            commit_message += commits[i]['message'];
        }
    }
    io.sockets.emit('push', {value: commit_message});
    res.render('index', { title: 'Express' });
});
//===========================


// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.set('port', process.env.PORT || 3000);

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});


//Websokcet接続の部分
var server = http.createServer(app);
server.listen(app.get('port'), function() {
    console.log("Express server listening on port " + app.get('port'));
});
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
    console.log('connection start');
});

module.exports = app;

なんだかごちゃごちゃありますが、ポイントとしては3つです。

1. bodyParserを使ったPOSTデータの受け取り

POSTされたパラメータをNode.js側で受け取るにはbodyParserというミドルウェアを使う必要があります。
その辺を下記で行ってます。

var bodyParser = require('body-parser');

・・・・・

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

2. ルーティングの設定

今回の場合はpostなので`app.postでデータを受け取ります。

commitメッセージをchrome拡張機能のポップアップに表示させるためにWebhookでPOSTされたデータの中からcommitメッセージを取得してます。

hookとして叩いたURLから何か画面を表示させる訳ではないので、viewの指定とかいらなそうなんですが、ちゃんと指定しないとうまく動かなかったので、res.renderも指定してます。

io.sockets.emitで指定したキーワード(ここではpush)とchrome拡張機能側で受け取りを指定するキーワードと一緒にする必要があります。

app.post('/', function(req, res) {
    var commits = req.param('commits');
    var commit_message = "";
    for(var i=0; i<commits.length; i++) {
        //マージのcommitメッセージはなくす
        if(commits[i]['message'].indexOf('Merge branch') < 0 ) {
            console.log(commits[i]['message']);
            commit_message += commits[i]['message'];
        }
    }
    io.sockets.emit('push', {value: commit_message});
    res.render('index', { title: 'Express' });
});

3. Websocketの通信

Socket.ioをインストール

npm install socket.io

Websokcetのコネクション開始部分

var server = http.createServer(app);
server.listen(app.get('port'), function() {
    console.log("Express server listening on port " + app.get('port'));
});
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
    console.log('connection start');
});

Chrome拡張機能の用意

まずは設定ファイルとなるmanifest.jsonです。

socket.io.jsはこちらにあります。
https://github.com/automattic/socket.io-client

manifest.json
{
  "manifest_version": 2,
  "name": "拡張機能の名前",
  "version": "1.0",
  "description": "説明文",
  "browser_action": {
        "name": "拡張機能の名前"
  },
  "permissions": [
    "notifications",
  ],
  "background": {
    "persistent": false,
    "scripts": ["socket.io.js", "eventpage.js"]
  },
  "icons" : {
    "16":"16x16のアイコン画像",
    "48":"48x48のアイコン画像"
  }
}

こちらが拡張機能のメインとなるjsです。
といってもたいしたことしてませんが、、、

先ほどのmanifest.jsonでbrowser_actionでdefault_popup(ツールバーのアイコンをクリックした時にポップアップを出すようにする)を指定するとなぜかchrome.browserAction.onClicked.addListenerがイベントとれなくなるので注意。

eventpage.js
var socket = io.connect("websocketサーバーのURL");

//websocketで接続した時
socket.on('push', function(message) {
        var opt = {
                type: 'basic',
                title: 'タイトル',
                message: message.value,
                iconUrl: "ポップアップで表示させるアイコン"
        }
        //アイコンにつけるバッチ
        chrome.browserAction.setBadgeText({text:"1"});
        //ポップアップ通知
        chrome.notifications.create("", opt, function(id){});
});

//ツールバーをクリック時にバッチを消す
chrome.browserAction.onClicked.addListener(
        function(tab) {
                chrome.browserAction.setBadgeText({text:""});
        }
);

イベント発生時のWebhookを設定をする

何かしらの通知をしたいイベントが発生したときにNode.jsサーバにリクエストを飛ばします。

今回はGitLabのWebhooksでPush eventsが発生したときにNode.jsサーバにリクエストを飛ばすようにします。

この部分を応用してイベント発生時にNode.jsのサーバにhttpリクエストを飛ばせば、リアルタイムで通知ができるようになるはずです!!

ykyk1218
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away