RustでTwitterAPIを叩く

目的

Twitterを監視するバッチ、厳密に言うと「自分のツイートを監視して一定のフィルターに該当するものをすべて削除していくバッチ処理」を必要としており、せっかくなのでRustで構築しようと思った

今回のゴール

Twitter-APIをコールするライブラリ自体はすでにCratesに存在している。目的を達成するには、APIが足りていないが、今回はまずこのライブラリをコールするところから始める。

また、利用方法についても基本的にはGoogleでヒットするが、そのまま紹介してもつまらないので以下のような流れを実装する

  1. 認証URLをブラウザで勝手に表示させる
  2. コールバックURLをローカルホストの指定ポートに向くようにしておき、そのURLを処理上で受けられるようにironでオープンしておく
  3. 認証ページで認証したあとのコールバックを、認証URLを開いたプロセス自身で受け取り、取得したアクセストークンを利用してツイートを行う
  4. プロセス自身をすべて破棄して終了

事前準備

プログラム以外に準備するものは以下のとおり

  • Twitter Application Managementでアプリケーションを登録、consumer_key及びconsumer_secretを取得しておくこと
  • 上記アプリケーション登録において、コールバックURLをローカルまたはRustプログラムを起動するサーバーのURLなど、コールバックを受けるURLに正しく設定すること。筆者は、http://127.0.0.1:8943/callbackとした。

利用ライブラリ

Cargo.tomlを参照したほうがわかりやすいように考えたので以下の通りとする

[package]
name = "tweet"
version = "0.1.0"
authors = ["deadcheat"]

[dependencies]
aurelius = "*"
iron = "*"
oauth-client = "0.1.2"
twitter-api = "*"
urlencoded="*"

aureliusがURLをオープンするために利用するcrate

こういうネーミングは正直好みだ。

実装

最新状態はGistにおいておこうと思う

Gist

一応こちらにも貼り付けておく

extern crate twitter_api as twitter;
extern crate oauth_client as oauth;
extern crate aurelius;
extern crate iron;
extern crate urlencoded;

use aurelius::browser;
use iron::prelude::*;
use oauth::Token;
use std::env;
use std::process;
use urlencoded::UrlEncodedQuery;

fn main() {
  let consumer_key    = "your consumer key";
  let consumer_secret = "secret";

  let consumer = Token::new(consumer_key, consumer_secret);
  let request = twitter::get_request_token(&consumer).unwrap();
  let auth_url = twitter::get_authorize_url(&request);
  println!("open the following url:{}", auth_url);

  let _ = browser::open(&auth_url);
  Iron::new(move |req: &mut Request| {
    match req.get_ref::<urlencodedquery>() {
        Ok(ref hashmap) =&gt; {
          println!("Parsed   GET request query string:\n {:?}", hashmap);

          let vec_oauth_verifier = hashmap.get("oauth_verifier").unwrap();
          let oauth_verifier = &amp;vec_oauth_verifier[0];
          println!("oauth_verifier: {:?}", oauth_verifier);

          let access = twitter::get_access_token(&amp;consumer, &amp;request, &amp;oauth_verifier).unwrap();

          // タイムラインの取得
          let tweets = twitter::get_last_tweets(&amp;consumer, &amp;access).unwrap();
          for tweet in tweets {
              println!("{} - {}", tweet.created_at, tweet.text)
          }

          // 引数で与えられた文字列を投稿する
          let args = env::args();
          let mut argv: Vec<string> = args.collect();
          argv.reverse();
          let _ = argv.pop();
          argv.reverse();
          for arg in argv {
              twitter::update_status(&amp;consumer, &amp;access, &amp;arg).unwrap();
          }
        },
        Err(ref e) =&gt; {
          println!("{:?}", e);
          process::exit(1);
        }
    };
    process::exit(0)
  }).http("callback-host:port").unwrap();

}

書いてみてなんだが、コールバックを受け取るためにIronでHTTPサーバーを起動している箇所はもう少しどうにか出来たようにも思う。

また、本筋ではないが、与えられた引数からarg0,つまりコマンド自身を指す文字列を除いた配列を作成するために以下の抜粋のように実施している点も、もう少し良い書き方があったのではと思っている。

let mut argv: Vec<string> = args.collect();
argv.reverse();
let _ = argv.pop();
argv.reverse();

argsをとって逆さまにした後にPOPによってスタックの先頭を抜き出して再度逆さまにする・・・美しくはない

もっとRust力を付けたいところである。

Rustの学習について

基本的には、公式のドキュメントが非常に良く出来ている。

書籍がほしいのだけれども、O'reillyの書籍は10月予定。検索とドキュメントでなんとかしていくしか無いのかもしれない。

Rust Essentialsというペーパーバックも刊行されているが、入り口過ぎるのではと思い手を出せていない。

最後に

Rust言語に興味を持っている方、それ以外にもLaravel、Golang、Elixirなど様々な言語でもくもくしたいエンジニアの皆さんを対象にしたもくもく&ざわざわ会というものを開催するので、ざわざわと話しながらいろいろと作業したいという方はこちらで受け付けているので是非参加してほしい

このブログの人気の投稿

2016年にgoを使ったのでまとめ

採用とは何か

vue-bulmaと太陽と埃の中で