Mastodon を Node.js で遊んでみる

# Mastodon
にわかに話題になっている Twitter っぽいサービス。
昨日(2017-4-12)あたりから急に話題になりはじめていて、自分もちょっと気になったので [pawoo.net](https://pawoo.net/@albno273) と [mstdn.jp](https://mstdn.jp/@albno273) にアカウントを作成しました。
またライブラリも豊富で、Ruby / Python / JavaScript / Node.js / Elixir 版が公式のドキュメントにリンクされています。

[Python でやってみた方](http://qiita.com/ignis_fatuus/items/f4b7213ad887af2cf71c)が既にいらっしゃったので、自分は Node.js で Toot するまでやってみました。

# 環境
macOS Sierra 10.12.4
Node.js v7.9.0

# やってみる
ツイートするまでには、

1. ``client_id`` と ``client_secret`` を取得する
2. それを基に Authorization Url を生成する
3. アクセスして取得した Authorization Code から Access Token を生成する
4. それを基に Toot

という流れを踏みます。
のですが、1〜3 については [Mastodon API Client Library - GitHub](https://github.com/vanita5/mastodon-api) の example で一発なので、実質2ステップです。

## アクセストークンの取得
まず前述のライブラリを

```bash
npm install --save mastodon-api
```

でインストール。
この中にある [authorization.js](https://github.com/vanita5/mastodon-api/blob/master/examples/authorization.js) をちょっといじって使います。デフォルトだと mastodon.social に向かうのですが、.social は人が多すぎて新規登録を停止しており、~~さらに .jp は諸事情([後述](http://qiita.com/albno273/items/eb109820125faf7638cd#%E8%A9%B0%E3%81%BE%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%93%E3%82%8D))でうまくいかなかったので、~~.io からトークンを取得しています。

```js:auth.js
const readline = require('readline')
const Mastodon = require('./node_modules/mastodon-api/lib/mastodon.js')

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
})

let clientId
let clientSecret

const baseUrl = 'https://mstdn.io'

Mastodon.createOAuthApp(baseUrl + '/api/v1/apps', 'testapp', 'read write follow')
    .catch(err => console.error(err))
    .then((res) => {
        console.log('Please save \'id\', \'client_id\' and \'client_secret\' in your program and use it from now on!')
        console.log(res)

        clientId = res.client_id
        clientSecret = res.client_secret

        return Mastodon.getAuthorizationUrl(clientId, clientSecret, baseUrl)
    })
    .then(url => {
        console.log('This is the authorization URL. Open it in your browser and authorize with your account!')
        console.log(url)
        return new Promise((resolve) => {
            rl.question('Please enter the code from the website: ', code => {
                resolve(code)
                rl.close()
            })
        })
    })
    .then(code => Mastodon.getAccessToken(clientId, clientSecret, code, baseUrl))
    .catch(err => console.error(err))
    .then(accessToken => {
        console.log(`This is the access token. Save it!\n${accessToken}`)
})
```

実行すると、

```
This is the authorization URL. Open it in your browser and authorize with your account!
https://mstdn.io/oauth/authorize?redirect_uri=(略)
Please enter the code from the website: 
```

と出るのでアクセスします。

![スクリーンショット 2017-04-13 20.45.36.png](https://qiita-image-store.s3.amazonaws.com/0/163084/c0bec44a-5e72-df59-10d6-2d6226442db8.png)

この画面の "AUTHORIZE" を押すと文字列が出てくるので、コンソールに入力するとアクセストークンを取得することができます。

## Toot する前にタイムラインを取得してみる
[node-mastodon](https://github.com/jessicahayley/node-mastodon) を ``npm install --save mastodon`` でインストール。

```js:timeline.js
var Masto = require('mastodon')

var M = new Masto({
    access_token: 'とーくん',
    timeout_ms: 60 * 1000,
    api_url: 'https://mstdn.io/api/v1/',
})

M.get('timelines/public', function(err, data, res) {
    if(!err)
        for (key in data)
            console.log(data[key].content.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, ''))
})
```

みんなのトゥートがベロベロと出てきます。
ちなみにトゥート本文は全体がpタグで囲まれていて、中身もHTMLタグが盛りだくさんです。ちょっと使いづらいかも。

## Toot してみる
```js:toot.js
var Masto = require('mastodon')

var M = new Masto({
    access_token: 'とーくん',
    timeout_ms: 60 * 1000,
    api_url: 'https://mstdn.io/api/v1/',
})

M.post('statuses', {status: 'Test from myapp'}, function (err, data, res) {
    if (!err)
        console.log(res)
})
```

![スクリーンショット 2017-04-13 23.04.13.png](https://qiita-image-store.s3.amazonaws.com/0/163084/4bb8c9a6-e802-fc9f-b893-5258314edadd.png)

できました。

## 詰まったところ
~~認証を .jp でやろうとしたのですが、以下のエラーを吐かれてできませんでした。~~

```
{ Error: Hostname/IP doesn't match certificate's altnames: "Host: mastodon.jp. is not in the cert's altnames: DNS:*.gmoserver.jp, DNS:gmoserver.jp"
    at Object.checkServerIdentity (tls.js:199:17)
    at TLSSocket.<anonymous> (_tls_wrap.js:1094:29)
    at emitNone (events.js:86:13)
    at TLSSocket.emit (events.js:188:7)
    at TLSSocket._finishInit (_tls_wrap.js:610:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:440:38)
  reason: 'Host: mastodon.jp. is not in the cert\'s altnames: DNS:*.gmoserver.jp, DNS:gmoserver.jp',
  host: 'mastodon.jp',
```
~~どうやらリクエストしてるドメインと証明書のドメインが違う場合に吐かれるエラーのようです。証明書チェックを無視すれば通るみたいですが、さすがに怖くてできず。~~
~~というか .jp ってお名前.com使ってるんですね。~~

[2017-4-14 追記]
ドメイン名を勘違いしていました……！すみません。
正しいドメインは mstdn.jp です。認証が通ることも確認しました。

いろんなニュースサイトで話題になったせいでユーザが大量に流入してるようですし、メールサーバもパンク寸前(今日(2017-4-13)の16時ごろ登録したのですが、登録確認メールが届くまでに40分かかりました)のようなので、なかなか個人レベルでインスタンスをもつのは大変そうです。
とはいえ面白いサービスだと思うので、これからどんどん発展してほしいです。

(ひとりぼっち惑星みたいにはならないよな……)

[2017-4-19 追記]
さくらクラウドに移転してサクサクになりましたね！今後が楽しみです。