public static ExchangeData BiserDecode(byte[] enc = null, Biser.Decoder extDecoder = null) { Biser.Decoder decoder = null; if (extDecoder == null) { if (enc == null || enc.Length == 0) { return(null); } decoder = new Biser.Decoder(enc); } else { if (extDecoder.CheckNull()) { return(null); } else { decoder = extDecoder; } } ExchangeData m = new ExchangeData(); m.LastServerSyncTimeStamp = decoder.GetLong(); m.SyncOperations = decoder.CheckNull() ? null : new System.Collections.Generic.List <SyncOperation>(); if (m.SyncOperations != null) { decoder.GetCollection(() => { var pvar1 = SyncOperation.BiserDecode(null, decoder); return(pvar1); }, m.SyncOperations, true); } m.RepeatSynchro = decoder.GetBool(); m.NewServerSyncTimeStamp = decoder.GetLong(); return(m); }
/// <summary> /// /// </summary> /// <returns></returns> public async Task <ESyncResult> SyncEntity() { try { bool repeatSynchro; var toServer = new ExchangeData(); using (var tran = SyncEngine.DBEngine.GetTransaction()) { toServer.SyncOperations = this.GetSyncOperations(tran, out repeatSynchro); toServer.LastServerSyncTimeStamp = this.GetLastServerSyncTimeStamp(tran); } //Sending Entities to server //var httpCapsule = await _engine._serverSender("/modules.http.GM_PersonalDevice/IDT_Actions", var caps = new HttpCapsule { Action = "SYNC", EntityType = typeof(T).FullName, Body = toServer.BiserEncoder().Encode() }; var httpCapsuleBt = await SyncEngine._serverSender(_entitySync.urlSync, caps.BiserEncoder().Encode()); if (httpCapsuleBt == null) //Synchro with error { return(ESyncResult.ERROR); } var httpCapsule = HttpCapsule.BiserDecode(httpCapsuleBt); //if (httpCapsule == null) //Synchro with error // return ESyncResult.ERROR; //Dictionary<string, string> res = httpCapsule.Type.DeserializeJsonSimple(); if (httpCapsule.IsOk) { var exData = ExchangeData.BiserDecode(httpCapsule.Body); if (!repeatSynchro && exData.RepeatSynchro) { repeatSynchro = true; } if (SyncEngine.Verbose) { Console.WriteLine($"SyncEntity<{ typeof(T).Name }> ::: server returned {exData.SyncOperations?.Count} items."); } if (this.UpdateLocalDatabase(exData)) { return(await SyncEntity()); //this is a rare exeuting place, only in case if clientSideEntityID equals to existing serverSideEntityID, and even in this case it should be executed only once } } else if (!httpCapsule.IsOk && httpCapsule.Action == "AUTH FAILED") { if (SyncEngine._resetWebSession != null) { try { SyncEngine._resetWebSession?.Invoke(); } catch {} } return(ESyncResult.AUTH_FAIL); } //Repeat call of the procedure if (repeatSynchro) { return(ESyncResult.REPEAT); } } catch (Exception ex) { Logger.LogException("EntitySyncingClient.SyncStrategyV1", "SyncEntity", ex, $"type: {typeof(T).Name}"); return(ESyncResult.ERROR); } if (SyncEngine.Verbose) { Console.WriteLine($"SyncEntity<{ typeof(T).Name }> ::: finished"); } return(ESyncResult.OK); }
public abstract bool UpdateLocalDatabase(ExchangeData exData);
public override bool UpdateLocalDatabase(ExchangeData exData) //(List<SyncOperation> syncList, long newServerSyncTimeStamp) { var now = DateTime.UtcNow.Ticks; bool reRunSync = false; using (var tran = SyncEngine.DBEngine.GetTransaction()) { //Synchronization of all necessary tables must be in entitySync.Init _entitySync.tran = tran; _entitySync.Init(); tran.ValuesLazyLoadingIsOn = false; tran.Insert(_entitySync.entityTable, new byte[] { LocalSyncTS, 1 }, _newLocalSyncTimeStamp > exData.NewServerSyncTimeStamp ? _newLocalSyncTimeStamp : exData.NewServerSyncTimeStamp); tran.Insert(_entitySync.entityTable, new byte[] { ServerSyncTS, 2 }, exData.NewServerSyncTimeStamp); T entity; T localEntity; int processedBeforeRaise = 0; //Taking care changed IDs by server foreach (var opr in exData.SyncOperations.Where(r => r.Operation == SyncOperation.eOperation.EXCHANGE)) { if (opr.ExternalId > 0) { //opr.ExternalID will help to determine new ID var rowLocalEntity = tran.Select <byte[], byte[]>(_entitySync.entityTable, new byte[] { Entity }.Concat(opr.InternalId.To_8_bytes_array_BigEndian())); if (rowLocalEntity.Exists) { var oldEntity = rowLocalEntity.GetDataBlockWithFixedAddress <T>(); _entitySync.ptrContent = null; //New GeneratedID must be stored for the new sync ((ISyncEntity)oldEntity).Id = opr.ExternalId; //Theoretically on this place can be called a user-function to get another ID type ((ISyncEntity)oldEntity).SyncTimestamp = ++now; //must be returned back, overriding SyncTimeStamp _entitySync.OnInsertEntity(oldEntity, default(T), SyncEngine.Serialize(oldEntity), opr.InternalId); InsertIndex4Sync(tran, _entitySync.entityTable, oldEntity, _entitySync.ptrContent, default(T)); //Setting value from the server for the existing ID (real entity that must belong to that id) _entitySync.ptrContent = rowLocalEntity.Value; _entitySync.OnInsertEntity((T)SyncEngine.Deserialize(opr.SerializedObject, typeof(T)), default(T), opr.SerializedObject, 0); reRunSync = true; } } } //standard entites foreach (var opr in exData.SyncOperations.Where(r => r.Operation != SyncOperation.eOperation.EXCHANGE)) { switch (opr.Operation) { case SyncOperation.eOperation.INSERT: var rowLocalEntity = tran.Select <byte[], byte[]>(_entitySync.entityTable, new byte[] { Entity }.Concat(opr.InternalId.To_8_bytes_array_BigEndian())); if (rowLocalEntity.Exists) { //Possible update _entitySync.ptrContent = rowLocalEntity.Value; localEntity = rowLocalEntity.GetDataBlockWithFixedAddress <T>(); entity = (T)SyncEngine.Deserialize(opr.SerializedObject, typeof(T)); if (((ISyncEntity)localEntity).SyncTimestamp < opr.SyncTimestamp) { //Local version is weaker then server version _entitySync.OnInsertEntity(entity, localEntity, opr.SerializedObject, 0); InsertIndex4Sync(tran, _entitySync.entityTable, entity, _entitySync.ptrContent, localEntity); } else { ////------------Nothing } } else { //Inserting new entity from server _entitySync.ptrContent = null; // entity = opr.SerializedObject.DeserializeProtobuf<T>(); entity = (T)SyncEngine.Deserialize(opr.SerializedObject, typeof(T)); _entitySync.OnInsertEntity(entity, default(T), opr.SerializedObject, 0); InsertIndex4Sync(tran, _entitySync.entityTable, entity, _entitySync.ptrContent, default(T)); } break; case SyncOperation.eOperation.REMOVE: //------------DOING NOTHING, WE DONT DELETE ENTITIES break; } //Computing processed elements and raises event once per SyncEntitiesMgr.RaiseSyncProcessEach System.Threading.Interlocked.Increment(ref Engine.SyncOperationsCount); processedBeforeRaise++; if (processedBeforeRaise >= Engine.RaiseSyncProcessEach) { processedBeforeRaise = 0; Engine.OnSyncProcess(); } } _entitySync.BeforeCommit(); tran.Commit(); } _entitySync.OnEntitySyncIsFinished(); return(reRunSync); }