/// <summary> /// Creates pull subscriptions for all rooms and waits on timer delay to pull subscriptions /// </summary> /// <param name="mailboxOwner"></param> /// <returns></returns> private async System.Threading.Tasks.Task PullSubscriptionChangesAsync(string mailboxOwner) { _traceListener.Trace("SyncProgram", $"PullSubscriptionChangesAsync({mailboxOwner}) starting"); var service = new EWService(EwsToken); service.SetImpersonation(ConnectingIdType.SmtpAddress, mailboxOwner); if (_subscriptions == null) { _subscriptions = new List <SubscriptionCollection>(); } var EwsService = new EWService(EwsToken); EwsService.SetImpersonation(ConnectingIdType.SmtpAddress, mailboxOwner); // Retreive and Store PullSubscription Details using (var _context = new EWSDbContext(EWSConstants.Config.Database)) { foreach (var room in _context.RoomListRoomEntities.Where(w => !string.IsNullOrEmpty(w.Identity))) { EntitySubscription dbSubscription = null; string watermark = null; if (_context.SubscriptionEntities.Any(rs => rs.SmtpAddress == room.SmtpAddress)) { dbSubscription = _context.SubscriptionEntities.FirstOrDefault(rs => rs.SmtpAddress == room.SmtpAddress); watermark = dbSubscription.Watermark; } else { // newup a subscription to track the watermark dbSubscription = new EntitySubscription() { LastRunTime = DateTime.UtcNow, SmtpAddress = room.SmtpAddress }; _context.SubscriptionEntities.Add(dbSubscription); } try { var roomService = new EWService(EwsToken); var subscription = roomService.CreatePullSubscription(ConnectingIdType.SmtpAddress, room.SmtpAddress, pollingTimeout, watermark); // close out the old subscription dbSubscription.PreviousWatermark = (!string.IsNullOrEmpty(watermark)) ? watermark : null; dbSubscription.Watermark = subscription.Watermark; _traceListener.Trace("SyncProgram", $"ListenToRoomReservationChangesAsync.Subscribed to room {room.SmtpAddress}"); _subscriptions.Add(new SubscriptionCollection() { Pulling = subscription, SmtpAddress = room.SmtpAddress }); var rowChanged = _context.SaveChanges(); _traceListener.Trace("SyncProgram", $"Pull subscription persisted {rowChanged} rows"); } catch (Microsoft.Exchange.WebServices.Data.ServiceRequestException srex) { _traceListener.Trace("SyncProgram", $"Failed to provision subscription {srex.Message}"); throw new Exception($"Subscription could not be created for {room.SmtpAddress} with MSG:{srex.Message}"); } } } try { var waitTimer = new TimeSpan(0, 5, 0); while (!CancellationTokenSource.IsCancellationRequested) { var milliseconds = (int)waitTimer.TotalMilliseconds; using (var _context = new EWSDbContext(EWSConstants.Config.Database)) { foreach (var item in _subscriptions) { bool?ismore = default(bool); do { PullSubscription subscription = item.Pulling; var events = subscription.GetEvents(); var watermark = subscription.Watermark; ismore = subscription.MoreEventsAvailable; var email = item.SmtpAddress; var databaseItem = _context.SubscriptionEntities.FirstOrDefault(rs => rs.SmtpAddress == email); // pull last event from stack TODO: need heuristic for how meetings can be stored var filteredEvents = events.ItemEvents.OrderBy(x => x.TimeStamp); foreach (ItemEvent ev in filteredEvents) { var itemId = ev.ItemId; try { // Send an item event you can bind to await Messenger.SendQueueO365ChangesAsync(queueSubscription, email, ev); } catch (ServiceResponseException ex) { _traceListener.Trace("SyncProgram", $"ServiceException: {ex.Message}"); continue; } } databaseItem.Watermark = watermark; databaseItem.LastRunTime = DateTime.UtcNow; // Save Database changes await _context.SaveChangesAsync(); }while (ismore == true); } } _traceListener.Trace("SyncProgram", $"Sleeping at {DateTime.UtcNow} for {milliseconds} milliseconds..."); System.Threading.Thread.Sleep(milliseconds); } } catch (Exception ex) { Console.WriteLine(ex.Message); } _traceListener.Trace("SyncProgram", $"PullSubscriptionChangesAsync({mailboxOwner}) exiting"); }
/// <summary> /// Poll localDB events and push service bus events to the Queue /// </summary> /// <param name="queueConnection"></param> /// <returns></returns> public async System.Threading.Tasks.Task SendQueueDatabaseChangesAsync(string queueConnection) { var sender = new MessageSender(queueConnection, SBQueueSyncDb); var token = await RetreiveToken(); var EwsService = new EWService(token); EwsService.SetImpersonation(ConnectingIdType.SmtpAddress, MailboxOwner); // Poll the rooms to store locally var roomlisting = EwsService.GetRoomListing(); using (var EwsDatabase = new EWSDbContext(EWSConstants.Config.Database)) { foreach (var roomlist in roomlisting) { foreach (var room in roomlist.Value) { EntityRoomListRoom databaseRoom = null; if (EwsDatabase.RoomListRoomEntities.Any(s => s.SmtpAddress == room.Address)) { databaseRoom = await EwsDatabase.RoomListRoomEntities.FirstOrDefaultAsync(f => f.SmtpAddress == room.Address); } else { databaseRoom = new EntityRoomListRoom() { SmtpAddress = room.Address, Identity = room.Address, RoomList = roomlist.Key }; EwsDatabase.RoomListRoomEntities.Add(databaseRoom); } } } var roomchanges = await EwsDatabase.SaveChangesAsync(); Trace.WriteLine($"Rooms {roomchanges} saved to database."); } var waitTimer = new TimeSpan(0, 5, 0); while (!_cancel.IsCancellationRequested) { var milliseconds = (int)waitTimer.TotalMilliseconds; // whatever you want to happen every 5 minutes Trace.WriteLine($"SendQueueDatabaseChangesAsync({MailboxOwner}) starting at {DateTime.UtcNow.ToShortTimeString()}"); using (var EwsDatabase = new EWSDbContext(EWSConstants.Config.Database)) { var i = 0; var bookings = EwsDatabase.AppointmentEntities.Include(ictx => ictx.Room) .Where(w => !w.ExistsInExchange || !w.SyncedWithExchange || (w.DeletedLocally && !w.SyncedWithExchange)); foreach (var booking in bookings) { Microsoft.Exchange.WebServices.Data.EventType eventType = Microsoft.Exchange.WebServices.Data.EventType.Deleted; if (!booking.ExistsInExchange) { eventType = Microsoft.Exchange.WebServices.Data.EventType.Created; } else if (!booking.SyncedWithExchange) { eventType = Microsoft.Exchange.WebServices.Data.EventType.Modified; } if (string.IsNullOrEmpty(booking.BookingReference)) { booking.BookingReference = $"Ref{booking.Id.ToString().PadLeft(6, '0')}"; } var ewsbooking = new EWS.Common.Models.UpdatedBooking() { DatabaseId = booking.Id, MailBoxOwnerEmail = booking.OrganizerSmtpAddress, SiteMailBox = booking.Room.SmtpAddress, Subject = booking.Subject, Location = booking.Location, StartUTC = booking.StartUTC, EndUTC = booking.EndUTC, ExchangeId = booking.BookingId, ExchangeChangeKey = booking.BookingChangeKey, BookingReference = booking.BookingReference, ExchangeEvent = eventType }; var message = new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(ewsbooking))) { ContentType = "application/json", Label = SBMessageSyncDb, MessageId = i.ToString() }; await sender.SendAsync(message); Trace.WriteLine($"{++i}. Sent: Id = {message.MessageId} w/ Subject:{booking.Subject}"); } Trace.WriteLine($"Sent {i} messages"); } Trace.WriteLine($"Sleeping at {DateTime.UtcNow} for {milliseconds} milliseconds..."); System.Threading.Thread.Sleep(milliseconds); } }