Esempio n. 1
0
        /// <summary>
        /// Requests remote invocation for a <see cref="ScheduledCallback"/>, to be delivered in parallel with the
        /// local invocation loop on iOS. Only one of these (the remote or local) will ultimately be allowed to
        /// run -- whichever arrives first.
        /// </summary>
        /// <returns>Task.</returns>
        /// <param name="callback">Callback.</param>
        private async Task RequestRemoteInvocationAsync(ScheduledCallback callback)
        {
            // not all callbacks are associated with a protocol (e.g., the app-level health test). because push notifications are
            // currently tied to the remote data store of the protocol, we don't currently provide PNR support for such callbacks.
            // on race conditions, it might be the case that the system attempts to schedule a duplicate callback. if this happens
            // the duplicate will not be assigned a next execution, and the system will try to unschedule/delete it. skip such
            // callbacks below.
            if (callback.Protocol != null && callback.NextExecution.HasValue)
            {
                try
                {
                    // the request id must differentiate the current device. furthermore, it needs to identify the
                    // request as one for a callback. lastly, it needs to identify the particular callback that it
                    // targets. the id does not include the callback invocation, as any newer requests for the
                    // callback should obsolete older requests.
                    string id = SensusServiceHelper.Get().DeviceId + "." + SENSUS_CALLBACK_KEY + "." + callback.Id;

                    PushNotificationUpdate update = new PushNotificationUpdate
                    {
                        Type    = PushNotificationUpdateType.Callback,
                        Content = JObject.Parse("{" +
                                                "\"callback-id\":" + JsonConvert.ToString(callback.Id) + "," +
                                                "\"invocation-id\":" + JsonConvert.ToString(callback.InvocationId) +
                                                "}")
                    };

                    PushNotificationRequest request = new PushNotificationRequest(id, SensusServiceHelper.Get().DeviceId, callback.Protocol, update, PushNotificationRequest.LocalFormat, callback.NextExecution.Value, callback.PushNotificationBackendKey);

                    await SensusContext.Current.Notifier.SendPushNotificationRequestAsync(request, CancellationToken.None);
                }
                catch (Exception ex)
                {
                    SensusException.Report("Exception while sending push notification request for scheduled callback:  " + ex.Message, ex);
                }
            }
        }
Esempio n. 2
0
        public override async Task<List<PushNotificationUpdate>> GetPushNotificationUpdatesAsync(CancellationToken cancellationToken)
        {
            Dictionary<string, PushNotificationUpdate> idUpdate = new Dictionary<string, PushNotificationUpdate>();

            // only let one caller at a time download the updates
            lock (_downloadingUpdatesLocker)
            {
                if (_downloadingUpdates)
                {
                    throw new Exception("Push notification updates are being downloaded on another thread.");
                }
                else
                {
                    _downloadingUpdates = true;
                }
            }

            AmazonS3Client s3 = null;

            try
            {
                s3 = await CreateS3ClientAsync();

                // retrieve updates sorted with most recently modified first. this will let us keep only the most recent version
                // of each update with the same id (note use of TryAdd below, which will only retain the first update per id).
                foreach (string updateKey in await ListKeysAsync(s3, PUSH_NOTIFICATIONS_UPDATES_DIRECTORY + "/" + SensusServiceHelper.Get().DeviceId, true, cancellationToken))
                {
                    try
                    {
                        GetObjectResponse getResponse = await s3.GetObjectAsync(_bucket, updateKey, cancellationToken);

                        if (getResponse.HttpStatusCode == HttpStatusCode.OK)
                        {
                            // catch any exceptions when trying to delete the update. we already retrieved it, and 
                            // we might just be lacking connectivity or might have been cancelled. the update will
                            // be pushed again in the future and we'll try deleting it again then.
                            try
                            {
                                await DeleteAsync(s3, updateKey, cancellationToken);
                            }
                            catch (Exception)
                            { }

                            string updatesJSON;
                            using (StreamReader reader = new StreamReader(getResponse.ResponseStream))
                            {
                                updatesJSON = reader.ReadToEnd().Trim();
                            }

                            foreach (JObject updateObject in JArray.Parse(updatesJSON))
                            {
                                PushNotificationUpdate update = updateObject.ToObject<PushNotificationUpdate>();
                                idUpdate.TryAdd(update.Id, update);
                            }
                        }
                        else
                        {
                            throw new Exception(getResponse.HttpStatusCode.ToString());
                        }
                    }
                    catch (Exception ex)
                    {
                        SensusServiceHelper.Get().Logger.Log("Exception while getting update object:  " + ex.Message, LoggingLevel.Normal, GetType());
                    }
                }

                SensusServiceHelper.Get().Logger.Log("Retrieved " + idUpdate.Count + " update(s).", LoggingLevel.Normal, GetType());

                return idUpdate.Values.ToList();
            }
            finally
            {
                lock (_downloadingUpdatesLocker)
                {
                    _downloadingUpdates = false;
                }

                DisposeS3(s3);
            }
        }