示例#1
0
        /// <summary>
        /// Get the conflict item
        /// </summary>
        /// <returns>Conflict item</returns>
        public virtual Conflict GetConflict()
        {
            if (!HasConflict())
            {
                return(null);
            }

            Conflict conflict = null;

            if (_currentEntryWrapper.IsConflict)
            {
                conflict = new SyncConflict
                {
                    LiveEntity   = _liveEntity,
                    LosingEntity = CreateEntity(_currentEntryWrapper.ConflictWrapper, _knownTypesDict),
                    Resolution   = (SyncConflictResolution)Enum.Parse(FormatterConstants.SyncConflictResolutionType, _currentEntryWrapper.ConflictDesc, true)
                };
            }
            else
            {
                conflict = new SyncError
                {
                    LiveEntity  = _liveEntity,
                    ErrorEntity = CreateEntity(_currentEntryWrapper.ConflictWrapper, _knownTypesDict),
                    Description = _currentEntryWrapper.ConflictDesc
                };
            }

            return(conflict);
        }
示例#2
0
        /// <summary>
        /// Get the conflict item
        /// </summary>
        /// <returns>Conflict item</returns>
        public virtual Conflict GetConflict()
        {
            if (!HasConflict())
            {
                return(null);
            }

            Conflict conflict;

            if (currentEntryWrapper.IsConflict)
            {
                conflict = new SyncConflict
                {
                    LiveEntity   = liveEntity,
                    LosingEntity = ReflectionUtility.GetObjectForType(currentEntryWrapper.ConflictWrapper, knownTypes),
                    Resolution   =
                        (SyncConflictResolution)
                        Enum.Parse(FormatterConstants.SyncConflictResolutionType,
                                   currentEntryWrapper.ConflictDesc, true)
                };
            }
            else
            {
                conflict = new SyncError
                {
                    LiveEntity  = liveEntity,
                    ErrorEntity =
                        ReflectionUtility.GetObjectForType(currentEntryWrapper.ConflictWrapper,
                                                           knownTypes),
                    Description = currentEntryWrapper.ConflictDesc
                };
            }

            return(conflict);
        }
示例#3
0
        public async Task Save <T>(T item, ESyncStatus syncStatus = ESyncStatus.Success, Exception exception = null, bool update = false)  where  T : Entity, new()
        {
            var c = GetAsyncConnection();

            item.SyncStatus = (byte)syncStatus;

            if (exception != null)
            {
                var error = new SyncError()
                {
                    Date = DateTime.Now, Identity = Guid.NewGuid().ToString(), Message = exception.Message
                };

                item.SyncErrorId = error.Identity;

                await c.InsertAsync(error);
            }

            if (!update && (await c.FindAsync <T>(item.Identity)) == null)
            {
                await c.InsertAsync(item);
            }
            else
            {
                await c.UpdateAsync(item);
            }
        }
 /// <summary>
 /// Called by SyncErrorInfo from the ClearSyncError method.  Used to remove the error
 /// from the collection and from the disk
 /// </summary>
 ///<param name="error">SyncError</param>
 internal void ClearSyncError(SyncError error)
 {
     using (_saveSyncLock.LockObject())
     {
         _cacheData.RemoveSyncError(error);
         _storageHandler.ClearSyncError((IsolatedStorageSyncError)error);
     }
 }
示例#5
0
        public void AddSerializedError(SyncError error, IsolatedStorageOfflineContext context)
        {
            IsolatedStorageSyncError oldError = (IsolatedStorageSyncError)Collections[error.ErrorEntity.GetType()].MapSyncError((IsolatedStorageOfflineEntity)error.LiveEntity, error, context);

            SyncErrors.Add(error);

            if (oldError != null)
            {
                ClearSyncError(oldError, context);
            }
        }
示例#6
0
        public void AddSerializedError(SyncError error, WinEightContext context)
        {
            SyncError oldError = (SyncError)Collections[error.ErrorEntity.GetType()].MapSyncError((OfflineEntity)error.LiveEntity, error, context);

            SyncErrors.Add(error);

            if (oldError != null)
            {
                ClearSyncError(oldError, context);
            }
        }
示例#7
0
        /// <summary>
        /// Clears the sync error and removes it from the error list on the c.
        /// </summary>
        public void ClearSyncError()
        {
            if (syncError != null)
            {
                context.ClearSyncError(syncError);
                syncError = null;

                OnPropertyChanged("SyncError");
                OnPropertyChanged("HasSyncError");
            }
        }
示例#8
0
        /// <summary>
        /// Adds a error to the list of in-memory
        /// </summary>
        /// <param name="error"></param>
        /// <param name="context">Context for the conflict is being added</param>
        public void AddSyncError(SyncError error, WinEightContext context)
        {
            OfflineEntity entity   = Collections[error.LiveEntity.GetType()].AddOrUpdateSyncEntity((OfflineEntity)error.LiveEntity);
            SyncError     oldError = Collections[error.LiveEntity.GetType()].MapSyncError(entity, error, context);

            SyncErrors.Add(error);

            if (oldError != null)
            {
                ClearSyncError(oldError, context);
            }
        }
示例#9
0
        /// <summary>
        /// Clears the sync error and removes it from the error list on the c.
        /// </summary>
        public async Task ClearSyncError()
        {
            if (syncError != null)
            {
                await context.ClearSyncError(syncError);

                syncError = null;

                OnPropertyChanged("SyncError");
                OnPropertyChanged("HasSyncError");
            }
        }
示例#10
0
        /// <summary>
        /// Sets the sync error, providing the cache data so that the error can be removed if ClearSyncerror
        /// is called.
        /// </summary>
        ///<param name="c">IsolatedStorageOfflineContext</param>
        /// <param name="se">error to set.</param>
        internal void SetSyncError(WinEightContext c, SyncError se)
        {
            SyncError oldError = this.syncError;

            this.context   = c;
            this.syncError = se;

            OnPropertyChanged("SyncError");

            if (oldError == null)
            {
                OnPropertyChanged("HasSyncError");
            }
        }
示例#11
0
        /// <summary>
        /// Sets the sync error, providing the cache data so that the error can be removed if ClearSyncerror
        /// is called.
        /// </summary>
        ///<param name="context">IsolatedStorageOfflineContext</param>
        /// <param name="syncError">error to set.</param>
        internal void SetSyncError(IsolatedStorageOfflineContext context, SyncError syncError)
        {
            SyncError oldError = this._syncError;

            this._context   = context;
            this._syncError = syncError;

            OnPropertyChanged("SyncError");

            if (oldError == null)
            {
                OnPropertyChanged("HasSyncError");
            }
        }
示例#12
0
        /// <summary>
        /// This function loops the rejected entites and sends back a SyncError for each entity. For each entity it does the following
        /// 1. Retrieve the current version in server.
        /// 1.a If its null then it copies the primary key to a new object and marks it as tombstone.
        /// 2. Adds the SyncError to existing list of SyncErrors.
        /// </summary>
        /// <param name="sqlProvider"></param>
        private void ProcessRejectedEntities(SqlSyncProviderService sqlProvider)
        {
            if (this._rejectedEntities == null || this._rejectedEntities.Count == 0)
            {
                return;
            }

            try
            {
                List <IOfflineEntity> serverVersions = sqlProvider.GetCurrentServerVersionForEntities(this._rejectedEntities.Keys);
                if (serverVersions.Count != this._rejectedEntities.Count)
                {
                    // Ensure we get a server version for each entity we passed
                    throw new InvalidOperationException("Did not get server versions for all rejected entities.");
                }
                for (int i = 0; i < this._rejectedEntities.Keys.Count; i++)
                {
                    IOfflineEntity server = serverVersions[i];
                    IOfflineEntity client = this._rejectedEntities.Keys.ElementAt(i);

                    if (server == null)
                    {
                        // This means the server didnt contain a version for the entity. Need to send a tombstone back then
                        // create a new object and copy the values over
                        ConstructorInfo constructorInfo = client.GetType().GetConstructor(Type.EmptyTypes);
                        server = (IOfflineEntity)constructorInfo.Invoke(null);
                        // Copy the primary key values over
                        foreach (PropertyInfo info in ReflectionUtility.GetPrimaryKeysPropertyInfoMapping(client.GetType()))
                        {
                            info.SetValue(server, info.GetValue(client, null), null);
                        }
                        server.ServiceMetadata.IsTombstone = true;
                    }

                    SyncError error = new SyncError()
                    {
                        ErrorEntity = client,
                        LiveEntity  = server,
                        Description = this._rejectedEntities[client]
                    };

                    _applyChangesResponse.Errors.Add(error);
                }
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Error in reading server row values. " + e.Message);
            }
        }
示例#13
0
        /// <summary>
        /// Called by SyncErrorInfo from the ClearSyncError method.  Used to remove the error
        /// from the collection and from the disk
        /// </summary>
        ///<param name="error">SyncError</param>
        internal async Task ClearSyncError(SyncError error)
        {
            using (saveSyncLock.LockObject())
            {
                WinEightSyncError winEightSyncError = error as WinEightSyncError;

                if (winEightSyncError == null)
                {
                    return;
                }

                cacheData.RemoveSyncError(error);
                await StorageHandler.ClearSyncError(winEightSyncError);
            }
        }
示例#14
0
        private void UpdateTimer_Tick(object sender, EventArgs e)
        {
            if (syncErrorText != null)
            {
                SyncError.SetError(TimeLabel, syncErrorText);
                if (syncErrorText.Length > 0)
                {
                    SyncStatusLabel.Text      = "Could not synchronize.";
                    SyncStatusLabel.ForeColor = Color.Red;
                    syncErrorText             = null;
                    prevSyncTime = DateTime.MinValue;
                }
            }

            if (prevSyncTime != DateTime.MinValue)
            {
                SyncStatusLabel.Text      = string.Format("Sync at {0} ({1:0.000} sec)", FormatTime(prevSyncTime), prevAdjustment);
                SyncStatusLabel.ForeColor = Color.LightGreen;
            }
        }
示例#15
0
 public void AddSyncError(SyncError error, OfflineContext context)
 {
 }
示例#16
0
 public void AddSerializedError(SyncError error, IsolatedStorageOfflineContext context)
 {
 }
        /// <summary>
        /// This function loops the rejected entites and sends back a SyncError for each entity. For each entity it does the following
        /// 1. Retrieve the current version in server.
        /// 1.a If its null then it copies the primary key to a new object and marks it as tombstone.
        /// 2. Adds the SyncError to existing list of SyncErrors.
        /// </summary>
        /// <param name="sqlProvider"></param>
        private void ProcessRejectedEntities(SqlSyncProviderService sqlProvider)
        {
            if (this._rejectedEntities == null || this._rejectedEntities.Count == 0)
            {
                return;
            }

            try
            {
                List<IOfflineEntity> serverVersions = sqlProvider.GetCurrentServerVersionForEntities(this._rejectedEntities.Keys);
                if (serverVersions.Count != this._rejectedEntities.Count)
                {
                    // Ensure we get a server version for each entity we passed
                    throw new InvalidOperationException("Did not get server versions for all rejected entities.");
                }
                for (int i = 0; i < this._rejectedEntities.Keys.Count; i++)
                {
                    IOfflineEntity server = serverVersions[i];
                    IOfflineEntity client = this._rejectedEntities.Keys.ElementAt(i);

                    if (server == null)
                    {
                        // This means the server didnt contain a version for the entity. Need to send a tombstone back then
                        // create a new object and copy the values over
                        ConstructorInfo constructorInfo = client.GetType().GetConstructor(Type.EmptyTypes);
                        server = (IOfflineEntity)constructorInfo.Invoke(null);
                        // Copy the primary key values over
                        foreach (PropertyInfo info in ReflectionUtility.GetPrimaryKeysPropertyInfoMapping(client.GetType()))
                        {
                            info.SetValue(server, info.GetValue(client, null), null);
                        }
                        server.ServiceMetadata.IsTombstone = true;
                    }

                    SyncError error = new SyncError()
                    {
                        ErrorEntity = client,
                        LiveEntity = server,
                        Description = this._rejectedEntities[client]
                    };

                    _applyChangesResponse.Errors.Add(error);
                }
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Error in reading server row values. " + e.Message);
            }
        }
 public abstract SyncError MapSyncError(IsolatedStorageOfflineEntity entity, SyncError error, IsolatedStorageOfflineContext context);
示例#19
0
 /// <summary>
 /// Removes the specified sync error
 /// </summary>
 /// <param name="error">Error to remove</param>
 public void RemoveSyncError(SyncError error)
 {
     SyncErrors.Remove(error);
 }
示例#20
0
 public WinEightSyncError(SyncError error)
 {
     this.LiveEntity = error.LiveEntity;
     this.ErrorEntity = error.ErrorEntity;
     this.Description = error.Description;
 }
 public IsolatedStorageSyncError(SyncError error)
 {
     this.LiveEntity = error.LiveEntity;
     this.ErrorEntity = error.ErrorEntity;
     this.Description = error.Description;
 }
示例#22
0
 public SyncException(SyncError error, string message) : base(message)
 {
     mError = error;
 }
示例#23
0
 private async void ClearSyncError(SyncError syncError, WinEightContext context)
 {
     RemoveSyncError(syncError);
     await context.ClearSyncError(syncError);
 }
示例#24
0
 public SyncException(SyncError error, string message)
     : base(message)
 {
     mError = error;
 }
示例#25
0
 /// <summary>
 /// Removes the specified sync error
 /// </summary>
 /// <param name="error">Error to remove</param>
 public void RemoveSyncError(SyncError error)
 {
     SyncErrors.Remove(error);
 }
示例#26
0
 private async void ClearSyncError(SyncError syncError, WinEightContext context)
 {
     RemoveSyncError(syncError);
     await context.ClearSyncError(syncError);
 }
示例#27
0
 public SyncException(SyncError error)
     : base(error.getMessage())
 {
     mError = error;
 }
示例#28
0
 public void RemoveSyncError(SyncError error)
 {
 }
示例#29
0
        /// <summary>
        /// Clears the sync error and removes it from the error list on the c.
        /// </summary>
        public async Task ClearSyncError()
        {
            if (syncError != null)
            {
                await context.ClearSyncError(syncError);
                syncError = null;

                OnPropertyChanged("SyncError");
                OnPropertyChanged("HasSyncError");
            }
        }
示例#30
0
 public SyncException(SyncError error) : base(error.getMessage())
 {
     mError = error;
 }
示例#31
0
        public void AddSerializedError(SyncError error, WinEightContext context)
        {
            SyncError oldError = (SyncError)Collections[error.ErrorEntity.GetType()].MapSyncError((OfflineEntity)error.LiveEntity, error, context);

            SyncErrors.Add(error);

            if (oldError != null)
            {                
                ClearSyncError(oldError,context);
            }
        }
示例#32
0
 public SyncException(SyncError error, Exception cause) : base(error.getMessage(), cause)
 {
     mError = error;
 }
示例#33
0
 public void AddSerializedError(SyncError error, OfflineContext context)
 {
 }
示例#34
0
        /// <summary>
        /// Sets the sync error, providing the cache data so that the error can be removed if ClearSyncerror
        /// is called.
        /// </summary>
        ///<param name="c">IsolatedStorageOfflineContext</param>
        /// <param name="se">error to set.</param>
        internal void SetSyncError(WinEightContext c, SyncError se)
        {
            SyncError oldError = this.syncError;

            this.context = c;
            this.syncError = se;

            OnPropertyChanged("SyncError");

            if (oldError == null)
            {
                OnPropertyChanged("HasSyncError");
            }
        }
示例#35
0
 private void ClearSyncError(SyncError syncError, IsolatedStorageOfflineContext context)
 {
     RemoveSyncError(syncError);
     context.StorageHandler.ClearSyncError((IsolatedStorageSyncError)syncError);
 }
示例#36
0
 protected virtual void OnSyncErrorReceived(byte code, SyncError <T> command)
 {
     OnCommandReceived(code, command);
     SyncErrorReceived.Raise(this, new CommandReceivedEventArgs <T, SyncError <T> >(code, command));
 }
        /// <summary>
        ///
        /// </summary>
        /// <param name="asynchronousResult"></param>
        private void downloadCallback(IAsyncResult asynchronousResult)
        {
            DownloadRequestState reqState = (DownloadRequestState)asynchronousResult.AsyncState;
            HttpWebRequest       request  = reqState.request;

            string callbackId = reqState.options.CallbackId;

            try
            {
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);

                // send a progress change event
                DispatchSyncProgress(0, response.ContentLength, 0, callbackId);

                using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    // create any directories in the path that do not exist
                    string directoryName = getDirectoryName(reqState.options.FilePath);
                    if (!string.IsNullOrEmpty(directoryName) && !isoFile.DirectoryExists(directoryName))
                    {
                        isoFile.CreateDirectory(directoryName);
                    }

                    // make sure we delete the file if it exists
                    if (isoFile.FileExists(reqState.options.FilePath))
                    {
                        isoFile.DeleteFile(reqState.options.FilePath);
                    }

                    if (!isoFile.FileExists(reqState.options.FilePath))
                    {
                        var file = isoFile.CreateFile(reqState.options.FilePath);
                        file.Close();
                    }

                    using (FileStream fileStream = new IsolatedStorageFileStream(reqState.options.FilePath, FileMode.Open, FileAccess.Write, isoFile))
                    {
                        long totalBytes = response.ContentLength;
                        int  bytesRead  = 0;
                        using (BinaryReader reader = new BinaryReader(response.GetResponseStream()))
                        {
                            using (BinaryWriter writer = new BinaryWriter(fileStream))
                            {
                                int    BUFFER_SIZE = 1024;
                                byte[] buffer;

                                while (true)
                                {
                                    buffer = reader.ReadBytes(BUFFER_SIZE);
                                    // fire a progress event ?
                                    bytesRead += buffer.Length;
                                    if (buffer.Length > 0 && !reqState.isCancelled)
                                    {
                                        writer.Write(buffer);
                                        DispatchSyncProgress(bytesRead, totalBytes, 1, callbackId);
                                    }
                                    else
                                    {
                                        writer.Close();
                                        reader.Close();
                                        fileStream.Close();
                                        break;
                                    }
                                    System.Threading.Thread.Sleep(1);
                                }
                            }
                        }
                    }
                    if (reqState.isCancelled)
                    {
                        isoFile.DeleteFile(reqState.options.FilePath);
                    }
                }

                if (reqState.isCancelled)
                {
                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new SyncError(AbortError)),
                                          callbackId);
                }
                else
                {
                    UnZip  unzipper     = new UnZip();
                    string destFilePath = "www/" + reqState.options.FilePath;
                    // at this point, bytesLoaded = bytesTotal so we'll just put the as '1'
                    DispatchSyncProgress(1, 1, 2, callbackId);
                    unzipper.unzip(reqState.options.FilePath, destFilePath, reqState.options.Type);

                    if (reqState.options.CopyCordovaAssets)
                    {
                        copyCordovaAssets(destFilePath);
                    }

                    DispatchSyncProgress(1, 1, 3, callbackId);
                    string result = "{ \"localPath\": \"" + reqState.options.FilePath + "\" , \"Id\" : \"" + reqState.options.Id + "\"}";
                    DispatchCommandResult(new PluginResult(PluginResult.Status.OK, result), callbackId);
                }
            }
            catch (IsolatedStorageException)
            {
                // Trying to write the file somewhere within the IsoStorage.
                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new SyncError(UnzipError)),
                                      callbackId);
            }
            catch (SecurityException)
            {
                // Trying to write the file somewhere not allowed.
                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new SyncError(UnzipError)),
                                      callbackId);
            }
            catch (WebException webex)
            {
                // TODO: probably need better work here to properly respond with all http status codes back to JS
                // Right now am jumping through hoops just to detect 404.
                HttpWebResponse response = (HttpWebResponse)webex.Response;
                if ((webex.Status == WebExceptionStatus.ProtocolError && response.StatusCode == HttpStatusCode.NotFound) ||
                    webex.Status == WebExceptionStatus.UnknownError)
                {
                    // Weird MSFT detection of 404... seriously... just give us the f(*&#$@ status code as a number ffs!!!
                    // "Numbers for HTTP status codes? Nah.... let's create our own set of enums/structs to abstract that stuff away."
                    // FACEPALM
                    // Or just cast it to an int, whiner ... -jm
                    int    statusCode = (int)response.StatusCode;
                    string body       = "";

                    using (Stream streamResponse = response.GetResponseStream())
                    {
                        using (StreamReader streamReader = new StreamReader(streamResponse))
                        {
                            body = streamReader.ReadToEnd();
                        }
                    }
                    SyncError ftError = new SyncError(ConnectionError, null, null, statusCode, body);
                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ftError),
                                          callbackId);
                }
                else
                {
                    lock (reqState)
                    {
                        if (!reqState.isCancelled)
                        {
                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
                                                                   new SyncError(ConnectionError)),
                                                  callbackId);
                        }
                        else
                        {
                            Debug.WriteLine("It happened");
                        }
                    }
                }
            }
            catch (Exception)
            {
                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
                                                       new SyncError(UnzipError)),
                                      callbackId);
            }

            //System.Threading.Thread.Sleep(1000);
            if (InProcDownloads.ContainsKey(reqState.options.Id))
            {
                InProcDownloads.Remove(reqState.options.Id);
            }
        }
        private void ResolveConflict(ConflictResult result, SaveData localSave, SaveData cloudSave)
        {
            LoadState cloudState;

            switch (result)
            {
            case ConflictResult.Cloud:
                Debug.Log("SaveGameManager (ResolveConflict) :: Resolving conflict with cloud save!");
                if (OverrideLocalSave(cloudSave, localSave))
                {
                    m_comparator.ReconcileData(localSave, cloudSave);
                    cloudSave.Save();
                    cloudState = LoadSystems(cloudSave);
                    if (cloudState == LoadState.OK)
                    {
                        m_saveData = cloudSave;
                        m_syncCompleteCallback(null, SyncState.Successful);
                    }
                    else
                    {
                        //Reset to local
                        LoadSystems(localSave);
                        m_saveData = localSave;
                        //TODO may need more specific errors
                        m_syncCompleteCallback(new SyncError("Failed to load resolved cloud save", ErrorCodes.SaveError), SyncState.Error);
                    }
                }
                else
                {
                    m_syncCompleteCallback(new SyncError("Failed to Override Local Save", ErrorCodes.SaveError), SyncState.Error);
                }
                break;

            case ConflictResult.Local:
                Debug.Log("SaveGameManager (ResolveConflict) :: Resolving conflict with local save!");
                m_comparator.ReconcileData(localSave, cloudSave);
                localSave.Save();
                LoadState localState = LoadSystems(localSave);
                if (localState == LoadState.OK)
                {
                    UploadSave(m_syncUser, localSave, delegate(Error error)
                    {
                        if (error != null && error.GetType() != typeof(UploadDisallowedError))
                        {
                            m_syncCompleteCallback(error, SyncState.Error);
                        }
                        else
                        {
                            m_saveData = localSave;
                            m_syncCompleteCallback(null, SyncState.Successful);
                        }
                    });
                }
                else
                {
                    //TODO may need more specific errors
                    m_syncCompleteCallback(new SyncError("Failed to load resolved cloud save", ErrorCodes.SaveError), SyncState.Error);
                }

                break;

            case ConflictResult.ForceCloud:
                SyncError forceCloudError = null;
                // Make sure we reset force override as otherwise user save file will get overriden again next time
                // If the flag doesn't exist (upgrading from old save?), just ignore the exception
                try
                {
                    cloudSave["User.ForceOverride"] = false;
                    localSave["User.ForceOverride"] = false;
                }
                catch (Exception e)
                {
                    Debug.LogException(e);
                }
                if (OverrideLocalSave(cloudSave, localSave))
                {
                    cloudSave.Save();

                    cloudState = LoadSystems(cloudSave);

                    if (cloudState == LoadState.OK)
                    {
                        m_saveData = cloudSave;
                        m_saveData.Save();
                    }
                    else
                    {
                        //Reset to local
                        LoadSystems(localSave);

                        m_saveData = localSave;
                        //TODO may need more specific errors
                        forceCloudError = new SyncError("Failed to load resolved cloud save", ErrorCodes.SaveError);
                    }
                }
                else
                {
                    m_saveData      = localSave;
                    forceCloudError = new SyncError("Failed to Override Local Save", ErrorCodes.SaveError);
                }
                // Upload the new save to cloud to delete forceOverride flag
                UploadSave(m_syncUser, m_saveData, delegate(Error error)
                {
                    if (error != null)
                    {
                        m_syncCompleteCallback(error, SyncState.Error);
                    }
                    else
                    {
                        m_syncCompleteCallback(forceCloudError, forceCloudError == null ? SyncState.Successful : SyncState.Error);
                    }
                });
                break;
            }
        }
示例#39
0
 private void ClearSyncError(SyncError syncError, IsolatedStorageOfflineContext context)
 {
     RemoveSyncError(syncError);
     context.StorageHandler.ClearSyncError((IsolatedStorageSyncError)syncError);
 }
示例#40
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="asynchronousResult"></param>
        private void downloadCallback(IAsyncResult asynchronousResult)
        {
            DownloadRequestState reqState = (DownloadRequestState)asynchronousResult.AsyncState;
            HttpWebRequest request = reqState.request;

            string callbackId = reqState.options.CallbackId;
            try
            {
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);

                // send a progress change event
                DispatchSyncProgress(0, response.ContentLength, 0, callbackId);

                using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    // create any directories in the path that do not exist
                    string directoryName = getDirectoryName(reqState.options.FilePath);
                    if (!string.IsNullOrEmpty(directoryName) && !isoFile.DirectoryExists(directoryName))
                    {
                        isoFile.CreateDirectory(directoryName);
                    }

                    // make sure we delete the file if it exists
                    if(isoFile.FileExists(reqState.options.FilePath))
                    {
                        isoFile.DeleteFile(reqState.options.FilePath);
                    }

                    if (!isoFile.FileExists(reqState.options.FilePath))
                    {
                        var file = isoFile.CreateFile(reqState.options.FilePath);
                        file.Close();
                    }

                    using (FileStream fileStream = new IsolatedStorageFileStream(reqState.options.FilePath, FileMode.Open, FileAccess.Write, isoFile))
                    {
                        long totalBytes = response.ContentLength;
                        int bytesRead = 0;
                        using (BinaryReader reader = new BinaryReader(response.GetResponseStream()))
                        {
                            using (BinaryWriter writer = new BinaryWriter(fileStream))
                            {
                                int BUFFER_SIZE = 1024;
                                byte[] buffer;

                                while (true)
                                {
                                    buffer = reader.ReadBytes(BUFFER_SIZE);
                                    // fire a progress event ?
                                    bytesRead += buffer.Length;
                                    if (buffer.Length > 0 && !reqState.isCancelled)
                                    {
                                        writer.Write(buffer);
                                        DispatchSyncProgress(bytesRead, totalBytes, 1, callbackId);
                                    }
                                    else
                                    {
                                        writer.Close();
                                        reader.Close();
                                        fileStream.Close();
                                        break;
                                    }
                                    System.Threading.Thread.Sleep(1);
                                }
                            }
                        }
                    }
                    if (reqState.isCancelled)
                    {
                        isoFile.DeleteFile(reqState.options.FilePath);
                    }
                }

                if (reqState.isCancelled)
                {
                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new SyncError(AbortError)),
                  callbackId);
                }
                else
                {
                    UnZip unzipper = new UnZip();
                    string destFilePath = "www/" + reqState.options.FilePath;
                    // at this point, bytesLoaded = bytesTotal so we'll just put the as '1'
                    DispatchSyncProgress(1, 1, 2, callbackId);
                    unzipper.unzip(reqState.options.FilePath, destFilePath, reqState.options.Type);

                    if(reqState.options.CopyCordovaAssets)
                    {
                        copyCordovaAssets(destFilePath);
                    }

                    DispatchSyncProgress(1, 1, 3, callbackId);
                    string result = "{ \"localPath\": \"" + reqState.options.FilePath + "\" , \"Id\" : \"" + reqState.options.Id + "\"}";
                    DispatchCommandResult(new PluginResult(PluginResult.Status.OK, result), callbackId);
                }
            }
            catch (IsolatedStorageException)
            {
                // Trying to write the file somewhere within the IsoStorage.
                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new SyncError(UnzipError)),
                                      callbackId);
            }
            catch (SecurityException)
            {
                // Trying to write the file somewhere not allowed.
                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new SyncError(UnzipError)),
                                      callbackId);
            }
            catch (WebException webex)
            {
                // TODO: probably need better work here to properly respond with all http status codes back to JS
                // Right now am jumping through hoops just to detect 404.
                HttpWebResponse response = (HttpWebResponse)webex.Response;
                if ((webex.Status == WebExceptionStatus.ProtocolError && response.StatusCode == HttpStatusCode.NotFound)
                    || webex.Status == WebExceptionStatus.UnknownError)
                {
                    // Weird MSFT detection of 404... seriously... just give us the f(*&#$@ status code as a number ffs!!!
                    // "Numbers for HTTP status codes? Nah.... let's create our own set of enums/structs to abstract that stuff away."
                    // FACEPALM
                    // Or just cast it to an int, whiner ... -jm
                    int statusCode = (int)response.StatusCode;
                    string body = "";

                    using (Stream streamResponse = response.GetResponseStream())
                    {
                        using (StreamReader streamReader = new StreamReader(streamResponse))
                        {
                            body = streamReader.ReadToEnd();
                        }
                    }
                    SyncError ftError = new SyncError(ConnectionError, null, null, statusCode, body);
                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ftError),
                                          callbackId);
                }
                else
                {
                    lock (reqState)
                    {
                        if (!reqState.isCancelled)
                        {
                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
                                                                   new SyncError(ConnectionError)),
                                                  callbackId);
                        }
                        else
                        {
                            Debug.WriteLine("It happened");
                        }
                    }
                }
            }
            catch (Exception)
            {
                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
                                                        new SyncError(UnzipError)),
                                      callbackId);
            }

            //System.Threading.Thread.Sleep(1000);
            if (InProcDownloads.ContainsKey(reqState.options.Id))
            {
                InProcDownloads.Remove(reqState.options.Id);
            }
        }
示例#41
0
 public abstract SyncError MapSyncError(OfflineEntity entity, SyncError error,
                                        WinEightContext context);
示例#42
0
        /// <summary>
        /// Adds a error to the list of in-memory
        /// </summary>
        /// <param name="error"></param>
        /// <param name="context">Context for the conflict is being added</param>
        public void AddSyncError(SyncError error, WinEightContext context)
        {
            OfflineEntity entity = Collections[error.LiveEntity.GetType()].AddOrUpdateSyncEntity((OfflineEntity)error.LiveEntity);
            SyncError oldError = Collections[error.LiveEntity.GetType()].MapSyncError(entity, error, context);

            SyncErrors.Add(error);

            if (oldError != null)
            {
                ClearSyncError(oldError, context);                
            }
        }
        /// <summary>
        /// Sets the sync error, providing the cache data so that the error can be removed if ClearSyncerror
        /// is called.
        /// </summary>
        ///<param name="context">IsolatedStorageOfflineContext</param>
        /// <param name="syncError">error to set.</param>
        internal void SetSyncError(IsolatedStorageOfflineContext context, SyncError syncError)
        {
            SyncError oldError = this._syncError;

            this._context = context;
            this._syncError = syncError;

            OnPropertyChanged("SyncError");

            if (oldError == null)
            {
                OnPropertyChanged("HasSyncError");
            }
        }
示例#44
0
        /// <summary>
        /// Runs the synchronization attempt.
        /// Does not raise exceptions.
        /// </summary>
        public async Task <SyncResult> Synchronize(CancellationToken token, SyncPolicy policy = SyncPolicy.Default)
        {
            if (DateTime.UtcNow < NextUploadOpportunity && policy == SyncPolicy.Default)
            {
                Log.Debug("Can't sync: sync attempt too early, next upload scheduled after {0}", NextUploadOpportunity);

                return(new SyncResult(new InvalidOperationException("Sync attempt too early")));
            }

            Settings.LastUploadAttempt = DateTime.UtcNow;

            if (!CheckSyncConditions(policy))
            {
                return(new SyncResult(error: new InvalidOperationException("Sync conditions not met")));
            }

            Log.Debug("Sync attempt started (policy {0})", policy);

            IsSyncing = true;
            StatusChanged.Raise(this);

            try {
                var ret = await SynchronizeInner(token, policy);

                Log.Debug("Sync process terminated normally");
                Log.Event("Sync.terminate", new Dictionary <string, string>()
                {
                    { "policy", policy.ToString() }
                });

                if (ret.HasFailed)
                {
                    UserLog.Add(UserLog.Icon.Error, LogStrings.FileUploadFailure, ret.Error.Message);

                    SyncError.Raise(this, new SyncErrorEventArgs(ret.Error));
                }
                else
                {
                    if (ret.ChunksUploaded == 1)
                    {
                        UserLog.Add(LogStrings.FileUploadSummarySingular);
                    }
                    else
                    {
                        UserLog.Add(LogStrings.FileUploadSummaryPlural, ret.ChunksUploaded);
                    }
                }

                return(ret);
            }
            catch (TaskCanceledException) {
                Log.Debug("Sync process was canceled");
                return(new SyncResult(0, 0));
            }
            catch (Exception ex) {
                Log.Error(ex, "Sync process failed with unforeseen error");

                UserLog.Add(UserLog.Icon.Error, LogStrings.FileUploadFailure, ex.Message);

                return(new SyncResult(error: ex));
            }
            finally {
                IsSyncing = false;
                StatusChanged.Raise(this);
            }
        }
示例#45
0
 public SyncException(SyncError error, Exception cause)
     : base(error.getMessage(), cause)
 {
     mError = error;
 }
示例#46
0
 public IsolatedStorageSyncError(SyncError error)
 {
     this.LiveEntity  = error.LiveEntity;
     this.ErrorEntity = error.ErrorEntity;
     this.Description = error.Description;
 }
示例#47
0
 public abstract SyncError MapSyncError(OfflineEntity entity, SyncError error,
                                        WinEightContext context);
        /// <summary>
        /// Handler for the ApplyChangedFailed event of the SqlSyncProvider class. This is used to record
        /// conflict information and apply the service conflict resolution policy.
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Event args</param>
        private void SqlSyncProviderApplyChangeFailed(object sender, DbApplyChangeFailedEventArgs e)
        {
            ApplyAction applyAction = ApplyAction.Continue;

            // Note: LocalChange table name may be null if the record does not exist on the server. So use the remote table name.
            string tableName = e.Conflict.RemoteChange.TableName;

            Type entityType = _configuration.TableGlobalNameToTypeMapping[tableName];

            ConstructorInfo constructorInfo = entityType.GetConstructor(Type.EmptyTypes);
            
            // Handle Errors first
            if (null != e.Error)
            {
                var syncError = new SyncError
                                    {
                                        LiveEntity = (IOfflineEntity)constructorInfo.Invoke(null),
                                        ErrorEntity = (IOfflineEntity)constructorInfo.Invoke(null)
                                    };

                //Note: When Error is not null, the conflict type should be ErrorsOccurred. Assert, just to make sure this is always correct.
                Debug.Assert(e.Conflict.Type == DbConflictType.ErrorsOccurred, "Conflict.Type is not ErrorsOccurred.");

                syncError.Description = e.Error.Message;

                // Fill in the error entity. This is the value of the client entity.
                _converter.GetEntityFromDataRow(e.Conflict.RemoteChange.Columns, e.Conflict.RemoteChange.Rows[0], syncError.ErrorEntity);

                // Mark the error entity as a tombstone, if the client sent a delete.
                // Note: The DataRow.RowState property is not marked as deleted, so we cannot use that
                // to determine if the client change was a delete.
                if (e.Conflict.Stage == DbSyncStage.ApplyingDeletes)
                {
                    syncError.ErrorEntity.ServiceMetadata.IsTombstone = true;
                }

                // Get the current version from the server.
                IOfflineEntity serverVersion = GetCurrentServerVersionForEntities(
                                                                new List<IOfflineEntity> { syncError.ErrorEntity },
                                                                (SqlConnection)e.Connection,
                                                                (SqlTransaction)e.Transaction)
                                                                .FirstOrDefault();

                // There is no item corresponding to the item sent from the client.
                // Example is an INSERT which caused an RI error and server does not have the record.
                if (null == serverVersion)
                {
                    // If there is no server record and the client changes is not a tombstone, then 
                    // set the LiveEntity as a compensating action which is a tombstone.
                    // This means that the client has to apply the delete locally
                    // for data convergence.

                    // If there is no server record and the client is a tombstone, then we ideally should
                    // just ackowledge the action and don't send any response but
                    // for now we will keep the sync error as is. 

                    _converter.GetEntityFromDataRow(e.Conflict.RemoteChange.Columns, e.Conflict.RemoteChange.Rows[0], syncError.LiveEntity);
                    syncError.LiveEntity.ServiceMetadata.IsTombstone = true;
                }
                else
                {
                    syncError.LiveEntity = serverVersion;
                }

                if (this.ApplyClientChangeFailed != null)
                {
                    this.ApplyClientChangeFailed(syncError.ErrorEntity);
                }

                // This will add the item as an exception to the server knowledge and will also send the exception to the client.
                // However the exception will be cleared the next time the client uploads changes, since we increment tickcounts always.

                applyAction = ApplyAction.Continue;

                // The ApplyChangesFailed event is fired when a conflict is detected. During resolution,
                // if change application fails due to some errors (such as RI, connectivity issues etc), 
                // the provider fires the ApplyChangesFailed event again 
                // to report an error. If we save the error entity as is, then both the original conflict and this new error
                // will be sent back to the client in the response. Since this is not desirable, we first need to remove the
                // corresponding conflict entity from the _conflicts collection before recording the error.

                // Note: item versions are not bumped since the conflict has not yet been resolved.

                RemoveEntityFromConflictCollection(tableName, syncError.LiveEntity);

                _syncErrors.Add(syncError);

                e.Action = applyAction;

                return;
            }

            // Create instances of OfflineCapableEntities and initialize the WinningChange and LosingChange properties.
            var c = new SyncConflict
                        {
                            LiveEntity = (IOfflineEntity)constructorInfo.Invoke(null),
                            LosingEntity = (IOfflineEntity)constructorInfo.Invoke(null)
                        };

            ConflictResolutionPolicy policyToUse = _conflictResolutionPolicy;

            SyncConflictResolution? userResolution = null;
            // Check and fire any Conflict interceptors            
            if (_configuration.HasConflictInterceptors(this._scopeName) ||
                _configuration.HasTypedConflictInterceptor(this._scopeName, entityType))
            {
                userResolution = GetUserConflictResolution(e, constructorInfo, entityType);

                if (userResolution != null && userResolution == SyncConflictResolution.ServerWins)
                {
                    policyToUse = ConflictResolutionPolicy.ServerWins;
                }
                else if (userResolution != null &&
                    (userResolution == SyncConflictResolution.ClientWins || userResolution == SyncConflictResolution.Merge))
                {
                    // If resolution is Merge or ClientWins, set the resolution to ClientWins so the runtime will 
                    // retry with force write and save the merged values back
                    policyToUse = ConflictResolutionPolicy.ClientWins;
                }
            }

            // If there were no Errors, then act based on the service conflict resolution policy.
            switch (policyToUse)
            {
                // ServerWins policy...
                case ConflictResolutionPolicy.ServerWins:

                    // For OCS, ApplyAction.Continue means ServerWins (local change will be maintained).
                    applyAction = ApplyAction.Continue;

                    // If the local change exists, then save it in the WinningChange property
                    if (null != e.Conflict.LocalChange && 1 == e.Conflict.LocalChange.Rows.Count)
                    {
                        _converter.GetEntityFromDataRow(e.Conflict.LocalChange.Columns, e.Conflict.LocalChange.Rows[0], c.LiveEntity);
                    }
                    // If local change does not exist
                    else
                    {
                        _converter.GetEntityFromDataRow(e.Conflict.RemoteChange.Columns, e.Conflict.RemoteChange.Rows[0], c.LiveEntity);
                        c.LiveEntity.ServiceMetadata.IsTombstone = true;
                    }

                    // Save the remote change in the LosingChange property.
                    if (1 == e.Conflict.RemoteChange.Rows.Count)
                    {
                        _converter.GetEntityFromDataRow(e.Conflict.RemoteChange.Columns, e.Conflict.RemoteChange.Rows[0], c.LosingEntity);
                    }

                    // Save the conflict resolution policy. 
                    c.Resolution = WebUtil.GetSyncConflictResolution(ConflictResolutionPolicy.ServerWins);

                    // Set the tombstone flag based on the type of the conflict.
                    switch (e.Conflict.Type)
                    {
                        case DbConflictType.LocalDeleteRemoteDelete:
                            c.LosingEntity.ServiceMetadata.IsTombstone = true;
                            c.LiveEntity.ServiceMetadata.IsTombstone = true;
                            break;
                        case DbConflictType.LocalDeleteRemoteUpdate:
                            c.LiveEntity.ServiceMetadata.IsTombstone = true;
                            break;
                        case DbConflictType.LocalUpdateRemoteDelete:
                            c.LosingEntity.ServiceMetadata.IsTombstone = true;
                            break;
                        // No changes to the tombstone flag for other cases.
                        default:
                            break;
                    }

                    if (this.ApplyClientChangeFailed != null)
                    {
                        this.ApplyClientChangeFailed(c.LosingEntity);
                    }

                    break;

                // ClientWins policy...
                case ConflictResolutionPolicy.ClientWins:

                    // For OCS, client change can be kept by using ApplyAction.RetryWithForceWrite.
                    applyAction = ApplyAction.RetryWithForceWrite;

                    if (1 == e.Conflict.RemoteChange.Rows.Count)
                    {
                        _converter.GetEntityFromDataRow(e.Conflict.RemoteChange.Columns, e.Conflict.RemoteChange.Rows[0], c.LiveEntity);
                    }

                    // If the local change exists, then save it in the WinningChange property
                    if (1 == e.Conflict.LocalChange.Rows.Count)
                    {
                        _converter.GetEntityFromDataRow(e.Conflict.RemoteChange.Columns, e.Conflict.LocalChange.Rows[0], c.LosingEntity);
                    }

                    // Save the conflict resolution policy. 
                    c.Resolution = userResolution ?? WebUtil.GetSyncConflictResolution(ConflictResolutionPolicy.ClientWins);

                    // Set the tombstone flag based on the type of the conflict.
                    switch (e.Conflict.Type)
                    {
                        case DbConflictType.LocalDeleteRemoteDelete:
                            c.LosingEntity.ServiceMetadata.IsTombstone = true;
                            c.LiveEntity.ServiceMetadata.IsTombstone = true;
                            break;
                        case DbConflictType.LocalDeleteRemoteUpdate:
                            c.LosingEntity.ServiceMetadata.IsTombstone = true;
                            break;
                        case DbConflictType.LocalUpdateRemoteDelete:
                            c.LiveEntity.ServiceMetadata.IsTombstone = true;
                            break;
                        // No changes to the tombstone flag for other cases.
                        default:
                            break;
                    }

                    if (this.ApplyClientChangeFailed != null)
                    {
                        this.ApplyClientChangeFailed(c.LiveEntity);
                    }

                    break;
            }

            // After deciding on the Live and the Losing entities for the conflict, we need to generate and save the SyncId 
            // of the LiveEntity. This value is used later after all changes are applied to project on the latest 
            // server knowledge and add positive exceptions to the updated client knowledge that is sent in the response.

            SyncId rowId = GenerateSyncIdForConflictingEntity(tableName, c.LiveEntity);

            if (!_conflictToSyncEntityIdMapping.ContainsKey(c))
            {
                _conflictToSyncEntityIdMapping.Add(c, rowId);

                // Note: SyncId's are unique for each entity.
                Debug.Assert(!_syncEntityIdToConflictMapping.ContainsKey(rowId), "!_syncEntityIdToConflictMapping.ContainsKey(rowId)");

                // Also fill the reverse mapping of syncId to the conflict entity.
                _syncEntityIdToConflictMapping.Add(rowId, c);
            }
            
            _conflicts.Add(c);

            e.Action = applyAction;
        }
示例#49
0
        public void AddSerializedError(SyncError error, IsolatedStorageOfflineContext context)
        {
            IsolatedStorageSyncError oldError = (IsolatedStorageSyncError)Collections[error.ErrorEntity.GetType()].MapSyncError((IsolatedStorageOfflineEntity)error.LiveEntity, error, context);

            SyncErrors.Add(error);

            if (oldError != null)
            {                
                ClearSyncError(oldError,context);
            }
        }