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 E87C0C79F for ; Wed, 16 May 2012 05:50:36 +0000 (UTC) Received: (qmail 87329 invoked by uid 500); 16 May 2012 05:50:36 -0000 Delivered-To: apmail-couchdb-dev-archive@couchdb.apache.org Received: (qmail 86304 invoked by uid 500); 16 May 2012 05:50:32 -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 86266 invoked by uid 99); 16 May 2012 05:50:31 -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:50:31 +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 paul.joseph.davis@gmail.com designates 209.85.212.52 as permitted sender) Received: from [209.85.212.52] (HELO mail-vb0-f52.google.com) (209.85.212.52) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 May 2012 05:50:23 +0000 Received: by vbzb23 with SMTP id b23so507596vbz.11 for ; Tue, 15 May 2012 22:50:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type:content-transfer-encoding; bh=0Imwhc9hG8UmGw8zy6ukaF2fxX6GKwKPMONpuGQa3/0=; b=II+li0N5MNxzfB+I9t8NCwSDBUIVz6/a0FOgmwElpYtQSTVQQ5DM6vyCBuxka6U+6Z YWWk3i+iRe58Vz5ZeE5qi93mILa+4wySqmh4//ME3Zjpb5SJzM4qjxjzzHYejkkNfvyp pPv93eVyYYF8MugDuz88rrwax9Oxvo9qCPpfTZfgmJwDQM59MW5ejBExAU+pmYJO9KOB yvc/VL981vKP7lcAjAapLkrtWBTKIPs9JWNMTH8rB1OnVCaWd9KdrR20bT66SqPkdAWj D7pmeBNkIL081ke2LjhGSd7nh88ycS4KjpRbkgQrxu667KyQFXxghPke/mJ4QLFk9uHa DsHA== Received: by 10.220.240.73 with SMTP id kz9mr1294976vcb.9.1337147402189; Tue, 15 May 2012 22:50:02 -0700 (PDT) MIME-Version: 1.0 Received: by 10.220.10.14 with HTTP; Tue, 15 May 2012 22:49:22 -0700 (PDT) In-Reply-To: References: <20120516053615.720C7161E9@tyr.zones.apache.org> From: Paul Davis Date: Wed, 16 May 2012 00:49:22 -0500 Message-ID: Subject: Re: git commit: add Server-Sent Events protocol to db changes API. close #COUCHDB-986 To: dev@couchdb.apache.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Oh, I missed the scoping a bit on that. Should be for browsers, but for the CLI tests I wouldn't be surprised if that fails with a "no property named EventSource on undefined" or whatever. I'd just add a if(window && window.EventSource) to fix if that's the case. Though we should add a ticket to revisit this since we're theoretically moving to the CLI tests, no point having test code that never runs and all that. On Wed, May 16, 2012 at 12:44 AM, Benoit Chesneau wro= te: > On Wed, May 16, 2012 at 7:42 AM, Paul Davis = wrote: >> 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/= script/test/changes.js >>> ---------------------------------------------------------------------- >>> diff --git a/share/www/script/test/changes.js b/share/www/script/test/c= hanges.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=3Deventsourc= e"); >>> + =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, fals= e); >>> + >>> + =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/couchd= b/couch_changes.erl >>> ---------------------------------------------------------------------- >>> diff --git a/src/couchdb/couch_changes.erl b/src/couchdb/couch_changes.= erl >>> 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", "eventsourc= e"]) of >>> + =A0 =A0true -> >>> =A0 =A0 =A0 =A0 fun(CallbackAcc) -> >>> =A0 =A0 =A0 =A0 =A0 =A0 {Callback, UserAcc} =3D get_callback_acc(Callba= ckAcc), >>> =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(Callba= ckAcc), >>> =A0 =A0 =A0 =A0 =A0 =A0 UserAcc2 =3D start_sending_changes(Callback, Us= erAcc, Feed), >>> @@ -261,7 +262,9 @@ get_changes_timeout(Args, Callback) -> >>> =A0 =A0 =A0 =A0 =A0 =A0 fun(UserAcc) -> {ok, Callback(timeout, Response= Type, 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, <<>>}, "con= tinuous", UserAcc), >>> + =A0 =A0 =A0 =A0UserAcc2 =3D Callback({change, ChangesRow, <<>>}, Resp= onseType, 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/couchd= b/couch_httpd_db.erl >>> ---------------------------------------------------------------------- >>> diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_d= b.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">>, ChangeP= rop), >>> + =A0 =A0 =A0 =A0 =A0 =A0send_chunk(Resp, ["data: ", ?JSON_ENCODE(Chang= e), >>> + =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, 20= 0, 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(Valu= e)}; >>> =A0 =A0 =A0 =A0 {"limit", _} -> >>> =A0 =A0 =A0 =A0 =A0 =A0 Args#changes_args{limit=3Dlist_to_integer(Value= )}; >>> =A0 =A0 =A0 =A0 {"style", _} -> >>>