とりあえず statuses/sample を持ってくる

pingpong003ワークショップ@公立はこだて未来大学」に参加したのがきっかけで,「#ppfun」というハッシュタグを付けたつぶやきを流すアプリケーションをひそかに作っています.


そこで見つけたのがこれ,TwitterStreaming APIをいじってみました.
キーワードやユーザIDなどでつぶやきにフィルタをかけて,リアルタイムに取得できるみたいです.
Twitter クライアントというよりは,つぶやきを流し続けたり,蓄積して分析したりするような使い方をするならとっても適しているような気がします.


まだ直さないといけないところが残っていますが,とりあえず statuses/sample からつぶやきとニックネームを取得して出力するものを公開します.
statuses/filter を使ったものももうすぐ公開します.


今回お世話になったみなさん,とてもとても感謝です.

[追記]
isLimit 関数ですが,delete が来るおは受け取ったステータスに欠落部分がある時でしたね.

#include <iostream>
using namespace std;

#include "./curl/curl.h"
#include "./babel/babel.h"
#include "./picojson.h"
using namespace picojson;

#define CR 13
#define LF 10

struct MemoryStruct
{
    char *memory;
    size_t size;
};

bool
isLimit(value *pv)
{
    value obj = pv->get("delete");
    if (obj == NULL)
        return false;
    else
        return true;
}

static void
*myrealloc(void *ptr, size_t size)
{
    /* There might be a realloc() out there that doesn't like reallocing
    NULL pointers, so we take care of it here */
    if(ptr)
        return realloc(ptr, size);
    else
        return malloc(size);
}

static size_t
WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, MemoryStruct *data)
{
    size_t realsize = size * nmemb;

    data->memory = (char *)myrealloc(data->memory, data->size + realsize +  1);
    if (data->memory)
    {
        memcpy(&(data->memory[data->size]), ptr, realsize);
        data->size += realsize;
        data->memory[data->size] = 0;
    }
    
    //  picojson
    if (CR == data->memory[data->size-2] && LF == data->memory[data->size-1])   //  Parsing Responses
    {
        value v;
        string err;
        parse(v, data->memory, data->memory + data->size, &err);
        
        if (isLimit(&v))    //  Track Limiting
        {
            exit(0);    //  cleanup してない
        }

        if (err.empty())
        {
            const string key("usr");
            object obj = v.get<object>();
            value  usr = v.get("user");

            object obj_usr = usr.get<object>();
            string screen_name(obj_usr["screen_name"].to_str());
            string text(obj["text"].to_str());
            cout << screen_name << ": " << babel::utf8_to_sjis(text) << endl;

            data->memory = NULL;
            data->size   = 0;
        }
    }

    return realsize;
}

int
main(int argc, char **argv)
{
    // babel
    babel::init_babel();    

    // cURL
    CURL *curl_handle;
    CURLcode res;
    struct MemoryStruct chunk;

    chunk.memory=NULL; /* we expect realloc(NULL, size) to work */ 
    chunk.size = 0;    /* no data at this point */ 
    curl_handle = curl_easy_init();

    curl_easy_setopt(curl_handle, CURLOPT_PROXY, "192.168.0.1:8080");
    curl_easy_setopt(curl_handle, CURLOPT_PROXYUSERPWD, "PROXY_USER_NAME:PROXY_PASSWORD");
    curl_easy_setopt(curl_handle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY);
    curl_easy_setopt(curl_handle, CURLOPT_USERPWD, "TWITTER_ID:TWITTER_PASSWORD");

    if(curl_handle)
    {
        curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/sample.json");

        /* send all data to this function  */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

        /* we pass our 'chunk' struct to the callback function */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

        res = curl_easy_perform(curl_handle);

        /* always cleanup */ 
        curl_easy_cleanup(curl_handle);
    }
    return 0;
}

さて,libcurl や picojson をもっと上手に使えるように勉強しなくちゃ_〆(・・o)