年度の切り取り線

幼稚園の頃、「平成**年度」っていう単語を聞いて、じいちゃんがやっていた陶芸(=粘土)とはどういう関係があるのか一生懸命考えていました。玲です。
そんな幼稚園時代はもう15年以上前で、ちょうど10年前は小学6年生だと思うとなんだか時間の流れの早さに背筋が冷えます。腰痛が悪化するよ。

ちょうど去年の今日に初めて家族とともに豊橋の地を踏んで(オープンキャンパスとかは一切行かなかったから)、寮で暮らすための諸々を買い込んで親と居酒屋で酒を飲んでいました。
私は成人して1年経ってなかったし、まして親の励ましともお節介ともとれるような話に生返事をしていたせいか、そんなに飲んでいなかったのに翌日ひどい腹痛に襲われて、涙目になりながら寮の部屋の整理をしていたことがつい昨日のように思い出されます。ちょっと誇張したけど。

そして明日で、大学に入ってから、そして一人暮らしを初めて1年が経つようです。ぶっちゃけ、感慨はないです。今は感慨よりも、流れ出る鼻水が早く止まってくれと思わずにはいられない(笑)。

でもまぁ、料理もできず、まして親元から離れて暮らしたこともなかったような人間が、ポンと放り出されてもなんとかやっていけるもんだなぁとは思ったりします。相変わらず料理する時は肉をできるだけまな板で切らないように冷凍してから叩き割ったりとか(ワイルドだろぅ?)、青菜は調理がめんどくさそうだから買わないとかバカなことばっかりしてますけど、私はスロースターターだし、健康面でも十二指腸潰瘍が再発した以外に悪いところはひとまず無さそうなので、うまくやっていけてるんだろうと思うことにしてます。

むしろ、私が一人でのらりくらりと暮らしているよりも、親のほうが心配ですね。私が親元を離れてホームシックになるならまだ話は分かるんですが、どうやらその逆だったようで。
私は「ドラ息子一人いなくなって清々するでしょ」くらいに思っていたんですが、親というのはなんというか、うん…うまく言えないですが、とりあえず愛されてたんだなと先日帰省した時に感じました。親孝行しないとな。

とりあえず新年度の目標は

  • 研究を頑張る
  • お金を稼ぐ(ほどほどに)
  • 少しは健康に気を配る

といったところでしょうかね。まぁマイペースが取り柄?なので、今年度ものらりくらりとやっていきたいと思います。

ではでは。

Twitter4CでシンプルなUserStream対応クライアントを作る

現在公開しているC言語でTwitter APIを扱うライブラリ「Twitter4C」にはリクエストトークンとアクセストークンの取得、そしてツイートの機能が付いています。
しかし、それだけではなんだか面白味に欠けるので、Twitter4CのマイナーアップデートのついでにUserStream APIにアクセスしてタイムラインを取得して表示するプログラムを作ってみたいと思います。

4/1追記:Github上に公開しました。Twitter公式認定は嘘ですが動作は本当です(笑)
https://github.com/Plemling138/Twitter4C_UserStream

Outline

  • twilib.cにUserStream API接続用関数を追加
  • session.cでJSONファイルを受信
  • JSONから必要な情報を抜き出して表示

本来は通信とJSONパースを並行してやるところですが、今回は簡単にするために受信バッファを適当なタイミングでパース関数に渡して表示させています。再接続もしません。接続の切断?Ctrl+Cで(殴

Twitter4Cの変更

まずはUserStream APIに接続するための関数を作ります。Twitter4C_UpdateStatusをテンプレートとして、リクエスト部分を改変していく感じです。

UserStream APIのURLはhttps://userstream.twitter.com/2/user.jsonなので、ここに対してリクエストを投げます。メソッドがGETなので署名生成とリクエスト部分がごっそり変わってたりします。

また、上のコードに関する定義をtwilib.hに追加します。

続いてsession.cの改変に移ります。user.jsonに接続すると、ツイートのJSONファイルが切断するまで永遠に送りつけられてきます。ただし受信データは細切れなので、適当な区切り(改行コード)が含まれるまでバッファに追加し続けています。
また、セッションが切断されないように変な数字?が送られてきたりするので、10バイト以下の受信データは連結せずに捨てるような処理にしています。

区切り文字を検知するとJSONのパースに移りますが、もしバッファを超えるような場合は解析対象とせずにそのまま捨てるような処理になっています。経験値で言うと8KB程度あればだいたいのツイートは読めますが、JSONに付随してくる情報が多いとこれを超えることが割とあります。

引き続きJSONパース部分を見てみましょう。JSONのパースには「Parson」を使用しますので、適宜ダウンロードしてparson.cとparson.hをコピーしておいてください。今回は通常のツイートと何らかのアクション(特にFavorite)を表示させます。

最後にmain関数の変更を行います。引数のチェック部分とUpdateStatusの部分を以下のように変更します。

 

ここまで変更すればひとまず完成です。あとはMakefileにparson.cを追加してビルドすれば、ユーザストリーミング対応のクライアントが完成します。

実際に動作させるとこんな感じになります(緑色の四角は私のサブ垢名)。この時はちょっと急いでバグフィックスしたせいで取りこぼしたりが起きたりしてますが、一応表示はうまくできているようです。
ss1

というわけで、Twitter4CでもUserStreamできたよ!っていうお話でした。ちゃんちゃん。

References   [ + ]

1. char *)STREAM_HOSTNAME, reqheader, buf); return 0; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
int Twitter_ConnectUserStream(struct Twitter_consumer_token *c,  struct Twitter_access_token *a)
{
  char buf[BUF_SIZE] = {''};
 
  char oauth_signature_key[100] = {''};
 
  struct timeval tv;
  char tstamp[20] = {''};
 
  char nonce_tmp[20] = {''};
  char nonce[20] = {''};
  char nonce_urlenc[20] = {''};
 
  char auth_tmpmsg[300 + TWEET_MAX_LENGTH] = {''};//Temporary message for HMAC-SHA1
  char auth_encmsg[300 + (TWEET_MAX_LENGTH * ENCODED_CHAR_MARGIN)] = {''};//Temporary message for HMAC-SHA1(URL-Encoded)
  char auth_postmsg[350 + (TWEET_MAX_LENGTH * ENCODED_CHAR_MARGIN)] = {''};
  char encstatus[(TWEET_MAX_LENGTH * ENCODED_CHAR_MARGIN)] = {''};
 
  char postmsg[400 + (TWEET_MAX_LENGTH * ENCODED_CHAR_MARGIN)] = {''};//POST Header
  char reqheader[460 + (TWEET_MAX_LENGTH * ENCODED_CHAR_MARGIN)] = {''};//POST Header
 
  char hmacmsg[40] = {''};
  char b64msg[40] = {''};
 
  char b64urlenc[50] = {''};
 
  int i = 0;
 
  //Signature Key
  sprintf(oauth_signature_key, "%s&%s", c->consumer_secret, a->access_secret);
 
  //Get date, set as timestamp
  gettimeofday(&tv, NULL);
  sprintf(tstamp, "%ld", tv.tv_sec);
 
  //Set OAuth Nonce
  sprintf(nonce_tmp, "%ld", tv.tv_usec);
  base64_encode(nonce_tmp, strlen(nonce_tmp), nonce, 128);
  URLEncode(nonce, nonce_urlenc);
 
  //Generate OAuth Post message
  sprintf(auth_tmpmsg, "%s%s&%s%s&%s%s&%s%s&%s%s&%s%s", OAUTH_CONSKEY, c->consumer_key, OAUTH_NONCE, nonce_urlenc, OAUTH_SIGMETHOD, HMAC_SHA1, OAUTH_TSTAMP, tstamp,  OAUTH_TOKEN, a->access_token, OAUTH_VER, OAUTH_VER_NUM);
  URLEncode(auth_tmpmsg, auth_encmsg);
  sprintf(auth_postmsg, "%s&%s&%s", MSG_GET, USER_STREAM_ENCODED_URL, auth_encmsg);
 
  //Generate OAuth Signature
  hmac_sha1(oauth_signature_key, strlen(oauth_signature_key), auth_postmsg, strlen(auth_postmsg), hmacmsg);
 
  //Count Singnature length
  i=0;
  while(i<300) {
    if(hmacmsg[i] == 0 && hmacmsg[i+1] == 0 && hmacmsg[i+2] == 0) break;
    i++;
  }
 
  //Encode Signature text by BASE64, also URL Encode
  base64_encode(hmacmsg, i, b64msg, 128);
  URLEncode(b64msg, b64urlenc);
 
  //Generate POST Message
  sprintf(postmsg, "%s"%s", %s"%s", %s"%s", %s"%s", %s"%s", %s"%s", %s"%s"", OAUTH_CONSKEY, c->consumer_key, OAUTH_NONCE, nonce_urlenc,  OAUTH_SIGMETHOD, HMAC_SHA1, OAUTH_TSTAMP, tstamp, OAUTH_TOKEN, a->access_token, OAUTH_VER, OAUTH_VER_NUM, OAUTH_SIG, b64urlenc);
 
  sprintf(reqheader, "GET %s %srnHost: %srnAuthorization: OAuth %srnrn", USER_STREAM_URL, HTTP_VER, STREAM_HOSTNAME, postmsg);
  printf("%s", reqheader);
 
  //SSL Session
  SSL_send_and_recv((char *)STREAM_HOSTNAME, reqheader, buf);
 
  return 0;
}

また、上のコードに関する定義をtwilib.hに追加します。

続いてsession.cの改変に移ります。user.jsonに接続すると、ツイートのJSONファイルが切断するまで永遠に送りつけられてきます。ただし受信データは細切れなので、適当な区切り(改行コード)が含まれるまでバッファに追加し続けています。
また、セッションが切断されないように変な数字?が送られてきたりするので、10バイト以下の受信データは連結せずに捨てるような処理にしています。

区切り文字を検知するとJSONのパースに移りますが、もしバッファを超えるような場合は解析対象とせずにそのまま捨てるような処理になっています。経験値で言うと8KB程度あればだいたいのツイートは読めますが、JSONに付随してくる情報が多いとこれを超えることが割とあります。

引き続きJSONパース部分を見てみましょう。JSONのパースには「Parson」を使用しますので、適宜ダウンロードしてparson.cとparson.hをコピーしておいてください。今回は通常のツイートと何らかのアクション(特にFavorite)を表示させます。