Esempio n. 1
0
        public EntitySync ForEntity <T>(SynchronizationParameters synchronizationParameters) where T : AbstractEntity, new()
        {
            Type       type       = typeof(T);
            string     typeName   = type.Name;
            EntitySync entitySync = new EntitySync
            {
                Type   = type,
                Getter = sql => DatabaseConnection.Connection.Query <T>(sql).Cast <AbstractEntity>().ToList(),
            };

            if (typeName != "User" && synchronizationParameters.DontUpload.Contains(typeName))
            {
                entitySync.Up = () => entitySync.PostUp();
            }
            else
            {
                entitySync.Up = () => UploadAsync <T>(synchronizationParameters, entitySync.PostUp);
            }

            if (synchronizationParameters.DontDownload.Contains(typeName))
            {
                entitySync.Down = () => entitySync.PostDown();
            }
            else
            {
                entitySync.Down = () => DownloadAsync <T>(synchronizationParameters, entitySync.PostDown);
            }

            entitySync.CreateTable = connection => connection.CreateTable <T>();
            entitySync.DropTable   = connection => connection.DropTable <T>();

            return(entitySync);
        }
        public RestService(SynchronizationParameters synchronizationParameters)
        {
            Server = synchronizationParameters.Server;
            var authData        = string.Format("{0}:{1}", synchronizationParameters.Username, synchronizationParameters.Password);
            var authHeaderValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(authData));

            client = new HttpClient();
            client.MaxResponseContentBufferSize        = 256 * 100000;
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authHeaderValue);
        }
Esempio n. 3
0
        public void Synchronize(SynchronizationParameters synchronizationParameters)
        {
            NotificationService.Send(NotificationEvent.PreSynchronization);

            List <EntitySync> syncTables = synchronizationParameters.EntitiesInSynchronization = Setup(synchronizationParameters);

            Debug.Assert(syncTables.Count >= 2, "syncEntities.Count >= 2");
            Debug.Assert(syncTables[0].Type == typeof(DeletedRecord), "syncEntities[0].Type == typeof(DeletedRecord)");
            Debug.Assert(syncTables[1].Type == typeof(User), "syncEntities[1].Type == typeof(User)");

            //synchronizationParameters.Notif((syncTables.Count >= 2) + "syncEntities.Count >= 2");
            //synchronizationParameters.Notif((syncTables[0].Type == typeof(DeletedRecord)) + "syncEntities[0].Type == typeof(DeletedRecord)");
            //synchronizationParameters.Notif((syncTables[1].Type == typeof(User)) +  "syncEntities[1].Type == typeof(User)");

            for (int i = 0; i < syncTables.Count; i++)
            {
                EntitySync sync = syncTables[i];

                // Handle each PostXxx Action different for last SyncEntity
                if (sync == syncTables.Last())
                {
                    // After last upload start with first SyncEntity download
                    sync.PostUp = syncTables[0].Down;
                    // After last download invoke finalAction
                    sync.PostDown = () =>
                    {
                        NotificationService.Send(NotificationEvent.Synchronized);
                        synchronizationParameters.FinalAction();
                    };
                }
                else
                {
                    // after up-/download start up-/download of next SyncEntity
                    sync.PostUp   = syncTables[i + 1].Up;
                    sync.PostDown = syncTables[i + 1].Down;
                }
            }

            synchronizationParameters.EntitiesInSynchronization[1].PostUp = synchronizationParameters.EntitiesInSynchronization[0].Down;

            synchronizationParameters.Downloaded                             =
                synchronizationParameters.Uploaded                           =
                    synchronizationParameters.RecordsToDelete                =
                        synchronizationParameters.RecordsDeleted             =
                            synchronizationParameters.RecordsDeletedAtServer = 0;

            synchronizationParameters.EntitiesInSynchronization[0].Up();
        }
Esempio n. 4
0
        private LastEntitySyncTime GetLastSyncTime <T>(SynchronizationParameters synchronizationParameters) where T : AbstractEntity, new()
        {
            string             entityName  = typeof(T).Name;
            LastEntitySyncTime lastSyncObj = DatabaseConnection.Connection.Query <LastEntitySyncTime>("select * from [LastEntitySyncTime] " +
                                                                                                      "where [EntityName] = ?", new[] { entityName }).FirstOrDefault();

            if (lastSyncObj == null)
            {
                List <T> entities     = DatabaseConnection.Connection.Query <T>("select * from [" + entityName + "]");
                DateTime lastSyncTime = entities.Count == 0 ? default(DateTime) : entities.Select(o => o.ModifiedDate).Max();

                DatabaseConnection.Connection.Insert(lastSyncObj = new LastEntitySyncTime {
                    EntityName = entityName, LastDownloadTime = lastSyncTime
                });
            }

            return(lastSyncObj);
        }
Esempio n. 5
0
        private async void DeleteAsync(SynchronizationParameters synchronizationParameters, Action finishedNotification)
        {
            IRestService <User> restService = new RestService <User>(synchronizationParameters);

            try
            {
                await restService.UploadAsync(new List <ToDelete>(QueryEntities <DeletedRecord>(synchronizationParameters)
                                                                  .Select(d => new ToDelete
                {
                    Entity = d.EntityName.Split('.').Last(),
                    Pk = d.EntityPk
                })), synchronizationParameters.ExceptionHandler, "users/singleRequestDelete");

                finishedNotification();
            }
            catch (Exception exception)
            {
                synchronizationParameters.ExceptionHandler(exception);
            }
        }
Esempio n. 6
0
 private void UploadAsync <T>(SynchronizationParameters synchronizationParameters, Action finishedNotification) where T : AbstractEntity, new()
 {
     if (typeof(T) == typeof(DeletedRecord))
     {
         //synchronizationParameters.Notif("UploadAsync(DeletedRecord)");
         //DeleteAsync(synchronizationParameters, finishedNotification);
         finishedNotification();
         //synchronizationParameters.Notif("UploadAsync(DeletedRecord) finished");
     }
     else if (typeof(T) == typeof(User))
     {
         //synchronizationParameters.Notif("UploadAsync(User)");
         UploadAsyncSingleRequest(synchronizationParameters, finishedNotification);
         //synchronizationParameters.Notif("UploadAsync(User) finished");
     }
     else
     {
         Debug.Assert(false, "Unexpected type in upload: " + typeof(T).Name);
     }
 }
Esempio n. 7
0
 private List <T> QueryEntities <T>(SynchronizationParameters synchronizationParameters) where T : AbstractEntity, new()
 {
     return(DatabaseConnection.Connection.Query <T>("select * from [" + typeof(T).Name + "] where IsPending = 1 order by ModifiedDate"));
 }
Esempio n. 8
0
        private async void UploadAsyncSingleRequest(SynchronizationParameters synchronizationParameters, Action finishedNotification)
        {
            Stopwatch watch = new Stopwatch();

            watch.Start();

            IRestService <User>          restService    = new RestService <User>(synchronizationParameters);
            IDictionary <string, object> underlyingRoot = new ExpandoObject();
            bool exceptionOccured             = false;
            List <AbstractEntity> allEntities = new List <AbstractEntity>();
            int entitiesInRequest             = 0;
            int requestCount = 0;

            foreach (EntitySync entity in synchronizationParameters.EntitiesInSynchronization)
            {
                string entityName = entity.Type.Name;

                if (synchronizationParameters.DontUpload.Contains(entityName))
                {
                    continue;
                }

                List <AbstractEntity> entities = entity.Getter("select * from " + entityName + " where IsPending=1 order by ModifiedDate");

                if (entities.Count == 0)
                {
                    continue;
                }

                allEntities.AddRange(entities);

                Dictionary <string, PropertyInfo> foreignKeys = GetForeignKeyProperties(entity.Type);
                var grouped = entities
                              .GroupBy(e => foreignKeys.Count == 0 ?
                                       "" :
                                       foreignKeys.Select(f => f.Value.GetValue(e)).Aggregate((i, j) => i + "," + j))
                              .ToDictionary(g =>
                {
                    Dictionary <string, string> keys = new Dictionary <string, string>();
                    string[] values = g.Key.ToString().Split(',');
                    int index       = 0;

                    foreach (KeyValuePair <string, PropertyInfo> kvp in foreignKeys)
                    {
                        keys.Add(kvp.Key, values[index++]);
                    }

                    return(keys);
                }, g => g);

                Debug.WriteLine("now " + entityName + ", until now " + allEntities.Count + " entities");

                if (entitiesInRequest + entities.Count > GeneratedConstants.UploadPageSize)
                {
                    List <object> l = new List <object>();

                    underlyingRoot.Add(restService.ListProperty(entity.Type), l);

                    foreach (var group in grouped)
                    {
                        int          groupCount = group.Value.Count();
                        List <int[]> pieces     = CutIntoPieces(entitiesInRequest, groupCount);

                        if (pieces.Count == 0)
                        {
                            l.Add(new
                            {
                                ForeignKeys = group.Key,
                                Values      = group.Value
                            });
                            entitiesInRequest += group.Value.Count();
                        }
                        else
                        {
                            foreach (int[] piece in pieces)
                            {
                                l.Add(new
                                {
                                    ForeignKeys = group.Key,
                                    Values      = group.Value.Skip(piece[0]).Take(piece[1])
                                });

                                await UploadAsync(
                                    restService,
                                    underlyingRoot,
                                    exception => { exceptionOccured = true; ExceptionHandler(synchronizationParameters, exception); }, requestCount ++);

                                if (exceptionOccured)
                                {
                                    return;
                                }

                                underlyingRoot = new ExpandoObject();
                                underlyingRoot.Add(restService.ListProperty(entity.Type), l = new List <object>());
                            }

                            entitiesInRequest = pieces.Last()[1];
                        }
                    }
                }
                else
                {
                    underlyingRoot.Add(restService.ListProperty(entity.Type), grouped.Select(g => new
                    {
                        ForeignKeys = g.Key,
                        Values      = g.Value
                    }));
                    entitiesInRequest += entities.Count;
                }
            }

            if (!exceptionOccured)
            {
                await UploadAsync(
                    restService,
                    underlyingRoot,
                    exception => { exceptionOccured = true; ExceptionHandler(synchronizationParameters, exception); }, requestCount ++);
            }

            if (!exceptionOccured)
            {
                Stopwatch watchUpdatePending = new Stopwatch();

                watchUpdatePending.Start();

                foreach (var group in allEntities.GroupBy(e => e.GetType()))
                {
                    DatabaseConnection.Connection.Execute("update " + group.Key.Name + " set IsPending = 0 where Pk in (" +
                                                          group.Select(e => "'" + e.Pk + "'").Aggregate((i, j) => i + "," + j) + ")");
                }

                //foreach (AbstractEntity entity in allEntities)
                //{
                //    entity.IsPending = false;
                //    db.Update(entity);
                //}

                Debug.WriteLine("watchUpdatePending needed: " + watchUpdatePending.Elapsed);

                synchronizationParameters.Uploaded = allEntities.Count;
                finishedNotification();

                return;
            }
        }
Esempio n. 9
0
 private void ExceptionHandler(SynchronizationParameters synchronizationParameters, Exception exception)
 {
     NotificationService.Send(NotificationEvent.SynchronizationFailed);
     synchronizationParameters.ExceptionHandler(exception);
 }
Esempio n. 10
0
        private async void DownloadAsync <T>(SynchronizationParameters synchronizationParameters, Action finishedNotification) where T : AbstractEntity, new()
        {
            LastEntitySyncTime lastSyncRecord = GetLastSyncTime <T>(synchronizationParameters);
            RestService <T>    restService    = new RestService <T>(synchronizationParameters);

#if DEBUG
            Stopwatch watch = new Stopwatch();
            TimeSpan  elapsed;

            watch.Start();
#endif

            try
            {
                int pageCount = 0;
                DownloadResult <T> downloadResult;

                do
                {
                    downloadResult = await restService.DownloadAsync(lastSyncRecord.LastDownloadTime, pageCount, GeneratedConstants.DownloadPageSize);

#if DEBUG
                    if (GeneratedConstants.LogDebug && typeof(T).Name == "GlucoseValue")
                    {
                        elapsed = watch.Elapsed;
                        watch.Restart();
                        Debug.WriteLine("Download " + typeof(T).Name + " page=" + pageCount + ", size=" + GeneratedConstants.DownloadPageSize + " needed " + elapsed);
                    }
#endif

                    pageCount++;

                    if (previousTask != null)
                    {
                        await previousTask;
                    }

                    if (downloadResult.Items.Count > 0)
                    {
                        previousTask = Task.Factory.StartNew(() =>
                        {
                            Stopwatch refreshWatch = new Stopwatch();

                            refreshWatch.Start();

                            List <T> objectsForUpdateLocal = new List <T>(downloadResult.Items);

                            if (typeof(T) == typeof(DeletedRecord) && objectsForUpdateLocal.Count > 0)
                            {
                                foreach (T obj in objectsForUpdateLocal)
                                {
                                    synchronizationParameters.RecordsToDelete++;

                                    DeletedRecord deletedRecord = obj as DeletedRecord;

                                    int deletedRecords = DatabaseConnection
                                                         .Connection
                                                         .Execute("delete from [" + deletedRecord.EntityName + "] where [Pk] = ?",
                                                                  new[] { deletedRecord.EntityPk });

                                    if (synchronizationParameters.Refresh != null && refreshWatch.Elapsed >= TimeSpan.FromSeconds(1))
                                    {
                                        synchronizationParameters.Refresh();
                                        refreshWatch.Restart();
                                    }

                                    synchronizationParameters.RecordsDeleted += deletedRecords;
                                }

                                DatabaseConnection.Connection.Execute("delete from DeletedRecord where EntityPk in (" +
                                                                      objectsForUpdateLocal.Select(o => "'" + (o as DeletedRecord).EntityPk + "'").Aggregate((i, j) => i + "," + j) + ")");

                                if (synchronizationParameters.Refresh != null && refreshWatch.Elapsed >= TimeSpan.FromSeconds(1))
                                {
                                    synchronizationParameters.Refresh();
                                    refreshWatch.Restart();
                                }
#if DEBUG
                                if (GeneratedConstants.LogDebug)
                                {
                                    elapsed = watch.Elapsed;
                                    watch.Restart();
                                    Debug.WriteLine("Performing delete actions, count=" + objectsForUpdateLocal.Count + " needed " + elapsed);
                                }
#endif
                            }
                            else
                            {
                                foreach (T obj in objectsForUpdateLocal)
                                {
                                    try
                                    {
                                        DatabaseConnection.Connection.Insert(obj);
                                    }
                                    catch (Exception)
                                    {
                                        DatabaseConnection.Connection.GetChildren(obj);
                                        obj.IsPending = false;
                                        DatabaseConnection.Connection.Update(obj);
                                    }

                                    synchronizationParameters.Downloaded++;

                                    if (synchronizationParameters.Refresh != null && refreshWatch.Elapsed >= TimeSpan.FromSeconds(1))
                                    {
                                        synchronizationParameters.Refresh();
                                        refreshWatch.Restart();
                                    }
                                }
#if DEBUG
                                if (GeneratedConstants.LogDebug && typeof(T).Name == "GlucoseValue")
                                {
                                    elapsed = watch.Elapsed;
                                    watch.Restart();
                                    Debug.WriteLine("Insert/update actions, count=" + objectsForUpdateLocal.Count + " needed " + elapsed);
                                }
#endif
                            }

                            if (!downloadResult.FetchNextPage)
                            {
                                lastSyncRecord.LastDownloadTime = objectsForUpdateLocal.Last().ModifiedDate;
                                DatabaseConnection.Connection.Update(lastSyncRecord);
                            }
                        });
                    }
                } while (downloadResult.FetchNextPage);

                finishedNotification();
            }
            catch (Exception exception)
            {
                Debug.WriteLine(exception.StackTrace);
                ExceptionHandler(synchronizationParameters, exception);
            }
            finally
            {
                synchronizationParameters.Refresh?.Invoke();
            }
        }