public static ICouchbaseResponseState GetChangesPost(ICouchbaseListenerContext context) { DBMonitorCouchbaseResponseState responseState = new DBMonitorCouchbaseResponseState(); var responseObject = PerformLogicWithDatabase(context, true, db => { var response = context.CreateResponse(); responseState.Response = response; var body = context.BodyAs<Dictionary<string, object>>(); ProcessBody(body); if (body.GetCast<ChangesFeedMode>("feed") < ChangesFeedMode.Continuous) { if(context.CacheWithEtag(db.GetLastSequenceNumber().ToString())) { response.InternalStatus = StatusCode.NotModified; return response; } } var options = ChangesOptions.Default; responseState.Db = db; responseState.ContentOptions = body.GetCast<DocumentContentOptions>("content_options"); responseState.ChangesFeedMode = body.GetCast<ChangesFeedMode>("feed"); responseState.ChangesIncludeDocs = body.GetCast<bool>("include_docs"); options.IncludeDocs = responseState.ChangesIncludeDocs; responseState.ChangesIncludeConflicts = body.GetCast<string>("style") == "all_docs"; options.IncludeConflicts = responseState.ChangesIncludeConflicts; options.ContentOptions = responseState.ContentOptions; options.SortBySequence = !options.IncludeConflicts; options.Limit = body.GetCast<int>("limit", options.Limit); int since = body.GetCast<int>("since"); string filterName = body.GetCast<string>("filter"); if(filterName != null) { Status status = new Status(); responseState.ChangesFilter = db.GetFilter(filterName, status); if(responseState.ChangesFilter == null) { return context.CreateResponse(status.Code); } responseState.FilterParams = context.GetQueryParams(); } RevisionList changes = db.ChangesSince(since, options, responseState.ChangesFilter, responseState.FilterParams); if((responseState.ChangesFeedMode >= ChangesFeedMode.Continuous) || (responseState.ChangesFeedMode == ChangesFeedMode.LongPoll && changes.Count == 0)) { // Response is going to stay open (continuous, or hanging GET): response.Chunked = true; if(responseState.ChangesFeedMode == ChangesFeedMode.EventSource) { response["Content-Type"] = "text/event-stream; charset=utf-8"; } if(responseState.ChangesFeedMode >= ChangesFeedMode.Continuous) { response.WriteHeaders(); foreach(var rev in changes) { response.SendContinuousLine(ChangesDictForRev(rev, responseState), context.ChangesFeedMode); } } responseState.SubscribeToDatabase(db); int heartbeat = body.GetCast<int>("heartbeat", Int32.MinValue); if(heartbeat != Int32.MinValue) { if(heartbeat <= 0) { responseState.IsAsync = false; return context.CreateResponse(StatusCode.BadParam); } heartbeat = Math.Max(heartbeat, (int)MinHeartbeat.TotalMilliseconds); string heartbeatResponse = context.ChangesFeedMode == ChangesFeedMode.EventSource ? "\n\n" : "\r\n"; responseState.StartHeartbeat(heartbeatResponse, TimeSpan.FromMilliseconds(heartbeat)); } return context.CreateResponse(); } else { if(responseState.ChangesIncludeConflicts) { response.JsonBody = new Body(ResponseBodyForChanges(changes, since, options.Limit, responseState)); } else { response.JsonBody = new Body(ResponseBodyForChanges(changes, since, responseState)); } return response; } }); responseState.Response = responseObject; return responseState; }
/// <summary> /// Returns a sorted list of changes made to documents in the database, in time order of application. /// </summary> /// <returns>The response state for further HTTP processing</returns> /// <param name="context">The context of the Couchbase Lite HTTP request</param> /// <remarks> /// http://docs.couchdb.org/en/latest/api/database/changes.html#get--db-_changes /// </remarks> public static ICouchbaseResponseState GetChanges(ICouchbaseListenerContext context) { DBMonitorCouchbaseResponseState responseState = new DBMonitorCouchbaseResponseState(); var responseObject = PerformLogicWithDatabase(context, true, db => { var response = context.CreateResponse(); responseState.Response = response; if (context.ChangesFeedMode < ChangesFeedMode.Continuous) { if(context.CacheWithEtag(db.GetLastSequenceNumber().ToString())) { response.InternalStatus = StatusCode.NotModified; return response; } } var options = ChangesOptions.Default; responseState.Db = db; responseState.ContentOptions = context.ContentOptions; responseState.ChangesFeedMode = context.ChangesFeedMode; responseState.ChangesIncludeDocs = context.GetQueryParam<bool>("include_docs", bool.TryParse, false); options.IncludeDocs = responseState.ChangesIncludeDocs; responseState.ChangesIncludeConflicts = context.GetQueryParam("style") == "all_docs"; options.IncludeConflicts = responseState.ChangesIncludeConflicts; options.ContentOptions = context.ContentOptions; options.SortBySequence = !options.IncludeConflicts; options.Limit = context.GetQueryParam<int>("limit", int.TryParse, options.Limit); int since = context.GetQueryParam<int>("since", int.TryParse, 0); string filterName = context.GetQueryParam("filter"); if(filterName != null) { Status status = new Status(); responseState.ChangesFilter = db.GetFilter(filterName, status); if(responseState.ChangesFilter == null) { return context.CreateResponse(status.Code); } responseState.FilterParams = context.GetQueryParams(); } RevisionList changes = db.ChangesSince(since, options, responseState.ChangesFilter, responseState.FilterParams); if((context.ChangesFeedMode >= ChangesFeedMode.Continuous) || (context.ChangesFeedMode == ChangesFeedMode.LongPoll && changes.Count == 0)) { // Response is going to stay open (continuous, or hanging GET): response.Chunked = true; if(context.ChangesFeedMode == ChangesFeedMode.EventSource) { response["Content-Type"] = "text/event-stream; charset=utf-8"; } if(context.ChangesFeedMode >= ChangesFeedMode.Continuous) { response.WriteHeaders(); foreach(var rev in changes) { var success = response.SendContinuousLine(ChangesDictForRev(rev, responseState), context.ChangesFeedMode); if(!success) { return context.CreateResponse(StatusCode.BadRequest); } } } responseState.SubscribeToDatabase(db); string heartbeatParam = context.GetQueryParam("heartbeat"); if(heartbeatParam != null) { int heartbeat; if(!int.TryParse(heartbeatParam, out heartbeat) || heartbeat <= 0) { responseState.IsAsync = false; return context.CreateResponse(StatusCode.BadParam); } var heartbeatSpan = TimeSpan.FromMilliseconds(heartbeat); if(heartbeatSpan < MinHeartbeat) { heartbeatSpan = MinHeartbeat; } string heartbeatResponse = context.ChangesFeedMode == ChangesFeedMode.EventSource ? "\n\n" : "\r\n"; responseState.StartHeartbeat(heartbeatResponse, heartbeatSpan); } return response; } else { if(responseState.ChangesIncludeConflicts) { response.JsonBody = new Body(ResponseBodyForChanges(changes, since, options.Limit, responseState)); } else { response.JsonBody = new Body(ResponseBodyForChanges(changes, since, responseState)); } return response; } }); responseState.Response = responseObject; return responseState; }
public static ICouchbaseResponseState GetChangesPost(ICouchbaseListenerContext context) { DBMonitorCouchbaseResponseState responseState = new DBMonitorCouchbaseResponseState(); var responseObject = PerformLogicWithDatabase(context, true, db => { var response = context.CreateResponse(); responseState.Response = response; var body = context.BodyAs <Dictionary <string, object> >(); ProcessBody(body); if (body.GetCast <ChangesFeedMode>("feed") < ChangesFeedMode.Continuous) { if (context.CacheWithEtag(db.GetLastSequenceNumber().ToString())) { response.InternalStatus = StatusCode.NotModified; return(response); } } var options = ChangesOptions.Default; responseState.Db = db; responseState.ContentOptions = body.GetCast <DocumentContentOptions>("content_options"); responseState.ChangesFeedMode = body.GetCast <ChangesFeedMode>("feed"); responseState.ChangesIncludeDocs = body.GetCast <bool>("include_docs"); options.IncludeDocs = responseState.ChangesIncludeDocs; responseState.ChangesIncludeConflicts = body.GetCast <string>("style") == "all_docs"; options.IncludeConflicts = responseState.ChangesIncludeConflicts; options.ContentOptions = responseState.ContentOptions; options.SortBySequence = !options.IncludeConflicts; options.Limit = body.GetCast <int>("limit", options.Limit); int since = body.GetCast <int>("since"); string filterName = body.GetCast <string>("filter"); if (filterName != null) { Status status = new Status(); responseState.ChangesFilter = db.GetFilter(filterName, status); if (responseState.ChangesFilter == null) { return(context.CreateResponse(status.Code)); } responseState.FilterParams = context.GetQueryParams(); } if (responseState.ChangesFeedMode >= ChangesFeedMode.LongPoll) { // Response is going to stay open (continuous, or hanging GET): response.Chunked = true; if (responseState.ChangesFeedMode == ChangesFeedMode.EventSource) { response["Content-Type"] = "text/event-stream; charset=utf-8"; } response.WriteHeaders(); if (responseState.SubscribeToDatabase(db, since, options)) { int heartbeat = body.GetCast <int>("heartbeat", Int32.MinValue); if (heartbeat != Int32.MinValue) { if (heartbeat <= 0) { responseState.IsAsync = false; return(context.CreateResponse(StatusCode.BadParam)); } heartbeat = Math.Max(heartbeat, (int)MinHeartbeat.TotalMilliseconds); string heartbeatResponse = context.ChangesFeedMode == ChangesFeedMode.EventSource ? "\n\n" : "\r\n"; responseState.StartHeartbeat(heartbeatResponse, TimeSpan.FromMilliseconds(heartbeat)); } } return(responseState.Response); } else { var changes = db.ChangesSinceStreaming(since, options, responseState.ChangesFilter, responseState.FilterParams); response.Chunked = true; response.Headers["Content-Type"] = "application/json"; response.WriteBodyCallback = WriteChangesBodyJson; if (responseState.ChangesIncludeConflicts) { response.WriteBodyContext = new WriteChangesContext { IncludeConflicts = true, Since = since, Limit = options.Limit, Changes = changes, ResponseState = responseState }; } else { response.WriteBodyContext = new WriteChangesContext { Since = since, Changes = changes, ResponseState = responseState }; } return(response); } }); responseState.Response = responseObject; return(responseState); }
/// <summary> /// Returns a sorted list of changes made to documents in the database, in time order of application. /// </summary> /// <returns>The response state for further HTTP processing</returns> /// <param name="context">The context of the Couchbase Lite HTTP request</param> /// <remarks> /// http://docs.couchdb.org/en/latest/api/database/changes.html#get--db-_changes /// <remarks> public static ICouchbaseResponseState GetChanges(ICouchbaseListenerContext context) { DBMonitorCouchbaseResponseState responseState = new DBMonitorCouchbaseResponseState(); var responseObject = PerformLogicWithDatabase(context, true, db => { var response = context.CreateResponse(); responseState.Response = response; if (context.ChangesFeedMode < ChangesFeedMode.Continuous) { if (context.CacheWithEtag(db.LastSequenceNumber.ToString())) { response.InternalStatus = StatusCode.NotModified; return(response); } } var options = ChangesOptions.Default; responseState.Db = db; responseState.ContentOptions = context.ContentOptions; responseState.ChangesFeedMode = context.ChangesFeedMode; responseState.ChangesIncludeDocs = context.GetQueryParam <bool>("include_docs", bool.TryParse, false); options.IncludeDocs = responseState.ChangesIncludeDocs; responseState.ChangesIncludeConflicts = context.GetQueryParam("style") == "all_docs"; options.IncludeConflicts = responseState.ChangesIncludeConflicts; options.ContentOptions = context.ContentOptions; options.SortBySequence = !options.IncludeConflicts; options.Limit = context.GetQueryParam <int>("limit", int.TryParse, options.Limit); int since = context.GetQueryParam <int>("since", int.TryParse, 0); string filterName = context.GetQueryParam("filter"); if (filterName != null) { Status status = new Status(); responseState.ChangesFilter = db.GetFilter(filterName, status); if (responseState.ChangesFilter == null) { return(context.CreateResponse(status.Code)); } responseState.FilterParams = context.GetQueryParams(); } RevisionList changes = db.ChangesSince(since, options, responseState.ChangesFilter, responseState.FilterParams); if ((context.ChangesFeedMode >= ChangesFeedMode.Continuous) || (context.ChangesFeedMode == ChangesFeedMode.LongPoll && changes.Count == 0)) { // Response is going to stay open (continuous, or hanging GET): response.Chunked = true; if (context.ChangesFeedMode == ChangesFeedMode.EventSource) { response["Content-Type"] = "text/event-stream; charset=utf-8"; } if (context.ChangesFeedMode >= ChangesFeedMode.Continuous) { response.WriteHeaders(); foreach (var rev in changes) { response.SendContinuousLine(ChangesDictForRev(rev, responseState), context.ChangesFeedMode); } } responseState.SubscribeToDatabase(db); string heartbeatParam = context.GetQueryParam("heartbeat"); if (heartbeatParam != null) { int heartbeat; if (!int.TryParse(heartbeatParam, out heartbeat) || heartbeat <= 0) { responseState.IsAsync = false; return(context.CreateResponse(StatusCode.BadParam)); } heartbeat = Math.Min(heartbeat, MIN_HEARTBEAT); string heartbeatResponse = context.ChangesFeedMode == ChangesFeedMode.EventSource ? "\n\n" : "\r\n"; responseState.StartHeartbeat(heartbeatResponse, heartbeat); } return(context.CreateResponse()); } else { if (responseState.ChangesIncludeConflicts) { response.JsonBody = new Body(ResponseBodyForChanges(changes, since, options.Limit, responseState)); } else { response.JsonBody = new Body(ResponseBodyForChanges(changes, since, responseState)); } return(response); } }); responseState.Response = responseObject; return(responseState); }
/// <summary> /// Returns a sorted list of changes made to documents in the database, in time order of application. /// </summary> /// <returns>The response state for further HTTP processing</returns> /// <param name="context">The context of the Couchbase Lite HTTP request</param> /// <remarks> /// http://docs.couchdb.org/en/latest/api/database/changes.html#get--db-_changes /// </remarks> public static ICouchbaseResponseState GetChanges(ICouchbaseListenerContext context) { DBMonitorCouchbaseResponseState responseState = new DBMonitorCouchbaseResponseState(); var responseObject = PerformLogicWithDatabase(context, true, db => { var response = context.CreateResponse(); responseState.Response = response; if (context.ChangesFeedMode < ChangesFeedMode.Continuous) { if (context.CacheWithEtag(db.GetLastSequenceNumber().ToString())) { response.InternalStatus = StatusCode.NotModified; return(response); } } var options = ChangesOptions.Default; responseState.Db = db; responseState.ContentOptions = context.ContentOptions; responseState.ChangesFeedMode = context.ChangesFeedMode; responseState.ChangesIncludeDocs = context.GetQueryParam <bool>("include_docs", bool.TryParse, false); options.IncludeDocs = responseState.ChangesIncludeDocs; responseState.ChangesIncludeConflicts = context.GetQueryParam("style") == "all_docs"; options.IncludeConflicts = responseState.ChangesIncludeConflicts; options.ContentOptions = context.ContentOptions; options.SortBySequence = !options.IncludeConflicts; options.Limit = context.GetQueryParam <int>("limit", int.TryParse, options.Limit); int since = context.GetQueryParam <int>("since", int.TryParse, 0); string filterName = context.GetQueryParam("filter"); if (filterName != null) { Status status = new Status(); responseState.ChangesFilter = db.GetFilter(filterName, status); if (responseState.ChangesFilter == null) { var code = Database.FilterCompiler == null ? StatusCode.NotImplemented : StatusCode.NotFound; return(context.CreateResponse(code)); } responseState.FilterParams = context.GetQueryParams(); } string heartbeatParam = context.GetQueryParam("heartbeat"); int heartbeat = 0; if (heartbeatParam != null && (!Int32.TryParse(heartbeatParam, out heartbeat) || heartbeat <= 0)) { return(context.CreateResponse(StatusCode.BadParam)); } var changes = db.ChangesSinceStreaming(since, options, responseState.ChangesFilter, responseState.FilterParams); if ((context.ChangesFeedMode >= ChangesFeedMode.Continuous) || (context.ChangesFeedMode == ChangesFeedMode.LongPoll && !changes.Any())) { // Response is going to stay open (continuous, or hanging GET): response.Chunked = true; if (context.ChangesFeedMode == ChangesFeedMode.EventSource) { response["Content-Type"] = "text/event-stream; charset=utf-8"; } if (context.ChangesFeedMode >= ChangesFeedMode.Continuous) { response.WriteHeaders(); foreach (var rev in changes) { var success = response.SendContinuousLine(ChangesDictForRev(rev, responseState), context.ChangesFeedMode); if (!success) { return(context.CreateResponse(StatusCode.BadRequest)); } } } var subscribed = responseState.SubscribeToDatabase(db, since, options); if (!subscribed) { return(response); } if (heartbeat > 0) { var heartbeatSpan = TimeSpan.FromMilliseconds(heartbeat); if (heartbeatSpan < MinHeartbeat) { heartbeatSpan = MinHeartbeat; } string heartbeatResponse = context.ChangesFeedMode == ChangesFeedMode.EventSource ? "\n\n" : "\r\n"; responseState.StartHeartbeat(heartbeatResponse, heartbeatSpan); } return(response); } else { response.Chunked = true; response.Headers["Content-Type"] = "application/json"; response.WriteBodyCallback = WriteChangesBodyJson; if (responseState.ChangesIncludeConflicts) { response.WriteBodyContext = new WriteChangesContext { IncludeConflicts = true, Since = since, Limit = options.Limit, Changes = changes, ResponseState = responseState }; } else { response.WriteBodyContext = new WriteChangesContext { Since = since, Changes = changes, ResponseState = responseState }; } } return(response); }); responseState.Response = responseObject; return(responseState); }