public NetworkRequest <T> BuildSubscribeRequest <T>(string collectionName, string deviceID) { const string REST_PATH = "appdata/{appKey}/{collectionName}/_subscribe"; var urlParameters = new Dictionary <string, string>(); urlParameters.Add("appKey", ((KinveyClientRequestInitializer)client.RequestInitializer).AppKey); urlParameters.Add("collectionName", collectionName); NetworkRequest <T> subscribeCollection = new NetworkRequest <T>(client, "POST", REST_PATH, null, urlParameters); JObject requestPayload = new JObject(); requestPayload.Add(Constants.STR_REALTIME_DEVICEID, deviceID); subscribeCollection.HttpContent = requestPayload; client.InitializeRequest(subscribeCollection); return(subscribeCollection); }
public static PendingWriteAction buildFromRequest <T> (NetworkRequest <T> request) { PendingWriteAction newAction = new PendingWriteAction(); newAction.action = request.RequestMethod; if (request.uriResourceParameters.ContainsKey("entityID")) { newAction.entityId = request.uriResourceParameters["entityID"]; } if (request.uriResourceParameters.ContainsKey("collectionName")) { newAction.collection = request.uriResourceParameters["collectionName"]; } newAction.state = JsonConvert.SerializeObject(request.customRequestHeaders); return(newAction); }
public NetworkRequest <T> buildGetCountRequest <T> (string collectionName, string queryString = null) { string REST_PATH = "appdata/{appKey}/{collectionName}/_count"; var urlParameters = new Dictionary <string, string> (); urlParameters.Add("appKey", ((KinveyClientRequestInitializer)client.RequestInitializer).AppKey); urlParameters.Add("collectionName", collectionName); if (!string.IsNullOrEmpty(queryString)) { REST_PATH = "appdata/{appKey}/{collectionName}/_count?query={querystring}"; Dictionary <string, string> modifiers = ParseQueryForModifiers(queryString, ref REST_PATH, ref urlParameters); } NetworkRequest <T> getCountQuery = new NetworkRequest <T>(client, "GET", REST_PATH, null, urlParameters); client.InitializeRequest(getCountQuery); return(getCountQuery); }
private async Task <uint> PerformNetworkCount() { uint networkCount = default(uint); try { string mongoQuery = this.BuildMongoQuery(); NetworkRequest <JObject> request = Client.NetworkFactory.buildGetCountRequest <JObject>(Collection, mongoQuery); JObject networkResults = await request.ExecuteAsync().ConfigureAwait(false); if (networkResults != null) { JToken count = networkResults.GetValue("count"); if (count != null) { networkCount = count.ToObject <uint>(); } else { throw new KinveyException(EnumErrorCategory.ERROR_DATASTORE_NETWORK, EnumErrorCode.ERROR_GENERAL, "Error in FindCountAsync() for network results."); } } } catch (KinveyException) { throw; } catch (Exception e) { throw new KinveyException(EnumErrorCategory.ERROR_DATASTORE_NETWORK, EnumErrorCode.ERROR_GENERAL, "Error in FindCountAsync() for network results.", e); } return(networkCount); }
private async Task <Tuple <T, KinveyException, int> > HandlePushPOST(PendingWriteAction pwa) { T entity = default(T); var offset = 0; KinveyException kinveyException = null; try { int result = 0; string tempID = pwa.entityId; var localEntity = Cache.FindByID(pwa.entityId); JObject obj = JObject.FromObject(localEntity); obj["_id"] = null; localEntity = Newtonsoft.Json.JsonConvert.DeserializeObject <T>(obj.ToString()); NetworkRequest <T> request = Client.NetworkFactory.buildCreateRequest <T>(pwa.collection, localEntity); entity = await request.ExecuteAsync().ConfigureAwait(false); Cache.UpdateCacheSave(entity, tempID); result = SyncQueue.Remove(pwa); if (result == 0) { offset++; } } catch (KinveyException ke) { kinveyException = ke; offset++; } return(new Tuple <T, KinveyException, int>(entity, kinveyException, offset)); }
public override async Task <T> ExecuteAsync() { T savedEntity = default(T); NetworkRequest <T> request = null; string entityID = null;; JToken idToken = JObject.FromObject(entity) ["_id"]; if (idToken != null && !String.IsNullOrEmpty(idToken.ToString())) { entityID = idToken.ToString(); request = Client.NetworkFactory.buildUpdateRequest(Collection, entity, entityID); } else { request = Client.NetworkFactory.buildCreateRequest(Collection, entity); } switch (Policy) { case WritePolicy.FORCE_LOCAL: // sync PendingWriteAction pendingAction = PendingWriteAction.buildFromRequest(request); string saveModeLocal = request.RequestMethod; string tempIdLocal = null; if (String.Equals("POST", saveModeLocal)) { tempIdLocal = PrepareCacheSave(ref entity); savedEntity = Cache.Save(entity); pendingAction.entityId = tempIdLocal; } else { savedEntity = Cache.Update(entity); } SyncQueue.Enqueue(pendingAction); break; case WritePolicy.FORCE_NETWORK: // network savedEntity = await request.ExecuteAsync(); break; case WritePolicy.NETWORK_THEN_LOCAL: // cache string saveModeNetworkThenLocal = request.RequestMethod; string tempIdNetworkThenLocal = null; if (String.Equals("POST", saveModeNetworkThenLocal)) { tempIdNetworkThenLocal = PrepareCacheSave(ref entity); Cache.Save(entity); } else { Cache.Update(entity); } // network save savedEntity = await request.ExecuteAsync(); if (tempIdNetworkThenLocal != null) { Cache.UpdateCacheSave(savedEntity, tempIdNetworkThenLocal); } break; case WritePolicy.LOCAL_THEN_NETWORK: string saveModeLocalThenNetwork = request.RequestMethod; // cache if (String.Equals("POST", saveModeLocalThenNetwork)) { entityID = PrepareCacheSave(ref entity); savedEntity = Cache.Save(entity); } else { savedEntity = Cache.Update(entity); } KinveyException kinveyException = null; Exception exception = null; try { // network save savedEntity = await request.ExecuteAsync(); } catch (KinveyException kinveyEx) { kinveyException = kinveyEx; } catch (Exception ex) { exception = ex; } if (kinveyException != null || exception != null) { // if the network request fails, save data to sync queue var localPendingAction = PendingWriteAction.buildFromRequest(request); localPendingAction.entityId = entityID; SyncQueue.Enqueue(localPendingAction); if (kinveyException != null) { throw kinveyException; } } else { Cache.UpdateCacheSave(savedEntity, entityID); } break; default: throw new KinveyException(EnumErrorCategory.ERROR_GENERAL, EnumErrorCode.ERROR_GENERAL, "Invalid write policy"); } return(savedEntity); }
public NetworkRequest <T> BuildGetAggregateRequest <T>(string collectionName, EnumReduceFunction reduceFunction, string query, string groupField, string aggregateField) { string REST_PATH = "appdata/{appKey}/{collectionName}/_group"; var urlParameters = new Dictionary <string, string>(); urlParameters.Add("appKey", ((KinveyClientRequestInitializer)client.RequestInitializer).AppKey); urlParameters.Add("collectionName", collectionName); JObject keyval = new JObject(); if (!String.IsNullOrEmpty(groupField)) { keyval.Add(groupField, true); } JObject initialval = new JObject(); JObject httpBodyContent = new JObject(); httpBodyContent.Add("key", keyval); string reduce = String.Empty; switch (reduceFunction) { case EnumReduceFunction.REDUCE_FUNCTION_SUM: initialval.Add("result", 0); reduce = $"function(doc,out){{ out.result += doc.{aggregateField}; }}"; break; case EnumReduceFunction.REDUCE_FUNCTION_MIN: initialval.Add("result", Int32.MaxValue); reduce = $"function(doc,out){{ out.result = Math.min(out.result, doc.{aggregateField}); }}"; break; case EnumReduceFunction.REDUCE_FUNCTION_MAX: initialval.Add("result", Int32.MinValue); reduce = $"function(doc,out){{ out.result = Math.max(out.result, doc.{aggregateField}); }}"; break; case EnumReduceFunction.REDUCE_FUNCTION_AVERAGE: initialval.Add("result", 0); initialval.Add("count", 0); reduce = $"function(doc,out){{ out.result = (((out.result * out.count) + doc.{aggregateField}) / (out.count += 1)); }}"; break; default: // TODO throw new KinveyException() break; } httpBodyContent.Add("initial", initialval); httpBodyContent.Add("reduce", reduce); if (!String.IsNullOrEmpty(query)) { const char CHAR_CURLY_BRACE_OPENING = '{'; const char CHAR_CURLY_BRACE_CLOSING = '}'; const char CHAR_COLON = ':'; const char CHAR_DOUBLE_QUOTATION_MARK = '"'; JObject condition = new JObject(); query = query.TrimStart(CHAR_CURLY_BRACE_OPENING).TrimEnd(CHAR_CURLY_BRACE_CLOSING); string[] cond = query.Split(CHAR_COLON); cond[0] = cond[0].TrimStart(CHAR_DOUBLE_QUOTATION_MARK).TrimEnd(CHAR_DOUBLE_QUOTATION_MARK); cond[1] = cond[1].TrimStart(CHAR_DOUBLE_QUOTATION_MARK).TrimEnd(CHAR_DOUBLE_QUOTATION_MARK); condition.Add(cond[0], cond[1]); httpBodyContent.Add("condition", condition); } NetworkRequest <T> findAggregateQuery = new NetworkRequest <T>(client, "POST", REST_PATH, httpBodyContent, urlParameters); client.InitializeRequest(findAggregateQuery); return(findAggregateQuery); }
/// <summary> /// Perfoms finding in backend. /// </summary> /// <returns>The async task with the request results.</returns> protected async Task <NetworkReadResponse <T> > PerformNetworkFind() { try { string mongoQuery = this.BuildMongoQuery(); bool isQueryModifierPresent = !string.IsNullOrEmpty(mongoQuery) ? mongoQuery.Contains(Constants.STR_QUERY_MODIFIER_SKIP) || mongoQuery.Contains(Constants.STR_QUERY_MODIFIER_LIMIT) : false; if (DeltaSetFetchingEnabled && !isQueryModifierPresent) { QueryCacheItem queryCacheItem = Client.CacheManager.GetQueryCacheItem(Collection, mongoQuery, null); if (!Cache.IsCacheEmpty()) { if (queryCacheItem != null && !string.IsNullOrEmpty(queryCacheItem.lastRequest)) { // Able to perform server-side delta set fetch NetworkRequest <DeltaSetResponse <T> > request = Client.NetworkFactory.BuildDeltaSetRequest <DeltaSetResponse <T> >(queryCacheItem.collectionName, queryCacheItem.lastRequest, queryCacheItem.query); DeltaSetResponse <T> results = null; try { results = await request.ExecuteAsync().ConfigureAwait(false); } catch (KinveyException ke) { // Regardless of the error, remove the QueryCacheItem if it exists Client.CacheManager.DeleteQueryCacheItem(queryCacheItem); switch (ke.StatusCode) { case 400: // ResultSetSizeExceeded or ParameterValueOutOfRange if (ke.Error.Equals(Constants.STR_ERROR_BACKEND_RESULT_SET_SIZE_EXCEEDED)) { // This means that there are greater than 10k items in the delta set. // Clear QueryCache table, perform a regular GET // and capture x-kinvey-request-start time return(await PerformNetworkInitialDeltaGet(mongoQuery).ConfigureAwait(false)); } else if (ke.Error.Equals(Constants.STR_ERROR_BACKEND_PARAMETER_VALUE_OUT_OF_RANGE)) { // This means that the last sync time for delta set is too far back, or // the backend was enabled for delta set after the client was enabled // and already attempted a GET. // Perform regular GET and capture x-kinvey-request-start time return(await PerformNetworkInitialDeltaGet(mongoQuery).ConfigureAwait(false)); } break; case 403: // MissingConfiguration if (ke.Error.Equals(Constants.STR_ERROR_BACKEND_MISSING_CONFIGURATION)) { // This means that server-side delta sync // is not enabled - should perform a regular // GET and capture x-kinvey-request-start time return(await PerformNetworkInitialDeltaGet(mongoQuery).ConfigureAwait(false)); } break; default: // This is not a delta sync specific error throw; } } // With the _deltaset endpoint result from the server: // 1 - Apply deleted set to local cache List <string> listDeletedIDs = new List <string>(); foreach (var deletedItem in results.Deleted) { listDeletedIDs.Add(deletedItem.ID); } Cache.DeleteByIDs(listDeletedIDs); // 2 - Apply changed set to local cache Cache.RefreshCache(results.Changed); // 3 - Update the last request time for this combination // of collection:query queryCacheItem.lastRequest = request.RequestStartTime; Client.CacheManager.SetQueryCacheItem(queryCacheItem); // 4 - Return network results return(new NetworkReadResponse <T>(results.Changed, results.Changed.Count, true)); } else { // Perform regular GET and capture x-kinvey-request-start time return(await PerformNetworkInitialDeltaGet(mongoQuery).ConfigureAwait(false)); } } else { // Perform regular GET and capture x-kinvey-request-start time return(await PerformNetworkInitialDeltaGet(mongoQuery, queryCacheItem).ConfigureAwait(false)); } } return(await PerformNetworkGet(mongoQuery).ConfigureAwait(false)); } catch (KinveyException) { throw; } catch (Exception e) { throw new KinveyException(EnumErrorCategory.ERROR_DATASTORE_NETWORK, EnumErrorCode.ERROR_GENERAL, "Error in FindAsync() for network results.", e); } }