/// <summary> /// Adds the category in Google Reader /// </summary> /// <param name="googleUserID">The Google User ID of the account under which this operation will be performed.</param> /// <param name="name">The name of the category to add</param> internal void AddCategoryInGoogleReader(string googleUserID, string name) { var op = new PendingGoogleReaderOperation(GoogleReaderOperation.AddLabel, new object[] { name }, googleUserID); lock (pendingGoogleReaderOperations) { pendingGoogleReaderOperations.Add(op); } }
/// <summary> /// Enqueues an event that adds a feed to the list of user's subscriptions in Google Reader /// </summary> /// <param name="googleUserID">The Google User ID of the account under which this operation will be performed.</param> /// <param name="feedUrl">The URL of the feed to add</param> /// <param name="title">The title of the new subscription</param> /// <returns>A GoogleReaderSubscription that describes the newly added feed</returns> public void AddFeedInGoogleReader(string googleUserID, string feedUrl, string title) { var op = new PendingGoogleReaderOperation(GoogleReaderOperation.AddFeed, new object[] { feedUrl, title }, googleUserID); lock (pendingGoogleReaderOperations) { pendingGoogleReaderOperations.Add(op); } }
/// <summary> /// Enqueues an event to mark an item as read or unread in Google Reader /// </summary> /// <param name="googleUserID">The Google User ID of the account under which this operation will be performed.</param> /// <param name="feedId">The ID of the parent feed in Google Reader</param> /// <param name="itemId">The atom:id of the news item</param> /// <param name="beenRead">Indicates whether the item was marked as read or unread</param> public void ChangeItemReadStateInGoogleReader(string googleUserID, string feedId, string itemId, bool beenRead) { var op = new PendingGoogleReaderOperation(GoogleReaderOperation.MarkSingleItemRead, new object[] { feedId, itemId, beenRead }, googleUserID); lock (pendingGoogleReaderOperations) { pendingGoogleReaderOperations.Add(op); } }
/// <summary> /// Enqueues an event to mark all items older than the the specified date as read in Google Reader /// </summary> /// <param name="googleUserID">The Google User ID of the account under which this operation will be performed.</param> /// <param name="feedUrl">The feed URL</param> /// <param name="olderThan">The date from which to mark all items older than that date as read</param> public void MarkAllItemsAsReadInGoogleReader(string googleUserID, string feedUrl, string olderThan) { var op = new PendingGoogleReaderOperation(GoogleReaderOperation.MarkAllItemsRead, new object[] { feedUrl, olderThan }, googleUserID); lock (pendingGoogleReaderOperations) { pendingGoogleReaderOperations.Add(op); } }
/// <summary> /// Enqueus an item that deletes the category in Google Reader /// </summary> /// <param name="googleUserID">The Google User ID of the account under which this operation will be performed.</param> /// <param name="name">The name of the category to delete</param> public void DeleteCategoryInGoogleReader(string googleUserID, string name) { var op = new PendingGoogleReaderOperation(GoogleReaderOperation.DeleteLabel, new object[] { name }, googleUserID); lock (pendingGoogleReaderOperations) { pendingGoogleReaderOperations.Add(op); } }
/// <summary> /// Enqueues an event that changes the category of a feed in Google Reader /// </summary> /// <param name="googleUserID">The Google User ID of the account under which this operation will be performed.</param> /// <param name="feedUrl">The feed URL</param> /// <param name="newCategory">The new category for the feed</param> /// <param name="oldCategory">The old category of the feed.</param> public void ChangeCategoryInGoogleReader(string googleUserID, string feedUrl, string newCategory, string oldCategory) { var op = new PendingGoogleReaderOperation(GoogleReaderOperation.MoveFeed, new object[] { feedUrl, newCategory, oldCategory }, googleUserID); lock (pendingGoogleReaderOperations) { pendingGoogleReaderOperations.Add(op); } }
/// <summary> /// Renames the specified category /// </summary> /// <remarks>This method assumes that the caller will rename categories on INewsFeed instances directly instead /// of having this method do it automatically.</remarks> /// <param name="googleUserID">The Google User ID of the account under which this operation will be performed.</param> /// <param name="oldName">The old name of the category</param> /// <param name="newName">The new name of the category</param> public void RenameCategoryInGoogleReader(string googleUserID, string oldName, string newName) { lock (pendingGoogleReaderOperations) { //don't bother adding a folder that was later renamed, simply add the final named folder PendingGoogleReaderOperation addFolderOp = pendingGoogleReaderOperations.Find( oldOp => oldOp.Action == GoogleReaderOperation.AddLabel && oldName.Equals(oldOp.Parameters[0])); if (addFolderOp == null) { //also check if category was renamed then renamed again PendingGoogleReaderOperation renameOp = pendingGoogleReaderOperations.Find( oldOp => oldOp.Action == GoogleReaderOperation.RenameLabel && oldName.Equals(oldOp.Parameters[1])); if (renameOp == null) { var op = new PendingGoogleReaderOperation(GoogleReaderOperation.RenameLabel, new object[] { oldName, newName }, googleUserID); pendingGoogleReaderOperations.Add(op); } else { pendingGoogleReaderOperations.Remove(renameOp); pendingGoogleReaderOperations.Add( new PendingGoogleReaderOperation(GoogleReaderOperation.RenameLabel, new[] { renameOp.Parameters[0], newName }, googleUserID)); } } else { pendingGoogleReaderOperations.Remove(addFolderOp); pendingGoogleReaderOperations.Add(new PendingGoogleReaderOperation(GoogleReaderOperation.AddLabel, new object[] { newName }, googleUserID)); } } }
/// <summary> /// Enqueues an event that deletes a feed from the list of user's subscriptions in Google Reader /// </summary> /// <param name="googleUserID">The Google User ID of the account under which this operation will be performed.</param> /// <param name="feedUrl">The URL of the feed to delete</param> /// <param name="feedTitle">The title of the feed to delete</param> public void DeleteFeedFromGoogleReader(string googleUserID, string feedUrl, string feedTitle) { var deleteOp = new PendingGoogleReaderOperation(GoogleReaderOperation.DeleteFeed, new object[] { feedUrl, feedTitle }, googleUserID); lock (pendingGoogleReaderOperations) { //remove all pending operations related to the feed since it is going to be unsubscribed IEnumerable <PendingGoogleReaderOperation> ops2remove = pendingGoogleReaderOperations.Where(op => op.GoogleUserName.Equals(deleteOp.GoogleUserName) && op.Parameters.Contains(feedUrl)); var ops2remove_array = ops2remove.ToArray(); //prevent collection modified Exceptions foreach (PendingGoogleReaderOperation op2remove in ops2remove_array) { pendingGoogleReaderOperations.Remove(op2remove); } pendingGoogleReaderOperations.Add(deleteOp); } }
/// <summary> /// Performs a set of pending network operations from the pendingGoogleReaderOperations queue on the /// Google Reader service. /// </summary> /// <param name="batchedItemsAmount">The number of operations that should be performed.</param> private void FlushPendingOperations(int batchedItemsAmount) { try { flushInprogress = true; do { PendingGoogleReaderOperation pendingOp = null; //perform all queued operations on the index lock (pendingGoogleReaderOperations) { if (pendingGoogleReaderOperations.Count > 0) { pendingOp = pendingGoogleReaderOperations[0]; } } //lock //Optimizing the index is an expensive operation so we don't want to //call it if the queue is being flushed since it may delay application exit. if (pendingOp != null) { PerformOperation(pendingOp); pendingGoogleReaderOperations.RemoveAt(0); } batchedItemsAmount--; //potential race condition on this.pendingIndexOperations.Count but chances are very low } while (pendingGoogleReaderOperations.Count > 0 && batchedItemsAmount >= 0); } finally { flushInprogress = false; } }
/// <summary> /// Performs the specified PendingGoogleReaderOperation. /// </summary> /// <param name="current">The operation to perform</param> private void PerformOperation(PendingGoogleReaderOperation current) { GoogleReaderFeedSource source = null; FeedSources.TryGetValue(current.GoogleUserName, out source); if (source == null) { return; } try { switch (current.Action) { case GoogleReaderOperation.AddFeed: source.AddFeedInGoogleReader(current.Parameters[0] as string, current.Parameters[1] as string); break; case GoogleReaderOperation.AddLabel: source.AddCategoryInGoogleReader(current.Parameters[0] as string); break; case GoogleReaderOperation.DeleteFeed: source.DeleteFeedFromGoogleReader(current.Parameters[0] as string, current.Parameters[1] as string); break; case GoogleReaderOperation.DeleteLabel: source.DeleteCategoryInGoogleReader(current.Parameters[0] as string); break; case GoogleReaderOperation.MarkAllItemsRead: source.MarkAllItemsAsReadInGoogleReader(current.Parameters[0] as string, current.Parameters[1] as string); break; case GoogleReaderOperation.MarkSingleItemRead: source.ChangeItemReadStateInGoogleReader(current.Parameters[0] as string, current.Parameters[1] as string, (bool)current.Parameters[2]); break; case GoogleReaderOperation.MarkSingleItemTagged: source.ChangeItemTaggedStateInGoogleReader(current.Parameters[0] as string, current.Parameters[1] as string, current.Parameters[2] as string, (bool)current.Parameters[3]); break; case GoogleReaderOperation.MoveFeed: source.ChangeCategoryInGoogleReader(current.Parameters[0] as string, current.Parameters[1] as string, current.Parameters[2] as string); break; case GoogleReaderOperation.RenameFeed: source.RenameFeedInGoogleReader(current.Parameters[0] as string, current.Parameters[1] as string); break; case GoogleReaderOperation.RenameLabel: source.RenameCategoryInGoogleReader(current.Parameters[0] as string, current.Parameters[1] as string); break; default: Debug.Assert(false, "Unknown Google Reader operation: " + current.Action); return; } } catch (Exception e) { //TODO: Rethrow to handle time outs and connections cancelled by host _log.Error("Error in GoogleReaderModifier.PerformOperation:", e); } ; }