拙作のC言語向けTwitterライブラリT4CはREST APIに加えてStreaming APIもサポートしています。
今回はC言語でどのようにしてStreaming APIをサポートするのか、について書こうと思います。
Streaming APIとは
Streaming APIとは簡単に言うと、リアルタイムに(何らからのEventが発生した場合に)TwitterからレスポンスがかえってくるAPIです。
で、リアルタイムに帰ってくる事に加え、無限にレスポンスが帰ってきます。
よって、通常のGET
リクエストとして処理することはできません。したがって、異なるアプローチをとることにします。
異なるアプローチといっても単純で、タイムアウトを無くして、レスポンスがかえってくるたびにcallback
が呼ばれるようにすればよいのです。
libcurlでタイムアウトをなくすには
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0);
とすればよいのです。
また、コールバックには次のようなものを指定すればそれが、レスポンスがかえってくるたびに呼ばれます。
static size_t streaming_callback_sample(void* ptr, size_t size, size_t nmemb, void* data) {
if (size * nmemb == 0)
return 0;
size_t realsize = size * nmemb;
string* str = (string*)data;
str->length = realsize + 1;
str->value = MALLOC_TN(char, str->length);
if (str->value != NULL) {
memcpy(str->value, ptr, realsize);
strcat(str->value, "\0");
fprintf(stderr, "RECIEVED: %ld bytes\n", realsize);
fprintf(stderr, "[STREAMING API] received -> %s\n", str->value);
}
return realsize;
}
コード
あとは、以前に書いた記事(C言語でTwitter APIをつかって、ツイートしよう! (自前でOAuthを実装する話))のrequest
とほぼ同じような感じで一部、上で書いたことを反映させれば実現できます(重複になるのでstream関数内で用いてる関数などについての説明は行いませんので、詳しくは以前書いた記事を参照してください。)
void stream(T4C* t4c, string url, Parameters* paramsArgument, size_t (*callback)(void*, size_t, size_t, void*)) {
bool paramsArgumentWasNULL = false;
if (paramsArgument == NULL) {
paramsArgument = new_parameters();
paramsArgumentWasNULL = true;
}
Parameters* oauthParams = new_parameters();
genOAuthParams(t4c, oauthParams);
Parameters* params = new_parameters();
buildParams(params, oauthParams, paramsArgument);
string oauthSignature = signature(t4c->consumerSecret, t4c->accessTokenSecret, GET, url, params);
string encodedSignature = url_encode(oauthSignature);
add_parameter(oauthParams, make_string("oauth_signature"), encodedSignature);
add_parameter(params, make_string("oauth_signature"), encodedSignature);
string authorize = new_string();
string authorizeChild = join_parameters(oauthParams, ",");
authorize.length = 21 + authorizeChild.length;
authorize.value = MALLOC_TN(char, authorize.length);
sprintf(authorize.value, "Authorization: OAuth %s", string_get_value(authorizeChild));
string path = join_parameters(params, "&");
if (DEBUG) {
printf("----------------------------\n");
printf("STREAMING API");
printf("URL: %s\n", string_get_value(url));
printf("path: %s\n", string_get_value(path));
printf("authorize: %s\n", string_get_value(authorize));
printf("----------------------------\n");
}
CURL* curl;
curl = curl_easy_init();
string reqURL = new_string();
reqURL.length = url.length + 1 + path.length;
reqURL.value = MALLOC_TN(char, reqURL.length);
sprintf(reqURL.value, "%s?%s", url.value, path.value);
curl_easy_setopt(curl, CURLOPT_URL, reqURL.value);
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, string_get_value(authorize));
curl_easy_setopt(curl, CURLOPT_HEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
free_string(url);
free_string(path);
free_string(authorize);
free_parameters(oauthParams);
free_parameters(params);
if (paramsArgumentWasNULL) {
free_parameters(paramsArgument);
}
}
このようにすればC言語でTwitter UserStreamが受信できます。
以下にT4Cを用いてC言語でUserStreamを受信するコードを書きます
#include <t4c/parameters.h>
#include <t4c/string.h>
#include <t4c/t4c.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
//上に載せたコールバックをここに書く(スペースの関係上省略)
static size_t streaming_callback_sample(void* ptr, size_t size, size_t nmemb, void* data);
int main() {
T4C t4c = {
.consumerKey = make_string("Your Consumer Key"),
.consumerSecret = make_string("Your Consumer Secret"),
.accessToken = make_string("Your AccessToken"),
.accessTokenSecret = make_string("Your AccessTokenSecret")
};
stream(&t4c, make_string("https://userstream.twitter.com/1.1/user.json"), NULL, streaming_callback_sample);
}
また、T4CのREADMEにも書きましたが、/statuses/filter.json
のような引数をとるAPIも使うことができます。そちらはT4CのREADMEを参照してください。