TypeScript + Node.js + expressでGyazoサーバを作った

f:id:atdxfe:20140122145909p:plain
いい感じにスクリーンショットが撮れる

Gyazoは、スクリーンショットを共有するためのツール。
Gyazo - Gyazoへようこそ : スクリーンショットの瞬間共有
撮影したスクリーンショットは自動的にgyazo.com上へアップロードされるけど、URLは128bitのハッシュ値(MD5)で公開されるから、URLを知っている人にしかまず見えませんよ、ということになっている。

このGyazo、ソースが公開されており、サーバを設置してプライベートGyazoサーバを構築することが出来る。
せっかくなので、今回は最近使っているTypeScript(0.9.5) + Node.js + expressの構成で自作してみることにした。

shidasan/gyazo-server-typescript · GitHub

以下、ソース。

///<reference path='./d.ts/node/node.d.ts'/>
///<reference path='./d.ts/express/express.d.ts'/>

import express = require('express');
import http = require('http');
import fs = require('fs');
import path = require('path');
import crypto = require('crypto');

var CONFIG = require('config');

POSTで受け取ったファイルのハッシュをURLに用いる仕様はそのままとしたので、cryptoを使っている。

var app = express();
app.configure(function () {
    app.set('port', process.env.PORT || 3000);
    app.use(express.static(path.join(__dirname, CONFIG.Files)));
    app.use(express.bodyParser({ uploadDir: CONFIG.Files }));
});

アップロードされたファイルは/config以下のyamlに書かれたパスに保存される。

app.post('/upload', function(req, res) {
    var sourcepath = req.files.imagedata.path;
    var md5 = crypto.createHash('md5');
    
    var s = fs.createReadStream('./' + sourcepath);
    s.on('data', function(d) {
        md5.update(d);
    });
    
    s.on('end', function() {
        var digest = md5.digest('hex');
        var targetpath = CONFIG.Files + digest + '.png';
        fs.rename(sourcepath, targetpath, function(err?) {
          if (err) {
            throw err;
          }
          res.send('http://' + CONFIG.Host + '/' + path.basename(targetpath));
        });
    });
});

express.bodyParserを使用すると、アップロードされたファイルのステータスをreq.filesから取得することができる。
ファイルのハッシュをMD5で計算し、req.files.imagedata.pathで定義された古いファイル名から、ハッシュ値にリネームをする。
レスポンスにはURLを返せば、Gyazo Clientが自動的にブラウザで開いてくれる。

効果

アップロードされたスクリーンショットを直接DropBoxなどで管理することも出来るようになった

2014.1.22追記

クライアントは本家そのままです。その際は、ホスト等の設定を変更する必要があるので注意が必要。
gyazo/Gyazo · GitHub

2014.1.22さらに追記

上記の例はGitHubへのInitial Commit時のコード*1
これ以降、Twitter Cards対応のためのviewの定義など行っている。

*1:ac3b47ec6b46f3713f1c26540cba813affc6415e