예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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));
        }
예제 #6
0
        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);
        }
예제 #7
0
        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);
        }
예제 #8
0
        /// <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);
            }
        }