DartでTwitterのStreaming APIに接続してみた
結果
出来た。
技術的な話
別にそこまで技術的な話があるのかと言われるとないです。
//接続部分 //OAuthで接続する(?)用のインスタンスを作成。鍵とかつくってる部分はコード読んで var streamClient = new oauth.Client(oauthToken); //Streaming APIのエンドポイント Uri uri = Uri.parse("https://userstream.twitter.com/1.1/user.json"); //リクエストを生成 var request = new http.Request("GET", uri); //リクエストを送信。 var response = await streamClient.send(request); //来たレスポンスをStream<String>にしてる。 displaytweet(response.stream.toStringStream()); // ツイート表示部分 Future<String> displaytweet(Stream<String> tweets) async { await for (var tweet in tweets) { //ここでtryをやってるのは、JSONのデコードに失敗する可能性があるから。この辺もホントは適切な処理してあげなきゃいけない。 try { var map = JSON.decode(tweet); if (!map.containsKey("delete")) { print(map["user"]["name"] + " " + map["text"]); } } catch (e) { print(e); } } return ""; }
はてなブログはDartのシンタックスハイライトにいい加減対応してくれ。頼む。
(今はjavascriptで代用)
Dartチームがつくってるパッケージでhttpっていうのがあって、それを利用したoauthっていうパッケージを使ってる。正直詳しく解説しても日本でDartかいている人が殆どいないので無駄な気がするし、気になる人はコードを読むかコメント欄で教えて下さい。
問題はいくつかあって、Streamで飛んでくるデータがかならずしもJson単位じゃない(途中で途切れててJSON.decodeするとエラーが吐かれる)から、その辺を上手くくっつけて渡してあげるプログラムを書いてあげなきゃいけないってこと。これはtwitter.dartをstreaming APIを対応させる時に書こうと思ってる。
ただ、ちゃんとTwitter Streaming API に接続できるとわかったのはよかった。時間があるときにちゃんとライブラリにも対応させようと思う。
(受験生なのになんでこんな記事書いてるんだろう)
9/26追記
Fix Stream Parse Program · sh4869/dart_twitter_stream_test@e11ff05 · GitHub
直せました。byteStreamで受け取った時に必ずしもJsonごととは限らないのが原因だったので、普通につなぎ合わせる工夫をすればよかったんだけど、こんなことにめっちゃ時間がかかってしまった。悲しい。まあ何はともあれ使えるようになったので、これでupdate_nameも作れるね、やったね。
ポエム
高校3年生になり、ついに大学受験のための勉強をはじめざるを得なくなってしまった。
私はもともとコツコツとなにかをするということが苦手であり、もちろん勉強をする習慣なんてなかったため、三年間こつこつ真面目にやってきた優秀な人達に追いつくために夏休みのかなりの時間を受験勉強に割くことになった。普通の高校生なら当たり前なんだろうけど。
私が通っている学校は少しだけ普通の学校とは違う活動をしている人が多いため、推薦やAOで大学を決める人が多い。二年の終わりまでは私自身そうやって進路を決めていこうかと思っていたのだけれど、一番行きたい大学の推薦がとても厳しいということを去年の結果から知ったので、一般で行くしかないと覚悟を決めた。
夏休みに入ってからの勉強の進捗具合は悪くはない。一番自分が問題として抱えているのが、休日と平日のやる気の差だ。
平日は所謂夏期講習をとっているため、そこにある自習室などを活用して、それなりに勉強出来ているとは思うのだが、休日になるととつぜん気が抜けてしまい、家の机の前で魂を抜かれたようにぼーっとする時間が多く、休日の勉強時間は皆無と言っていいほどである。
もともとONとOFFの切り替えが苦手な人間なのだけれど、これだとマズイ気がする。というかマズイ。百合CPについて考えていたら大学落ちましたなんて、そんなに面白くもないし洒落にならない。なんとかしないと。アイマス百合の沼の深さがいけないのかもしれない。
結論
アイマスが悪い。
twitter.dartを作った
前々からつくろうと思っていたことを思い出して作った。
現状ちょっと使いやすいというだけでこれライブラリである意味あるか?みたいなところがあるのでいろいろ改善していきたいとおもってる
- エラー処理
現状DartTeamの公式パッケージであるhttpのhttp.BaseClientを継承して作られたoauth.dartを継承して作っているだけなので、返ってくるのがhttp.Responseクラスなので、twitter.dartを使いたい人はエラー判定とかも帰ってきたresponseのstatusCodeとか使って自分でやらなきゃいけないという欠点があるので、ライブラリ側でエラーを投げられるようにしたい。
- レスポンスのデータのクラスを作製する
こういう表現が正しいのかわからないが、今の段階だとtwitter.dartを使ってTwitterクライアント作ろうとか思っている人はレスポンスのbodyを読んでそれを自作のtweet classに代入して…みたいなことをやらなければいけないので、こちらでサポートしてしまいたい。
この夏受験生ということもありかなり忙しくなるのでちゃんと出来るかどうかわからないけれど、出来るだけ自分で直していけるようにしたい。
C++でWebsocketを扱う
知見を得たが使わなくなってしまったのでここで供養する。
Websocketpp
C++でWebsocket用のライブラリには、boost::asioがベースとなったwebsocketppがある。
boost::asioを使ったことがある方なら比較的簡単に扱うことが出来ると思う。
使うためにはboostが必要である。ubuntuなら
apt-get install libboost-dev
あたりをやれば入ると思う.
コンパイルオプションに -lboost_system -I websocketpp/
あたりをつければ動くと思われる。
websocket_client.hpp
#ifndef WSCLIENT_WEBSOCKET_CLIENT_HPP #define WSCLIENT_WEBSOCKET_CLIENT_HPP #include <websocketpp/config/asio_client.hpp> #include <websocketpp/client.hpp> #include <string> typedef websocketpp::client<websocketpp::config::asio_client> client; using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; using websocketpp::lib::bind; typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; class websocket_client { typedef websocket_client type; public: websocket_client(std::string uri); void connect(); void start(); void send(std::string meesage); const std::string get_status(); const std::string get_message(); protected: void on_open(websocketpp::connection_hdl hdl); void on_message(websocketpp::connection_hdl hdl,message_ptr msg); void on_close(websocketpp::connection_hdl hdl); private: client m_client; websocketpp::connection_hdl m_hdl; std::string m_status; std::string m_url; std::string m_msg; bool m_is_connect; }; #endif
websocket_client.cpp
#include "websocket_client.hpp" #include <websocketpp/config/asio_client.hpp> #include <websocketpp/client.hpp> #include <string> #include <iostream> typedef websocketpp::client<websocketpp::config::asio_client> client; using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; using websocketpp::lib::bind; typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr; websocket_client::websocket_client(std::string uri){ // set url m_url = uri; m_client.set_access_channels(websocketpp::log::alevel::all); m_client.set_error_channels(websocketpp::log::elevel::all); //Initialize ASIO m_client.init_asio(); //Register our Handler m_client.set_open_handler(bind(&type::on_open,this,::_1)); m_client.set_message_handler(bind(&type::on_message,this,::_1,::_2)); m_client.set_close_handler(bind(&type::on_close,this,::_1)); //m_hdl is null in first //Set client status value m_status = "none"; m_msg = ""; m_is_connect = false; } void websocket_client::connect(){ websocketpp::lib::error_code error_code; client::connection_ptr con = m_client.get_connection(m_url, error_code); if(error_code){ m_client.get_alog().write(websocketpp::log::alevel::app,error_code.message()); } //Save connection hdl from connection_ptr m_hdl = con->get_handle(); m_client.connect(con); m_status = "connect"; m_is_connect = true; } void websocket_client::start(){ if(!m_is_connect){ connect(); } m_client.run(); } void websocket_client::on_open(websocketpp::connection_hdl hdl){ m_status = "open"; send("test"); } void websocket_client::on_message(websocketpp::connection_hdl hdl,message_ptr msg){ m_msg = msg->get_payload(); std::cout << m_msg << std::endl; } void websocket_client::on_close(websocketpp::connection_hdl hdl){ m_status = "close"; } void websocket_client::send(std::string message){ if(m_is_connect){ try{ m_client.send(m_hdl,message,websocketpp::frame::opcode::text); } catch (const websocketpp::lib::error_code & e){ std::cout << e.message() << std::endl; } catch (...){ std::cout << "nanika okiteru " << std::endl; } } } const std::string websocket_client::get_status(){ return m_status; } const std::string websocket_client::get_message(){ return m_msg; }
詳しい説明みたいなのは今度追記する