トップ «前の日記(2008-02-10) 最新 次の日記(2008-02-12)» 編集

Route 477



2008-02-11

[biwascheme] JSONPを実装した

動機

twitterクライアントを書きたいので、クライアントのみで行うならJSONPが必要。

JSONP?

普通のAjaxはhtmlと同じドメインにしか接続できないため、twitter.comを見に行けない。

そこで、以下のようなscriptタグを動的に生成する。

<script src="http://twitter.com/statuses/friend_timeline.json?callback=recieve_json"></script>

さらに、受け側となる関数を用意する。

function recieve_json(data){
  //dataを利用した処理
}

twitterのサーバは、callback=(関数名)のような引数があると通常のJSONの代わりに以下のようなデータを返す。

recieve_json([{user: "yhara", ...}]);

これはJavaScriptの関数呼び出しになっている。

さてどうするか

Scheme側のAPIを考える。

(print (recieve-jsonp url))

とかやりたいよねw

receive-jsonpが2つ同時に呼ばれなけば、WebScheme.receive_jsonp みたいな受け皿を用意するだけで良さそう。

じゃあ2つ同時に呼ばれたらどうするか。 例えば、イベントハンドラの中にreceive_jsonpがあって、 ボタンが押されるたびに違うURLのJSONPを取りに行くとか。

(add-handler! ($ "run") "click"
  (print (receive_jsonp (get-content ($ "url")))))
;; ↑ちなみにこれはjquery風に書くとこういう意味だよ
;; $("run").click(function(){
;;   receive_jsonp($("url").text,
;;                 function(data){ print(data); });
;; }

これだと、WebScheme.receive_jsonpがどっちの継続を実行したらいいのか分からんくて困る。

案1

関数名を動的に増やす。WebScheme.receive_jsonp_1, WebScheme.receive_jsonp_2 ... みたいに。

いや、WebScheme.jsonp_receiver[0], WebScheme.jsonp_receiver[1], ... でもいいのか。 twitterのJSONPの関数名って記号使えるのかな。

試してみた

「.」も「[」もOK。というわけで案1を採用。うまく動いているようだ。

あとjsonはScheme側から見るとVector+Objectとかで使いにくいので、これをリスト+alistに変換する関数json->sexpを書いた。

[biwascheme] BiwaSchemeでtwitterビューアを実装しました

twitter にログイン中であることを確認して、以下のページを開いてみてください。

ソースはこんなかんじ。結構、短くね?

<script src="../lib/biwascheme.js">
;; access twitter
(define (get-timeline type)
  (json->sexp (receive-jsonp (string-append "http://twitter.com/statuses/" type "_timeline.json"))))

;; class user
(define (screen-name-of user)   (cadr (assoc "screen_name" user)))

;; class post 
(define (text-of post)    (cadr (assoc "text" post)))
(define (date-of post)    (parse-date (cadr (assoc "created_at" post))))
(define (user-of post)    (cadr (assoc "user" post)))
(define (screen-name post) 
  (screen-name-of (user-of post)))

(define (describe-post post)
  (print (date->string (date-of post) "~T") 
         ": "
         "<" (screen-name post) "> "
         (text-of post)))

(define (reload-timeline)
  (element-update! ($ "bs-console") "loading...")
  (let1 timeline (get-timeline "friends")
    (element-empty! ($ "bs-console"))
    (for-each describe-post timeline)))

(add-handler! ($ "reload") "click" reload-timeline)
(reload-timeline)
</script>

JSONPなんで、全てクライアント側(BiwaScheme)のみで実装してます。twitter.com以外のサーバには接続してませんよ。

めんどさを軽減するために、srfi-19の時間関係の関数とか、prototype.jsのElement.* の一部を実装した。

IEだけ日付がバグるのは、Date.parse("Mon Feb 11 02:50:33 +0000 2008") が失敗するせい。 そのうち直す。(date->stringは実装したけどstring->dateはまだ^^;)