예제 #1
0
        /// <summary>
        /// Kicks off a bi-directional synchronization of data between the library and the backend.
        /// First, the library calls push to send local changes to the backend. Subsequently, the library calls pull to fetch data in the collection from the backend and stores it on the device.
        /// You can provide a query as a parameter to the sync API, to restrict the data that is pulled from the backend. The query does not affect what data gets pushed to the backend.
        ///
        /// This API is not supported on a DataStore of type <see cref="KinveyXamarin.DataStoreType.NETWORK"/>. Calling this method on a network data store will throw an exception.
        /// </summary>
        /// <returns>DataStoreResponse indicating errors, if any.</returns>
        /// <param name="query">An optional query parameter that controls what gets pulled from the backend during a sync operation.</param>
        /// <param name="ct">[optional] CancellationToken used to cancel the request.</param>
        public async Task <SyncDataStoreResponse <T> > SyncAsync(IQueryable <object> query = null, CancellationToken ct = default(CancellationToken))
        {
            if (this.storeType == DataStoreType.NETWORK)
            {
                throw new KinveyException(EnumErrorCategory.ERROR_DATASTORE_NETWORK, EnumErrorCode.ERROR_DATASTORE_INVALID_SYNC_OPERATION, "");
            }

            // first push
            PushDataStoreResponse <T> pushResponse = await this.PushAsync(ct);              //partial success

            ct.ThrowIfCancellationRequested();

            //then pull
            PullDataStoreResponse <T> pullResponse = null;

            try
            {
                pullResponse = await this.PullAsync(query, -1, false, ct);
            }
            catch (KinveyException e)
            {
                pullResponse = new PullDataStoreResponse <T>();
                pullResponse.AddKinveyException(e);
            }

            SyncDataStoreResponse <T> response = new SyncDataStoreResponse <T>();

            response.PushResponse = pushResponse;
            response.PullResponse = pullResponse;

            return(response);
        }
예제 #2
0
        /// <summary>
        /// Executes the request asynchronously.
        /// </summary>
        /// <returns> The async task with the request result.</returns>
        public override async Task <PushDataStoreResponse <T> > ExecuteAsync()
        {
            var response = new PushDataStoreResponse <T>();

            if (HelperMethods.IsLessThan(Client.ApiVersion, 5))
            {
                response = await PushSingleActionsAsync().ConfigureAwait(false);
            }
            else
            {
                var pushMultiPostActionsResponse = await PushMultiPostActionsAsync().ConfigureAwait(false);

                response.SetResponse(pushMultiPostActionsResponse);

                var pushSinglePutActionsResponse = await PushSingleActionsAsync("PUT").ConfigureAwait(false);

                response.SetResponse(pushSinglePutActionsResponse);

                var pushSingleDeleteActionsResponse = await PushSingleActionsAsync("DELETE").ConfigureAwait(false);

                response.SetResponse(pushSingleDeleteActionsResponse);
            }

            return(response);
        }
예제 #3
0
        private async Task <PushDataStoreResponse <T> > PushMultiPostActionsAsync()
        {
            var response           = new PushDataStoreResponse <T>();
            var limit              = 10 * Constants.NUMBER_LIMIT_OF_ENTITIES;
            var offset             = 0;
            var pendingPostActions = SyncQueue.GetFirstN(limit, offset, "POST");

            while (pendingPostActions != null && pendingPostActions.Count > 0)
            {
                var tasks = new List <Task <Tuple <PushDataStoreResponse <T>, int> > >();

                var realCountOfMultiInsertOperations = pendingPostActions.Count / (double)Constants.NUMBER_LIMIT_OF_ENTITIES;
                realCountOfMultiInsertOperations = Math.Ceiling(realCountOfMultiInsertOperations);

                for (var index = 0; index < realCountOfMultiInsertOperations; index++)
                {
                    var pendingWritePostActionsForPush = pendingPostActions.Skip(index * Constants.NUMBER_LIMIT_OF_ENTITIES).Take(Constants.NUMBER_LIMIT_OF_ENTITIES).ToList();

                    if (pendingWritePostActionsForPush.Count > 0)
                    {
                        tasks.Add(HandlePushMultiPOST(pendingWritePostActionsForPush));
                    }
                }

                await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false);

                foreach (var task in tasks)
                {
                    response.AddEntities(task.Result.Item1.PushEntities);
                    response.AddExceptions(task.Result.Item1.KinveyExceptions);
                    offset += task.Result.Item2;
                }

                response.PushCount += pendingPostActions.Count;

                pendingPostActions = SyncQueue.GetFirstN(limit, offset, "POST");
            }
            return(response);
        }
예제 #4
0
        private async Task <PushDataStoreResponse <T> > PushSingleActionsAsync(string action = null)
        {
            var response = new PushDataStoreResponse <T>();
            var offset   = 0;
            var limit    = 10;

            var pendingActions = string.IsNullOrEmpty(action) ? SyncQueue.GetFirstN(limit, offset) :
                                 SyncQueue.GetFirstN(limit, offset, action);

            while (pendingActions != null && pendingActions.Count > 0)
            {
                var tasks = new List <Task <Tuple <T, KinveyException, int> > >();
                foreach (PendingWriteAction pwa in pendingActions)
                {
                    if (string.Equals("POST", pwa.action))
                    {
                        tasks.Add(HandlePushPOST(pwa));
                    }
                    else if (string.Equals("PUT", pwa.action))
                    {
                        tasks.Add(HandlePushPUT(pwa));
                    }
                    else if (string.Equals("DELETE", pwa.action))
                    {
                        tasks.Add(HandlePushDELETE(pwa));
                    }
                }

                try
                {
                    await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    response.AddKinveyException(new KinveyException(EnumErrorCategory.ERROR_DATASTORE_NETWORK,
                                                                    EnumErrorCode.ERROR_JSON_RESPONSE,
                                                                    e.Message,
                                                                    e));
                }

                var resultEntities   = new List <T>();
                var kinveyExceptions = new List <KinveyException>();
                var resultCount      = 0;
                foreach (var task in tasks)
                {
                    if (!EqualityComparer <T> .Default.Equals(task.Result.Item1, default(T)))
                    {
                        resultEntities.Add(task.Result.Item1);
                    }

                    if (task.Result.Item2 != null)
                    {
                        kinveyExceptions.Add(task.Result.Item2);
                    }

                    offset += task.Result.Item3;

                    resultCount++;
                }

                response.AddEntities(resultEntities);
                response.AddExceptions(kinveyExceptions);
                response.PushCount += resultCount;

                pendingActions = string.IsNullOrEmpty(action) ? SyncQueue.GetFirstN(limit, offset) :
                                 SyncQueue.GetFirstN(limit, offset, action);
            }

            return(response);
        }
예제 #5
0
        private async Task <Tuple <PushDataStoreResponse <T>, int> > HandlePushMultiPOST(ICollection <PendingWriteAction> pendingWriteActions)
        {
            var offset   = 0;
            var response = new PushDataStoreResponse <T>();

            var multiInsertNetworkResponse = new KinveyMultiInsertResponse <T>
            {
                Entities = new List <T>(),
                Errors   = new List <Error>()
            };
            var localData   = new List <Tuple <string, T, PendingWriteAction> >();
            var isException = false;

            try
            {
                foreach (var pendingWriteAction in pendingWriteActions)
                {
                    var entity = Cache.FindByID(pendingWriteAction.entityId);

                    var obj = JObject.FromObject(entity);
                    obj["_id"] = null;
                    entity     = Newtonsoft.Json.JsonConvert.DeserializeObject <T>(obj.ToString());

                    localData.Add(new Tuple <string, T, PendingWriteAction>(pendingWriteAction.entityId, entity, pendingWriteAction));
                }

                var multiInsertNetworkRequest = Client.NetworkFactory.BuildMultiInsertRequest <T, KinveyMultiInsertResponse <T> >(Collection, localData.Select(e => e.Item2).ToList());
                multiInsertNetworkResponse = await multiInsertNetworkRequest.ExecuteAsync().ConfigureAwait(false);
            }
            catch (KinveyException ke)
            {
                response.AddKinveyException(ke);
                offset     += pendingWriteActions.Count;
                isException = true;
            }
            catch (Exception ex)
            {
                response.AddKinveyException(new KinveyException(EnumErrorCategory.ERROR_GENERAL,
                                                                EnumErrorCode.ERROR_GENERAL,
                                                                ex.Message,
                                                                ex));
                offset     += pendingWriteActions.Count;
                isException = true;
            }

            if (!isException)
            {
                for (var index = 0; index < localData.Count; index++)
                {
                    try
                    {
                        if (multiInsertNetworkResponse.Entities[index] != null)
                        {
                            Cache.UpdateCacheSave(multiInsertNetworkResponse.Entities[index], localData[index].Item1);

                            var removeResult = SyncQueue.Remove(localData[index].Item3);

                            if (removeResult == 0)
                            {
                                offset++;
                            }
                        }
                    }
                    catch (KinveyException ke)
                    {
                        response.AddKinveyException(ke);
                        offset++;
                    }
                    catch (Exception ex)
                    {
                        response.AddKinveyException(new KinveyException(EnumErrorCategory.ERROR_GENERAL,
                                                                        EnumErrorCode.ERROR_GENERAL,
                                                                        ex.Message,
                                                                        ex));
                        offset++;
                    }
                }
            }

            var entities = multiInsertNetworkResponse.Entities.Where(e => e != null).ToList();

            response.AddEntities(entities);

            foreach (var error in multiInsertNetworkResponse.Errors)
            {
                response.AddKinveyException(new KinveyException(EnumErrorCategory.ERROR_BACKEND, EnumErrorCode.ERROR_GENERAL, error.Errmsg));
                offset++;
            }

            var result = new Tuple <PushDataStoreResponse <T>, int>(response, offset);

            return(result);
        }
예제 #6
0
 /// <summary>
 /// Sets the response.
 /// </summary>
 public void SetResponse(PushDataStoreResponse <T> response)
 {
     AddEntities(response.PushEntities);
     AddExceptions(response.KinveyExceptions);
     PushCount += response.PushCount;
 }