Exemple #1
0
        /// <summary>
        /// Thread that is waiting for signals to perform checks.
        /// </summary>
        private void ExecutiveThread()
        {
            log.Info("()");

            executiveThreadFinished.Reset();

            List <WaitHandle> handleList = new List <WaitHandle>();

            handleList.Add(ShutdownSignaling.ShutdownEvent);
            foreach (CronJob job in jobs.Values)
            {
                handleList.Add(job.Event);
            }

            WaitHandle[] handles = handleList.ToArray();

            Data.Database database = (Data.Database)Base.ComponentDictionary["Data.Database"];
            Network.LocationBasedNetwork locationBasedNetwork = (Network.LocationBasedNetwork)Base.ComponentDictionary["Network.LocationBasedNetwork"];
            ImageManager imageManager = (ImageManager)Base.ComponentDictionary["Data.ImageManager"];

            Network.Server server = (Network.Server)Base.ComponentDictionary["Network.Server"];
            Network.NeighborhoodActionProcessor neighborhoodActionProcessor = (Network.NeighborhoodActionProcessor)Base.ComponentDictionary["Network.NeighborhoodActionProcessor"];
            Network.CAN.ContentAddressNetwork   contentAddressNetwork       = (Network.CAN.ContentAddressNetwork)Base.ComponentDictionary["Network.ContentAddressNetwork"];

            while (!ShutdownSignaling.IsShutdown)
            {
                log.Info("Waiting for event.");

                int index = WaitHandle.WaitAny(handles);
                if (handles[index] == ShutdownSignaling.ShutdownEvent)
                {
                    log.Info("Shutdown detected.");
                    break;
                }

                CronJob job = null;
                foreach (CronJob cronJob in jobs.Values)
                {
                    if (handles[index] == cronJob.Event)
                    {
                        job = cronJob;
                        break;
                    }
                }

                log.Trace("Job '{0}' activated.", job.Name);
                switch (job.Name)
                {
                case "checkFollowersRefresh":
                    database.CheckFollowersRefresh();
                    break;

                case "checkExpiredHostedIdentities":
                    database.CheckExpiredHostedIdentities();
                    break;

                case "checkExpiredNeighbors":
                    if (locationBasedNetwork.LocServerInitialized)
                    {
                        database.CheckExpiredNeighbors();
                    }
                    else
                    {
                        log.Debug("LOC component is not in sync with the LOC server yet, checking expired neighbors will not be executed now.");
                    }
                    break;

                case "deleteUnusedImages":
                    imageManager.ProcessImageDeleteList();
                    break;

                case "refreshLocData":
                    locationBasedNetwork.RefreshLoc();
                    break;

                case "checkInactiveClientConnections":
                    server.CheckInactiveClientConnections();
                    break;

                case "checkNeighborhoodActionList":
                    neighborhoodActionProcessor.CheckActionList();
                    break;

                case "ipnsRecordRefresh":
                    contentAddressNetwork.IpnsRecordRefresh().Wait();
                    break;
                }
            }

            executiveThreadFinished.Set();

            log.Info("(-)");
        }
Exemple #2
0
        /// <summary>
        /// Updates identity profile and creates neighborhood action to propagate the change unless the client did not want the propagation.
        /// </summary>
        /// <param name="IdentityId">Network identifier of the identity to update.</param>
        /// <param name="SignedProfile">Signed profile information with updated values.</param>
        /// <param name="ProfileImageChanged">True if profile image is about to change.</param>
        /// <param name="ThumbnailImageChanged">True if thumbnail image is about to change.</param>
        /// <param name="NoPropagation">True if the client does not want this change of profile to be propagated to the neighborhood.</param>
        /// <param name="IdentityNotFound">If the function fails because the identity is not found, this referenced value is set to true.</param>
        /// <param name="ImagesToDelete">If the function succeeds and the profile images are altered, old image files has to be deleted, in which case their hashes
        /// are returned in this list, which has to be initialized by the caller.</param>
        /// <returns>true if the function succeeds, false otherwise.</returns>
        public async Task <bool> UpdateProfileAndPropagateAsync(byte[] IdentityId, SignedProfileInformation SignedProfile, bool ProfileImageChanged, bool ThumbnailImageChanged, bool NoPropagation, StrongBox <bool> IdentityNotFound, List <byte[]> ImagesToDelete)
        {
            log.Trace("()");
            bool res = false;

            bool signalNeighborhoodAction = false;
            bool success = false;

            List <byte[]> imagesToDelete = new List <byte[]>();

            ProfileInformation profile = SignedProfile.Profile;

            DatabaseLock[] lockObjects = new DatabaseLock[] { UnitOfWork.HostedIdentityLock, UnitOfWork.FollowerLock, UnitOfWork.NeighborhoodActionLock };
            using (IDbContextTransaction transaction = await unitOfWork.BeginTransactionWithLockAsync(lockObjects))
            {
                try
                {
                    HostedIdentity identity = (await GetAsync(i => (i.IdentityId == IdentityId) && (i.Cancelled == false))).FirstOrDefault();
                    if (identity != null)
                    {
                        bool isProfileInitialization = !identity.Initialized;

                        identity.Initialized = true;
                        identity.Version     = profile.Version.ToByteArray();
                        identity.Name        = profile.Name;

                        GpsLocation location = new GpsLocation(profile.Latitude, profile.Longitude);
                        identity.SetInitialLocation(location);
                        identity.ExtraData = profile.ExtraData;
                        identity.Signature = SignedProfile.Signature.ToByteArray();

                        if (ProfileImageChanged)
                        {
                            if (identity.ProfileImage != null)
                            {
                                imagesToDelete.Add(identity.ProfileImage);
                            }
                            identity.ProfileImage = profile.ProfileImageHash.Length != 0 ? profile.ProfileImageHash.ToByteArray() : null;
                        }

                        if (ThumbnailImageChanged)
                        {
                            if (identity.ThumbnailImage != null)
                            {
                                imagesToDelete.Add(identity.ThumbnailImage);
                            }
                            identity.ThumbnailImage = profile.ThumbnailImageHash.Length != 0 ? profile.ThumbnailImageHash.ToByteArray() : null;
                        }


                        Update(identity);


                        if (!NoPropagation)
                        {
                            // The profile change has to be propagated to all our followers
                            // we create database actions that will be processed by dedicated thread.
                            NeighborhoodActionType actionType = isProfileInitialization ? NeighborhoodActionType.AddProfile : NeighborhoodActionType.ChangeProfile;
                            string extraInfo = identity.PublicKey.ToHex();
                            signalNeighborhoodAction = await unitOfWork.NeighborhoodActionRepository.AddIdentityProfileFollowerActionsAsync(actionType, identity.IdentityId, extraInfo);
                        }

                        await unitOfWork.SaveThrowAsync();

                        transaction.Commit();
                        success = true;
                    }
                    else
                    {
                        IdentityNotFound.Value = true;
                    }
                }
                catch (Exception e)
                {
                    log.Error("Exception occurred: {0}", e.ToString());
                }

                if (!success)
                {
                    log.Warn("Rolling back transaction.");
                    unitOfWork.SafeTransactionRollback(transaction);
                }

                unitOfWork.ReleaseLock(lockObjects);
            }

            if (success)
            {
                // Only when the function succeeds the old images can be deleted.
                ImagesToDelete.AddRange(imagesToDelete);

                // Send signal to neighborhood action processor to process the new series of actions.
                if (signalNeighborhoodAction)
                {
                    Network.NeighborhoodActionProcessor neighborhoodActionProcessor = (Network.NeighborhoodActionProcessor)Base.ComponentDictionary[Network.NeighborhoodActionProcessor.ComponentName];
                    neighborhoodActionProcessor.Signal();
                }

                res = true;
            }


            log.Trace("(-):{0}", res);
            return(res);
        }
Exemple #3
0
        /// <summary>
        /// Deletes an existing activity from the database. Then a new neighborhood action is created to propagate the change to the neighborhood.
        /// </summary>
        /// <param name="ActivityId">Identifier of the activity to delete.</param>
        /// <param name="OwnerIdentityId">Network ID of the client who owns the activity.</param>
        /// <param name="NotFound">If the function fails, this is set to true if the reason of the failure is that the activity was not found.</param>
        /// <returns>true if the function succeeds, false otherwise.</returns>
        public async Task <bool> DeleteAndPropagateAsync(uint ActivityId, byte[] OwnerIdentityId, StrongBox <bool> NotFound)
        {
            log.Trace("(ActivityId:{0},OwnerIdentityId:'{1}')", ActivityId, OwnerIdentityId.ToHex());

            bool res = false;

            bool success = false;
            bool signalNeighborhoodAction = false;

            DatabaseLock[] lockObjects = new DatabaseLock[] { UnitOfWork.PrimaryActivityLock, UnitOfWork.FollowerLock, UnitOfWork.NeighborhoodActionLock };
            using (IDbContextTransaction transaction = await unitOfWork.BeginTransactionWithLockAsync(lockObjects))
            {
                try
                {
                    PrimaryActivity existingActivity = (await GetAsync(a => (a.ActivityId == ActivityId) && (a.OwnerIdentityId == OwnerIdentityId))).FirstOrDefault();
                    if (existingActivity != null)
                    {
                        Delete(existingActivity);

                        // The activity has to be propagated to all our followers we create database actions that will be processed by dedicated thread.
                        signalNeighborhoodAction = await unitOfWork.NeighborhoodActionRepository.AddActivityFollowerActionsAsync(NeighborhoodActionType.RemoveActivity, existingActivity.ActivityId, existingActivity.OwnerIdentityId);

                        await unitOfWork.SaveThrowAsync();

                        transaction.Commit();
                        success = true;
                    }
                    else
                    {
                        log.Debug("Activity ID {0}, owner identity ID '{1}' does not exist.", ActivityId, OwnerIdentityId.ToHex());
                        NotFound.Value = true;
                    }
                }
                catch (Exception e)
                {
                    log.Error("Exception occurred: {0}", e.ToString());
                }

                if (!success)
                {
                    log.Warn("Rolling back transaction.");
                    unitOfWork.SafeTransactionRollback(transaction);
                }

                unitOfWork.ReleaseLock(lockObjects);
            }

            if (success)
            {
                // Send signal to neighborhood action processor to process the new series of actions.
                if (signalNeighborhoodAction)
                {
                    Network.NeighborhoodActionProcessor neighborhoodActionProcessor = (Network.NeighborhoodActionProcessor)Base.ComponentDictionary[Network.NeighborhoodActionProcessor.ComponentName];
                    neighborhoodActionProcessor.Signal();
                }

                res = true;
            }


            log.Trace("(-):{0}", res);
            return(res);
        }
Exemple #4
0
        /// <summary>
        /// Inserts a new activity to the database provided that it does not exists yet. Then a new neighborhood action is created to propagate the new activity to the neighborhood.
        /// </summary>
        /// <param name="Activity">New activity to insert to database.</param>
        /// <returns>Status.Ok if the function succeeds,
        /// Status.ErrorAlreadyExists if activity with the same owner and ID already exists,
        /// Status.ErrorQuotaExceeded if the server is not willing to create any more activities because it has reached its limit already,
        /// Status.ErrorInternal if the function fails for other reason.</returns>
        public async Task <Status> CreateAndPropagateAsync(PrimaryActivity Activity)
        {
            log.Trace("()");

            Status res = Status.ErrorInternal;

            bool success = false;
            bool signalNeighborhoodAction = false;

            DatabaseLock[] lockObjects = new DatabaseLock[] { UnitOfWork.PrimaryActivityLock, UnitOfWork.FollowerLock, UnitOfWork.NeighborhoodActionLock };
            using (IDbContextTransaction transaction = await unitOfWork.BeginTransactionWithLockAsync(lockObjects))
            {
                try
                {
                    int hostedActivities = await CountAsync(null);

                    log.Trace("Currently hosting {0} activities.", hostedActivities);
                    if (hostedActivities < Config.Configuration.MaxActivities)
                    {
                        PrimaryActivity existingActivity = (await GetAsync(a => (a.ActivityId == Activity.ActivityId) && (a.OwnerIdentityId == Activity.OwnerIdentityId))).FirstOrDefault();
                        if (existingActivity == null)
                        {
                            await InsertAsync(Activity);

                            // The activity has to be propagated to all our followers we create database actions that will be processed by dedicated thread.
                            signalNeighborhoodAction = await unitOfWork.NeighborhoodActionRepository.AddActivityFollowerActionsAsync(NeighborhoodActionType.AddActivity, Activity.ActivityId, Activity.OwnerIdentityId, Activity.OwnerPublicKey.ToHex());

                            await unitOfWork.SaveThrowAsync();

                            transaction.Commit();
                            success = true;
                        }
                        else
                        {
                            log.Debug("Activity with the activity ID {0} and owner identity ID '{1}' already exists with database ID {2}.", Activity.ActivityId, Activity.OwnerIdentityId.ToHex(), existingActivity.DbId);
                            res = Status.ErrorAlreadyExists;
                        }
                    }
                    else
                    {
                        log.Debug("MaxActivities {0} has been reached.", Config.Configuration.MaxActivities);
                        res = Status.ErrorQuotaExceeded;
                    }
                }
                catch (Exception e)
                {
                    log.Error("Exception occurred: {0}", e.ToString());
                }

                if (!success)
                {
                    log.Warn("Rolling back transaction.");
                    unitOfWork.SafeTransactionRollback(transaction);
                }

                unitOfWork.ReleaseLock(lockObjects);
            }

            if (success)
            {
                // Send signal to neighborhood action processor to process the new series of actions.
                if (signalNeighborhoodAction)
                {
                    Network.NeighborhoodActionProcessor neighborhoodActionProcessor = (Network.NeighborhoodActionProcessor)Base.ComponentDictionary[Network.NeighborhoodActionProcessor.ComponentName];
                    neighborhoodActionProcessor.Signal();
                }

                res = Status.Ok;
            }


            log.Trace("(-):{0}", res);
            return(res);
        }
Exemple #5
0
        /// <summary>
        /// Updates an existing activity in the database. Then a new neighborhood action is created to propagate the changes to the neighborhood
        /// if this is required. If the update is rejected, the action is deleted from the database and this is propagated to the neighborhood.
        /// <para>Note that the change in activity is not propagated if the client sets no propagation flag in the request, or if only the activity
        /// expiration date or its location is changed.</para>
        /// </summary>
        /// <param name="UpdateRequest">Update request received from the client.</param>
        /// <param name="Signature">Signature of the updated activity data from the client.</param>
        /// <param name="OwnerIdentityId">Network ID of the client who requested the update.</param>
        /// <param name="CloserServerId">If the result is Status.ErrorRejected, this is filled with network identifier of a neighbor server that is closer to the target location.</param>
        /// <returns>Status.Ok if the function succeeds,
        /// Status.ErrorNotFound if the activity to update does not exist,
        /// Status.ErrorRejected if the update was rejected and the client should migrate the activity to closest proximity server,
        /// Status.ErrorInvalidValue if the update attempted to change activity's type,
        /// Status.ErrorInternal otherwise.</returns>
        public async Task <Status> UpdateAndPropagateAsync(UpdateActivityRequest UpdateRequest, byte[] Signature, byte[] OwnerIdentityId, StrongBox <byte[]> CloserServerId)
        {
            log.Trace("(UpdateRequest.Activity.Id:{0},OwnerIdentityId:'{1}')", UpdateRequest.Activity.Id, OwnerIdentityId.ToHex());

            Status res = Status.ErrorInternal;

            bool success = false;
            bool signalNeighborhoodAction           = false;
            bool migrateActivity                    = false;
            ActivityInformation activityInformation = UpdateRequest.Activity;

            DatabaseLock[] lockObjects = new DatabaseLock[] { UnitOfWork.PrimaryActivityLock, UnitOfWork.FollowerLock, UnitOfWork.NeighborhoodActionLock };
            using (IDbContextTransaction transaction = await unitOfWork.BeginTransactionWithLockAsync(lockObjects))
            {
                try
                {
                    PrimaryActivity existingActivity = (await GetAsync(a => (a.ActivityId == activityInformation.Id) && (a.OwnerIdentityId == OwnerIdentityId))).FirstOrDefault();
                    if (existingActivity != null)
                    {
                        // First, we check whether the activity should be migrated to closer proximity server.
                        GpsLocation oldLocation     = existingActivity.GetLocation();
                        GpsLocation newLocation     = new GpsLocation(activityInformation.Latitude, activityInformation.Longitude);
                        bool        locationChanged = !oldLocation.Equals(newLocation);

                        bool error = false;
                        if (locationChanged)
                        {
                            List <byte[]> ignoreServerIds = new List <byte[]>(UpdateRequest.IgnoreServerIds.Select(i => i.ToByteArray()));
                            if (!await unitOfWork.NeighborRepository.IsServerNearestToLocationAsync(newLocation, ignoreServerIds, CloserServerId, ProxMessageBuilder.ActivityMigrationDistanceTolerance))
                            {
                                if (CloserServerId.Value != null)
                                {
                                    migrateActivity = true;
                                    log.Debug("Activity's new location is outside the reach of this proximity server, the activity will be deleted from the database.");
                                }
                                else
                                {
                                    error = true;
                                }
                            }
                            // else No migration needed
                        }

                        if (!error)
                        {
                            // If it should not be migrated, we update the activity in our database.
                            if (!migrateActivity)
                            {
                                SignedActivityInformation signedActivityInformation = new SignedActivityInformation()
                                {
                                    Activity  = activityInformation,
                                    Signature = ProtocolHelper.ByteArrayToByteString(Signature)
                                };

                                PrimaryActivity updatedActivity = ActivityBase.FromSignedActivityInformation <PrimaryActivity>(signedActivityInformation);
                                ActivityChange  changes         = existingActivity.CompareChangeTo(updatedActivity);

                                if ((changes & ActivityChange.Type) == 0)
                                {
                                    bool propagateChange = false;
                                    if (!UpdateRequest.NoPropagation)
                                    {
                                        // If only changes in the activity are related to location or expiration time, the activity update is not propagated to the neighborhood.
                                        propagateChange = (changes & ~(ActivityChange.LocationLatitude | ActivityChange.LocationLongitude | ActivityChange.PrecisionRadius | ActivityChange.ExpirationTime)) != 0;
                                    }

                                    existingActivity.CopyFromSignedActivityInformation(signedActivityInformation);

                                    Update(existingActivity);

                                    if (propagateChange)
                                    {
                                        // The activity has to be propagated to all our followers we create database actions that will be processed by dedicated thread.
                                        signalNeighborhoodAction = await unitOfWork.NeighborhoodActionRepository.AddActivityFollowerActionsAsync(NeighborhoodActionType.ChangeActivity, existingActivity.ActivityId, existingActivity.OwnerIdentityId);
                                    }
                                    else
                                    {
                                        log.Trace("Change of activity ID {0}, owner identity ID '{1}' won't be propagated to neighborhood.", existingActivity.ActivityId, existingActivity.OwnerIdentityId.ToHex());
                                    }

                                    await unitOfWork.SaveThrowAsync();

                                    transaction.Commit();
                                    success = true;
                                }
                                else
                                {
                                    log.Debug("Activity ID {0}, owner identity ID '{1}' attempt to change type.", activityInformation.Id, OwnerIdentityId.ToHex());
                                    res = Status.ErrorInvalidValue;
                                }
                            }
                            // else this is handled below separately, out of locked section
                        }
                        // else Internal error
                    }
                    else
                    {
                        log.Debug("Activity ID {0}, owner identity ID '{1}' does not exist.", activityInformation.Id, OwnerIdentityId.ToHex());
                        res = Status.ErrorNotFound;
                    }
                }
                catch (Exception e)
                {
                    log.Error("Exception occurred: {0}", e.ToString());
                }

                if (!success)
                {
                    log.Warn("Rolling back transaction.");
                    unitOfWork.SafeTransactionRollback(transaction);
                }

                unitOfWork.ReleaseLock(lockObjects);
            }


            if (migrateActivity)
            {
                // If activity should be migrated, we delete it from our database and inform our neighbors.
                StrongBox <bool> notFound = new StrongBox <bool>(false);
                if (await DeleteAndPropagateAsync(activityInformation.Id, OwnerIdentityId, notFound))
                {
                    if (!notFound.Value)
                    {
                        // The activity was deleted from the database and this change will be propagated to the neighborhood.
                        log.Debug("Update rejected, activity ID {0}, owner identity ID '{1}' deleted.", activityInformation.Id, OwnerIdentityId.ToHex());
                        res = Status.ErrorRejected;
                    }
                    else
                    {
                        // Activity of given ID not found among activities created by the client.
                        res = Status.ErrorNotFound;
                    }
                }
            }

            if (success)
            {
                // Send signal to neighborhood action processor to process the new series of actions.
                if (signalNeighborhoodAction)
                {
                    Network.NeighborhoodActionProcessor neighborhoodActionProcessor = (Network.NeighborhoodActionProcessor)Base.ComponentDictionary[Network.NeighborhoodActionProcessor.ComponentName];
                    neighborhoodActionProcessor.Signal();
                }

                res = Status.Ok;
            }


            log.Trace("(-):{0}", res);
            return(res);
        }