Return-Path: X-Original-To: apmail-couchdb-dev-archive@www.apache.org Delivered-To: apmail-couchdb-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 634D9C786 for ; Wed, 16 May 2012 05:45:22 +0000 (UTC) Received: (qmail 75602 invoked by uid 500); 16 May 2012 05:45:21 -0000 Delivered-To: apmail-couchdb-dev-archive@couchdb.apache.org Received: (qmail 75554 invoked by uid 500); 16 May 2012 05:45:21 -0000 Mailing-List: contact dev-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list dev@couchdb.apache.org Received: (qmail 75542 invoked by uid 99); 16 May 2012 05:45:21 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 May 2012 05:45:21 +0000 X-ASF-Spam-Status: No, hits=-0.7 required=5.0 tests=RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of bchesneau@gmail.com designates 209.85.217.180 as permitted sender) Received: from [209.85.217.180] (HELO mail-lb0-f180.google.com) (209.85.217.180) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 May 2012 05:45:13 +0000 Received: by lbbgh12 with SMTP id gh12so343154lbb.11 for ; Tue, 15 May 2012 22:44:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; bh=vwyYgWUKEAlbpbIh8h1byYaYcydetjqm+qFyXtTj5Co=; b=v7rAFfh65qdMa3A44JU+MuZ5uPfmhZRfaQpX1z75DgaO5nNLenmU8XlXLqKNhhI4es QZm36osHO4DPHRnN+6SD9tky2OMbbn2AvzhoOgvHD3vyaXEdyPTcBo096eUD82p9xcq6 v79VlTemcIwkDPRZXjGOalI1/9V2phGcIwLsWDs1OVPl0n8c8RrQ6Tqm+f6D3X1+EU8z A1mFhS86iA4vkGebSVtEwQTOMOEhYeoAIpmi57mfWE5yLlMFojxoRBfg/scBYrVS4beb PhEhpGMneTXqbq8c6jPvRh7D4V06RObF6dFCi/ihlI+Nhfo3X2oe2kqF3q/ihiXIgLDP ixfg== MIME-Version: 1.0 Received: by 10.152.148.199 with SMTP id tu7mr1496648lab.43.1337147092731; Tue, 15 May 2012 22:44:52 -0700 (PDT) Received: by 10.112.28.196 with HTTP; Tue, 15 May 2012 22:44:52 -0700 (PDT) In-Reply-To: References: <20120516053615.720C7161E9@tyr.zones.apache.org> Date: Wed, 16 May 2012 07:44:52 +0200 Message-ID: Subject: Re: git commit: add Server-Sent Events protocol to db changes API. close #COUCHDB-986 From: Benoit Chesneau To: dev@couchdb.apache.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Wed, May 16, 2012 at 7:42 AM, Paul Davis w= rote: > That JS test looks broken for JS environments that don't support > EventSource. Notably the CLI test suite but also browsers that don't > implement it. I'd either move the entire test into the conditional or > reimplement it by parsing the actual data sent across. > well there is an if() . Isn't it enough ? - benoit > On Wed, May 16, 2012 at 12:36 AM, =A0 wrote: >> Updated Branches: >> =A0refs/heads/master af7441d8d -> 093d2aa65 >> >> >> add Server-Sent Events protocol to db changes API. close #COUCHDB-986 >> >> This patch add support for the new specification of w3c by adding a new >> feed type named `eventsource`: >> >> http://www.w3.org/TR/2009/WD-eventsource-20090423/ >> >> This patch is based on @indutny patch with edits. >> >> >> Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo >> Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/093d2aa6 >> Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/093d2aa6 >> Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/093d2aa6 >> >> Branch: refs/heads/master >> Commit: 093d2aa6544546a95f6133f1db3c4f4179793f3c >> Parents: af7441d >> Author: benoitc >> Authored: Wed May 16 07:30:19 2012 +0200 >> Committer: benoitc >> Committed: Wed May 16 07:30:19 2012 +0200 >> >> ---------------------------------------------------------------------- >> =A0share/www/script/test/changes.js | =A0 28 +++++++++++++++++++++++++++= + >> =A0src/couchdb/couch_changes.erl =A0 =A0| =A0 15 ++++++++++----- >> =A0src/couchdb/couch_httpd_db.erl =A0 | =A0 24 ++++++++++++++++++++++-- >> =A03 files changed, 60 insertions(+), 7 deletions(-) >> ---------------------------------------------------------------------- >> >> >> http://git-wip-us.apache.org/repos/asf/couchdb/blob/093d2aa6/share/www/s= cript/test/changes.js >> ---------------------------------------------------------------------- >> diff --git a/share/www/script/test/changes.js b/share/www/script/test/ch= anges.js >> index 19e22fd..c529b21 100644 >> --- a/share/www/script/test/changes.js >> +++ b/share/www/script/test/changes.js >> @@ -139,6 +139,34 @@ couchTests.changes =3D function(debug) { >> =A0 =A0 // otherwise we'll continue to receive heartbeats forever >> =A0 =A0 xhr.abort(); >> >> + =A0 =A0// test Server Sent Event (eventsource) >> + =A0 =A0if (window.EventSource) { >> + =A0 =A0 =A0var source =3D new EventSource( >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0"/test_suite_db/_changes?feed=3Deventsource= "); >> + =A0 =A0 =A0var results =3D []; >> + =A0 =A0 =A0var sourceListener =3D function(e) { >> + =A0 =A0 =A0 =A0var data =3D JSON.parse(e.data); >> + =A0 =A0 =A0 =A0results.push(data); >> + >> + =A0 =A0 =A0}; >> + >> + =A0 =A0 =A0source.addEventListener('message', sourceListener , false); >> + >> + =A0 =A0 =A0waitForSuccess(function() { >> + =A0 =A0 =A0 =A0if (results.length !=3D 3) >> + =A0 =A0 =A0 =A0 =A0throw "bad seq, try again"; >> + =A0 =A0 =A0}); >> + >> + =A0 =A0 =A0source.removeEventListener('message', sourceListener, false= ); >> + >> + =A0 =A0 =A0T(results[0].seq =3D=3D 1); >> + =A0 =A0 =A0T(results[0].id =3D=3D "foo"); >> + >> + =A0 =A0 =A0T(results[1].seq =3D=3D 2); >> + =A0 =A0 =A0T(results[1].id =3D=3D "bar"); >> + =A0 =A0 =A0T(results[1].changes[0].rev =3D=3D docBar._rev); >> + =A0 =A0} >> + >> =A0 =A0 // test longpolling >> =A0 =A0 xhr =3D CouchDB.newXhr(); >> >> >> http://git-wip-us.apache.org/repos/asf/couchdb/blob/093d2aa6/src/couchdb= /couch_changes.erl >> ---------------------------------------------------------------------- >> diff --git a/src/couchdb/couch_changes.erl b/src/couchdb/couch_changes.e= rl >> index aec7873..85c9e54 100644 >> --- a/src/couchdb/couch_changes.erl >> +++ b/src/couchdb/couch_changes.erl >> @@ -63,7 +63,8 @@ handle_changes(Args1, Req, Db0) -> >> =A0 =A0 =A0 =A0 put(last_changes_heartbeat, now()) >> =A0 =A0 end, >> >> - =A0 =A0if Feed =3D=3D "continuous" orelse Feed =3D=3D "longpoll" -> >> + =A0 =A0case lists:member(Feed, ["continuous", "longpoll", "eventsource= "]) of >> + =A0 =A0true -> >> =A0 =A0 =A0 =A0 fun(CallbackAcc) -> >> =A0 =A0 =A0 =A0 =A0 =A0 {Callback, UserAcc} =3D get_callback_acc(Callbac= kAcc), >> =A0 =A0 =A0 =A0 =A0 =A0 Self =3D self(), >> @@ -89,7 +90,7 @@ handle_changes(Args1, Req, Db0) -> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 get_rest_db_updated(ok) % clean out any = remaining update messages >> =A0 =A0 =A0 =A0 =A0 =A0 end >> =A0 =A0 =A0 =A0 end; >> - =A0 =A0true -> >> + =A0 =A0false -> >> =A0 =A0 =A0 =A0 fun(CallbackAcc) -> >> =A0 =A0 =A0 =A0 =A0 =A0 {Callback, UserAcc} =3D get_callback_acc(Callbac= kAcc), >> =A0 =A0 =A0 =A0 =A0 =A0 UserAcc2 =3D start_sending_changes(Callback, Use= rAcc, Feed), >> @@ -261,7 +262,9 @@ get_changes_timeout(Args, Callback) -> >> =A0 =A0 =A0 =A0 =A0 =A0 fun(UserAcc) -> {ok, Callback(timeout, ResponseT= ype, UserAcc)} end} >> =A0 =A0 end. >> >> -start_sending_changes(_Callback, UserAcc, "continuous") -> >> +start_sending_changes(_Callback, UserAcc, ResponseType) >> + =A0 =A0 =A0 =A0when ResponseType =3D:=3D "continuous" >> + =A0 =A0 =A0 =A0orelse ResponseType =3D:=3D "eventsource" -> >> =A0 =A0 UserAcc; >> =A0start_sending_changes(Callback, UserAcc, ResponseType) -> >> =A0 =A0 Callback(start, ResponseType, UserAcc). >> @@ -434,7 +437,9 @@ keep_sending_changes(Args, Acc0, FirstRound) -> >> =A0end_sending_changes(Callback, UserAcc, EndSeq, ResponseType) -> >> =A0 =A0 Callback({stop, EndSeq}, ResponseType, UserAcc). >> >> -changes_enumerator(DocInfo, #changes_acc{resp_type =3D "continuous"} = =3D Acc) -> >> +changes_enumerator(DocInfo, #changes_acc{resp_type =3D ResponseType} = =3D Acc) >> + =A0 =A0 =A0 =A0when ResponseType =3D:=3D "continuous" >> + =A0 =A0 =A0 =A0orelse ResponseType =3D:=3D "eventsource" -> >> =A0 =A0 #changes_acc{ >> =A0 =A0 =A0 =A0 filter =3D FilterFun, callback =3D Callback, >> =A0 =A0 =A0 =A0 user_acc =3D UserAcc, limit =3D Limit, db =3D Db, >> @@ -456,7 +461,7 @@ changes_enumerator(DocInfo, #changes_acc{resp_type = =3D "continuous"} =3D Acc) -> >> =A0 =A0 =A0 =A0 end; >> =A0 =A0 _ -> >> =A0 =A0 =A0 =A0 ChangesRow =3D changes_row(Results, DocInfo, Acc), >> - =A0 =A0 =A0 =A0UserAcc2 =3D Callback({change, ChangesRow, <<>>}, "cont= inuous", UserAcc), >> + =A0 =A0 =A0 =A0UserAcc2 =3D Callback({change, ChangesRow, <<>>}, Respo= nseType, UserAcc), >> =A0 =A0 =A0 =A0 reset_heartbeat(), >> =A0 =A0 =A0 =A0 {Go, Acc#changes_acc{seq =3D Seq, user_acc =3D UserAcc2,= limit =3D Limit - 1}} >> =A0 =A0 end; >> >> http://git-wip-us.apache.org/repos/asf/couchdb/blob/093d2aa6/src/couchdb= /couch_httpd_db.erl >> ---------------------------------------------------------------------- >> diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db= .erl >> index de39b9e..0920014 100644 >> --- a/src/couchdb/couch_httpd_db.erl >> +++ b/src/couchdb/couch_httpd_db.erl >> @@ -76,14 +76,23 @@ handle_changes_req1(Req, #db{name=3DDbName}=3DDb) -> >> >> =A0handle_changes_req2(Req, Db) -> >> =A0 =A0 MakeCallback =3D fun(Resp) -> >> - =A0 =A0 =A0 =A0fun({change, Change, _}, "continuous") -> >> + =A0 =A0 =A0 =A0fun({change, {ChangeProp}=3DChange, _}, "eventsource") = -> >> + =A0 =A0 =A0 =A0 =A0 =A0Seq =3D proplists:get_value(<<"seq">>, ChangePr= op), >> + =A0 =A0 =A0 =A0 =A0 =A0send_chunk(Resp, ["data: ", ?JSON_ENCODE(Change= ), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"\n", "id: = ", ?JSON_ENCODE(Seq), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"\n\n"]); >> + =A0 =A0 =A0 =A0({change, Change, _}, "continuous") -> >> =A0 =A0 =A0 =A0 =A0 =A0 send_chunk(Resp, [?JSON_ENCODE(Change) | "\n"]); >> =A0 =A0 =A0 =A0 ({change, Change, Prepend}, _) -> >> =A0 =A0 =A0 =A0 =A0 =A0 send_chunk(Resp, [Prepend, ?JSON_ENCODE(Change)]= ); >> + =A0 =A0 =A0 =A0(start, "eventsource") -> >> + =A0 =A0 =A0 =A0 =A0 =A0ok; >> =A0 =A0 =A0 =A0 (start, "continuous") -> >> =A0 =A0 =A0 =A0 =A0 =A0 ok; >> =A0 =A0 =A0 =A0 (start, _) -> >> =A0 =A0 =A0 =A0 =A0 =A0 send_chunk(Resp, "{\"results\":[\n"); >> + =A0 =A0 =A0 =A0({stop, _EndSeq}, "eventsource") -> >> + =A0 =A0 =A0 =A0 =A0 =A0end_json_response(Resp); >> =A0 =A0 =A0 =A0 ({stop, EndSeq}, "continuous") -> >> =A0 =A0 =A0 =A0 =A0 =A0 send_chunk( >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Resp, >> @@ -118,6 +127,15 @@ handle_changes_req2(Req, Db) -> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 end >> =A0 =A0 =A0 =A0 =A0 =A0 ) >> =A0 =A0 =A0 =A0 end; >> + =A0 =A0"eventsource" -> >> + =A0 =A0 =A0 =A0Headers =3D [ >> + =A0 =A0 =A0 =A0 =A0 =A0{"Content-Type", "text/event-stream"}, >> + =A0 =A0 =A0 =A0 =A0 =A0{"Cache-Control", "no-cache"} >> + =A0 =A0 =A0 =A0], >> + =A0 =A0 =A0 =A0{ok, Resp} =3D couch_httpd:start_json_response(Req, 200= , Headers), >> + =A0 =A0 =A0 =A0fun(FeedChangesFun) -> >> + =A0 =A0 =A0 =A0 =A0 =A0FeedChangesFun(MakeCallback(Resp)) >> + =A0 =A0 =A0 =A0end; >> =A0 =A0 _ -> >> =A0 =A0 =A0 =A0 % "longpoll" or "continuous" >> =A0 =A0 =A0 =A0 {ok, Resp} =3D couch_httpd:start_json_response(Req, 200)= , >> @@ -1097,13 +1115,15 @@ parse_doc_query(Req) -> >> >> =A0parse_changes_query(Req) -> >> =A0 =A0 lists:foldl(fun({Key, Value}, Args) -> >> - =A0 =A0 =A0 =A0case {Key, Value} of >> + =A0 =A0 =A0 =A0case {string:to_lower(Key), Value} of >> =A0 =A0 =A0 =A0 {"feed", _} -> >> =A0 =A0 =A0 =A0 =A0 =A0 Args#changes_args{feed=3DValue}; >> =A0 =A0 =A0 =A0 {"descending", "true"} -> >> =A0 =A0 =A0 =A0 =A0 =A0 Args#changes_args{dir=3Drev}; >> =A0 =A0 =A0 =A0 {"since", _} -> >> =A0 =A0 =A0 =A0 =A0 =A0 Args#changes_args{since=3Dlist_to_integer(Value)= }; >> + =A0 =A0 =A0 =A0{"last-event-id", _} -> >> + =A0 =A0 =A0 =A0 =A0 =A0Args#changes_args{since=3Dlist_to_integer(Value= )}; >> =A0 =A0 =A0 =A0 {"limit", _} -> >> =A0 =A0 =A0 =A0 =A0 =A0 Args#changes_args{limit=3Dlist_to_integer(Value)= }; >> =A0 =A0 =A0 =A0 {"style", _} -> >>