• R/O
  • SSH
  • HTTPS

poi-poi-capsule: Commit


Commit MetaInfo

Revision266 (tree)
Time2011-04-19 18:46:53
Authorpoi-poi-capsule

Log Message

・スターアイテム取得処理のマルチスレッド化
・その他細かいリファクタリング

Change Summary

Incremental Difference

--- trunk/0.2.X/AppController.m (revision 265)
+++ trunk/0.2.X/AppController.m (revision 266)
@@ -528,11 +528,6 @@
528528 // Kick off an initial refresh
529529 if ([prefs refreshOnStartup])
530530 [self refreshAllSubscriptions:self];
531-
532- // スターアイテムの同期
533- // TODO:フィードリフレッシュ時に非同期で行ったほうがいいだろう。
534- [[RefreshManagerGoogle sharedManager] starItemRefresh];
535-
536531 }
537532
538533 /* applicationShouldHandleReopen
@@ -3386,7 +3381,6 @@
33863381
33873382 if (![self isConnectingGoogle])
33883383 {
3389- // GoogleReaderと同期を指定していれば、購読リストのリフレッシュを行う。
33903384 BOOL loginSuccess = [[LoginControllerGoogle sharedManager] loginGoogle];
33913385 if (YES == loginSuccess)
33923386 {
@@ -3395,9 +3389,16 @@
33953389 // 購読リストの同期
33963390 [google syncFoldersAndFeedURLs];
33973391
3398- // 既読状態の同期
3399- [[RefreshManagerGoogle sharedManager] syncReadFlag];
3392+ // 未読記事取得
3393+
3394+ // 各購読リストから10件づつ記事を取得
3395+
3396+ // スターアイテムの同期
3397+ [google refreshStarItem:[[Database sharedDatabase] starItemFolder]];
34003398
3399+ // 既読状態の同期と既読記事取得
3400+ [google syncReadFlag];
3401+
34013402 // 購読記事のリフレッシュ
34023403 [google refreshSubscriptions:[foldersTree folders:0] ignoringSubscriptionStatus:NO];
34033404
--- trunk/0.2.X/EditManagerGoogle.h (revision 265)
+++ trunk/0.2.X/EditManagerGoogle.h (revision 266)
@@ -46,8 +46,7 @@
4646 - (void) notifyStarFlag:(NSString *)theGuid
4747 :(NSString *)feedURL
4848 :(BOOL)isStarAdd;
49-- (NSData*)getStarItem:(NSString*)continuation :(int)getItemCount;
50-- (int)getStarItemCount;
5149 - (NSArray*)getReadFeedList;
50+- (NSData*)getReedItem:(NSString*)directStreamIds;
5251
5352 @end
--- trunk/0.2.X/EditManagerGoogle.m (revision 265)
+++ trunk/0.2.X/EditManagerGoogle.m (revision 266)
@@ -659,84 +659,18 @@
659659 }
660660
661661 /*
662- * スター付きアイテムの数を取得
662+ * 最終更新時刻以降の既読記事を取得(最大10000件)
663663 */
664-- (int)getStarItemCount
665-{
666-
667- NSDictionary *header = [self createHttpHeader];
668- NSURL* url = [NSURL URLWithString:@"http://www.google.com/reader/api/0/stream/items/ids?n=10000&s=user/-/state/com.google/starred&output=xml&offsync=true"];
669-
670- NSData* reciveData;
671- HttpResult ret = [self httpRequest:@"GET"
672- url:url
673- reciveData:&reciveData
674- header:header
675- ];
676-
677- if(Ret_200OK != ret)
678- {
679- return 0;
680- }
681-
682- DDXMLDocument *doc = [[[DDXMLDocument alloc] initWithData:reciveData
683- options:0 error:nil] autorelease];
684- DDXMLElement *root = [doc rootElement];
685-
686- NSArray *feedListCount = [root nodesForXPath:@"//object/list[1]" error:nil];
687-
688- return [feedListCount count]-1;
689-
690-}
691-
692-/*
693- * 現在購読しているスター付きアイテムの取得
694- */
695-- (NSData*)getStarItem:(NSString*)continuation :(int)getItemCount
696-{
697- NSDictionary *header = [self createHttpHeader];
698-
699- NSURL *url;
700- if (nil == continuation)
701- {
702- url = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.google.com"
703- @"/reader/atom/user/-/state/com.google/starred?n=%d",
704- getItemCount]];
705- } else {
706- url = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.google.com"
707- @"/reader/atom/user/-/state/com.google"
708- @"/starred?n=%d&c=%@",
709- getItemCount, continuation]];
710- }
711-
712- NSData* reciveData;
713- HttpResult ret = [self httpRequest:@"GET"
714- url:url
715- reciveData:&reciveData
716- header:header
717- ];
718-
719- if(Ret_200OK != ret)
720- {
721- return nil;
722- }
723-
724- return reciveData;
725-}
726-
727-/*
728- * 最終更新時刻以降の既読記事を取得(最大1000件)
729- */
730664 - (NSData*)getReadFeed
731665 {
732666 NSDictionary *header = [self createHttpHeader];
733667
734668 NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.google.com"
735- @"/reader/api/0/stream/items/ids?s=user/-/state/com.google/read&n=1000&ot=%@",
669+ @"/reader/api/0/stream/items/ids?s=user/-/state/com.google/read&n=10000&ot=%@",
736670 [[Database sharedDatabase] getLastRefreshDate]]];
737671
738- NSLog(@"%@", [NSString stringWithFormat:@"http://www.google.com/reader/api/0/stream/items/ids?s=user/-/state/com.google/read&n=1000&ot=%@",
739- [[Database sharedDatabase] getLastRefreshDate]]);
672+ //NSLog(@"%@", [NSString stringWithFormat:@"http://www.google.com/reader/api/0/stream/items/ids?s=user/-/state/com.google/read&n=1000&ot=%@",
673+ // [[Database sharedDatabase] getLastRefreshDate]]);
740674
741675 NSData* reciveData;
742676 HttpResult ret = [self httpRequest:@"GET"
@@ -754,7 +688,7 @@
754688 }
755689
756690 /*
757- * 最終更新時刻以降の既読記事を取得(最大1000件)し、IDのリストを返却する
691+ * 最終更新時刻以降の既読記事を取得(最大10000件)し、IDのリストを返却する
758692 */
759693 - (NSArray*)getReadFeedList
760694 {
@@ -771,21 +705,56 @@
771705 int i=0;
772706 for (;i<[feedListCount count];i++)
773707 {
774- //id
775- NSArray *feedListGoogle = [root nodesForXPath:[NSString stringWithFormat:@"//object[1]/list[1]/object[%d]/number[1]", i+offset] error:nil];
776708
709+ NSMutableDictionary *dict = [[[NSMutableDictionary alloc] init] autorelease];
710+
711+ // id
712+ NSArray *feedListId = [root nodesForXPath:[NSString stringWithFormat:@"//object[1]/list[1]/object[%d]/number[1]", i+offset] error:nil];
777713 NSMutableString *tempFeedId = [NSMutableString stringWithFormat:@"%@",
778- [[feedListGoogle objectAtIndex:0] stringValue]];
779-
780- //NSLog(@"%@", tempFeedId);
714+ [[feedListId objectAtIndex:0] stringValue]];
715+ [dict setObject:[NSString stringWithFormat:@"%016qx", [tempFeedId longLongValue]]
716+ forKey:@"id"];
717+
718+ // directStreamIds
719+ NSArray *feedListDSI = [root nodesForXPath:[NSString stringWithFormat:@"//object[1]/list[1]/object[%d]/list[1]/string[1]", i+offset] error:nil];
720+ [dict setObject:[[feedListDSI objectAtIndex:0] stringValue] forKey:@"directStreamIds"];
721+ [result addObject:dict];
722+
723+ //NSLog(@"%@", [root nodesForXPath:[NSString stringWithFormat:@"//object[1]/list[1]/object[%d]/list[1]/string[1]", i+offset] error:nil]);
724+ //NSLog(@"%@", [NSString stringWithFormat:@"%016qx", [[feedListId objectAtIndex:0] longLongValue]]);
781725 //NSLog(@"%@", [NSString stringWithFormat:@"%016qx", [tempFeedId longLongValue]]);
782726 //符号なし64ビット整数 (unsigned long long), 16進数[0-9a-f]として表示。(a-fは小文字)
783- [result addObject:[NSString stringWithFormat:@"%016qx", [tempFeedId longLongValue]]];
784-
785727 }
786728 return result;
787729 }
788730
731+
732+/*
733+ * 未取得の既読記事を取得する
734+ */
735+- (NSData*)getReedItem:(NSString*)directStreamIds
736+{
737+ NSDictionary *header = [self createHttpHeader];
738+
739+ NSURL *url;
740+ url = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.google.com/reader/atom/%@",
741+ directStreamIds]];
742+
743+ NSData* reciveData;
744+ HttpResult ret = [self httpRequest:@"GET"
745+ url:url
746+ reciveData:&reciveData
747+ header:header
748+ ];
749+
750+ if(Ret_200OK != ret)
751+ {
752+ return nil;
753+ }
754+
755+ return reciveData;
756+}
757+
789758 -(void)dealloc
790759 {
791760 [token release];
--- trunk/0.2.X/RefreshManagerGoogle.h (revision 265)
+++ trunk/0.2.X/RefreshManagerGoogle.h (revision 266)
@@ -37,6 +37,6 @@
3737 +(RefreshManagerGoogle *)sharedManager;
3838 -(void)subscriptionFeed:(Folder *)folder;
3939 -(void)syncFoldersAndFeedURLs;
40--(void)starItemRefresh;
4140 -(void)syncReadFlag;
41+-(void)refreshStarItem:(Folder *)folder;
4242 @end
--- trunk/0.2.X/RefreshManagerGoogle.m (revision 265)
+++ trunk/0.2.X/RefreshManagerGoogle.m (revision 266)
@@ -30,7 +30,8 @@
3030 typedef enum {
3131 MA_Refresh_NilType = -1,
3232 MA_Refresh_Feed,
33- MA_Refresh_FavIcon
33+ MA_Refresh_FavIcon,
34+ MA_Refresh_Star
3435 } RefreshTypes;
3536
3637
@@ -65,6 +66,12 @@
6566 -(NSString *)getRedirectURL:(NSData *)data;
6667 -(BOOL)findFeedUrlToLocal:(NSDictionary *)googleFolder;
6768 -(BOOL)findFeedUrlToGoogle:(NSArray *)folderArrayGoogle :(Folder *)localFolder;
69+-(void)refreshSubscriptions:(NSArray *)foldersArray ignoringSubscriptionStatus:(BOOL)ignoreSubStatus;
70+-(BOOL)isRefreshingFolder:(Folder *)folder ofType:(RefreshTypes)type;
71+-(void)connRequest:(NSURL *)url :(Folder *)folder :(ActivityItem*)aItem :(SEL)endSelector;
72+-(void)getStarItemListCompleted:(AsyncConnection *)connector;
73+-(void)pumpStarItemListRefresh:(Folder *)folder;
74+-(void)pumpStarItemFeedRefresh:(Folder *)folder;
6875 @end
6976
7077 // Single refresh item type
@@ -469,7 +476,6 @@
469476 */
470477 -(void)pumpSubscriptionRefreshGoogle:(Folder *)folder
471478 {
472- AsyncConnection * conn;
473479
474480 // GoogleReaderと同期していないFeedはスキップ。
475481 if (MA_Google_NOT_SYNC == [folder googleSyncFlag])
@@ -507,29 +513,39 @@
507513 ,[[unReadDict objectForKey:@"id"] stringByURLEncoding:NSUTF8StringEncoding]
508514 ,unReadCount]];
509515
510- @try
511- {
512- conn = [[AsyncConnection alloc] init];
513- [conn setHttpHeaders:[[EditManagerGoogle sharedManager] createHttpHeader]];
514-
515- if ([conn beginLoadDataFromURL:url
516- username:[folder username]
517- password:[folder password]
518- delegate:self
519- contextData:folder
520- log:aItem
521- didEndSelector:@selector(folderRefreshCompleted:)])
522- [self addConnection:conn];
523- }
524- @finally
525- {
526- [conn release];
527- break;
528- }
516+ [self connRequest:url
517+ :folder
518+ :aItem
519+ :@selector(folderRefreshCompleted:)];
529520 }
530521 }
531522
523+-(void)connRequest:(NSURL *)url :(Folder *)folder :(ActivityItem*)aItem :(SEL)endSelector
524+{
525+ AsyncConnection * conn;
526+ @try
527+ {
528+ conn = [[AsyncConnection alloc] init];
529+ [conn setHttpHeaders:[[EditManagerGoogle sharedManager] createHttpHeader]];
530+
531+ if ([conn beginLoadDataFromURL:url
532+ username:[folder username]
533+ password:[folder password]
534+ delegate:self
535+ contextData:folder
536+ log:aItem
537+ didEndSelector:endSelector])
538+ [self addConnection:conn];
539+ }
540+ @finally
541+ {
542+ [conn release];
543+ }
544+}
532545
546+/* refreshSubscriptions
547+ * Add the folders specified in the foldersArray to the refreshArray.
548+ */
533549 -(void)refreshSubscriptions:(NSArray *)foldersArray ignoringSubscriptionStatus:(BOOL)ignoreSubStatus
534550 {
535551 // GoogleReaderから未読記事リストの取得し、新着記事を取得する
@@ -537,10 +553,43 @@
537553 if (nil == unReadCountList)
538554 return;
539555
540- [super refreshSubscriptions:foldersArray ignoringSubscriptionStatus:ignoreSubStatus];
541-
556+ statusMessageDuringRefresh = NSLocalizedString(@"Refreshing subscriptions...", nil);
557+ for (Folder * folder in foldersArray)
558+ {
559+ if (IsGroupFolder(folder))
560+ [self refreshSubscriptions:[[Database sharedDatabase] arrayOfFolders:[folder itemId]] ignoringSubscriptionStatus:NO];
561+ else if (IsRSSFolder(folder))
562+ {
563+ if (!IsUnsubscribed(folder) || ignoreSubStatus)
564+ {
565+ if (![self isRefreshingFolder:folder ofType:MA_Refresh_Feed])
566+ {
567+ RefreshItemGoogle * newItem = [[RefreshItemGoogle alloc] init];
568+ [newItem setFolder:folder];
569+ [newItem setType:MA_Refresh_Feed];
570+ [refreshArray addObject:newItem];
571+ [newItem release];
572+ }
573+ }
574+ }
575+ }
576+ [self beginRefreshTimer];
542577 }
543578
579+/* isRefreshingFolder
580+ * Returns whether refreshArray has an queue refresh for the specified folder
581+ * and refresh type.
582+ */
583+-(BOOL)isRefreshingFolder:(Folder *)folder ofType:(RefreshTypes)type
584+{
585+ for (RefreshItemGoogle * item in refreshArray)
586+ {
587+ if ([item folder] == folder && [item type] == type)
588+ return YES;
589+ }
590+ return NO;
591+}
592+
544593 -(void)refreshPumper:(NSTimer *)aTimer
545594 {
546595 while (([connectionsArray count] < maximumConnections) && ([refreshArray count] > 0))
@@ -559,6 +608,11 @@
559608 case MA_Refresh_FavIcon:
560609 [self pumpFolderIconRefresh:[item folder]];
561610 break;
611+
612+ case MA_Refresh_Star:
613+ [self pumpStarItemListRefresh:[item folder]];
614+ break;
615+
562616 }
563617 [refreshArray removeObjectAtIndex:0];
564618 }
@@ -600,186 +654,6 @@
600654 return;
601655 }
602656
603-/* starItemRefresh
604- * スターアイテムの同期を行う。
605- */
606--(void)starItemRefresh
607-{
608- if (NO == updateStarItem)
609- return;
610-
611- Database * db = [Database sharedDatabase];
612- Folder * folder = [db starItemFolder];
613- int folderId = [folder itemId];
614-
615- EditManagerGoogle * edit = [EditManagerGoogle sharedManager];
616-
617- [self setFolderUpdatingFlag:folder flag:NO];
618- int serverRecordCount = [edit getStarItemCount];
619- NSData * receivedData = [edit getStarItem:nil :serverRecordCount];
620-
621- // Empty data feed is OK if we got HTTP 200
622- int newArticlesFromFeed = 0;
623- RichXMLParser * newFeed = [[RichXMLParser alloc] init];
624- if ([receivedData length] > 0)
625- {
626- // Create a new rich XML parser instance that will take care of
627- // parsing the XML data we just got.
628- if (newFeed == nil || ![newFeed parseRichXML:receivedData])
629- {
630- // Mark the feed as failed
631- [self setFolderErrorFlag:folder flag:YES];
632- [newFeed release];
633- return;
634- }
635-
636- // Extract the latest title and description
637- NSString * feedTitle = [newFeed title];
638- NSString * feedDescription = [newFeed description];
639-
640- // We'll be collecting articles into this array
641- NSMutableArray * articleArray = [NSMutableArray array];
642- NSMutableArray * articleGuidArray = [NSMutableArray array];
643-
644- // Parse off items.
645-
646- for (FeedItem * newsItem in [newFeed items])
647- {
648- NSDate * articleDate = [newsItem date];
649-
650- //16桁のID部分のみを切り出す
651- NSMutableString * tempGuid = [NSMutableString stringWithFormat:[newsItem guid]];
652- [tempGuid replaceOccurrencesOfString:@"tag:google.com,2005:reader/item/"
653- withString:@""
654- options:NSLiteralSearch
655- range:NSMakeRange(0, [tempGuid length])];
656-
657- //既存のレコードと重複させないよう、guidの先頭に"star:"を付与する。
658- NSString * articleGuid = [NSString stringWithFormat:@"%@%@",
659- MA_StarItem_String, tempGuid];
660-
661- // Bad feeds! I'm talking to you, WordPress Trac.
662- NSUInteger articleIndex = [articleGuidArray indexOfObject:articleGuid];
663- if (articleIndex != NSNotFound)
664- {
665- if (articleDate == nil)
666- continue; // Skip this duplicate article
667-
668- Article * existingArticle = [articleArray objectAtIndex:articleIndex];
669- if ([articleDate compare:[existingArticle date]] == NSOrderedDescending)
670- {
671- // This article is later, so use it instead
672- [articleArray removeObjectAtIndex:articleIndex];
673- [articleGuidArray removeObjectAtIndex:articleIndex];
674- }
675- else
676- continue; // Skip this duplicate article
677- }
678- [articleGuidArray addObject:articleGuid];
679-
680- if (articleDate == nil)
681- articleDate = [NSDate date];
682-
683- Article * article = [[Article alloc] initWithGuid:articleGuid];
684- [article setFolderId:folderId];
685- [article setAuthor:[newsItem author]];
686- [article setBody:[newsItem description]];
687- [article setTitle:[newsItem title]];
688- [article setLink:[newsItem link]];
689- [article setDate:articleDate];
690- [article setEnclosure:[newsItem enclosure]];
691- [article markRead:YES];
692- [article markFlagged:YES];
693- if ([[article enclosure] isNotEqualTo:@""])
694- {
695- [article setHasEnclosure:YES];
696- }
697- [articleArray addObject:article];
698- [article release];
699-
700- //guidに対応するレコードがあれば、フラグをONにする。
701- [db updateStarItem:folderId :tempGuid];
702- }
703-
704- // Here's where we add the articles to the database
705- if ([articleArray count] > 0u)
706- {
707- //サーバ側のスター付きアイテムに無いローカル側のアイテムは削除。
708- [db beginTransaction];
709- BOOL findFlag;
710- NSArray * localArticles = [folder articles];
711- for (Article * localArticle in localArticles)
712- {
713- findFlag = NO;
714- for (Article * serverArticle in articleArray)
715- {
716- if ([[localArticle guid] isEqualToString:[serverArticle guid]])
717- {
718- findFlag = YES;
719- break;
720- }
721- }
722- if (NO == findFlag)
723- {
724- //削除
725- [db markArticleFlagged:[folder itemId]
726- guid:[localArticle guid]
727- isFlagged:NO];
728- }
729- }
730-
731- NSArray * guidHistory = [db guidHistoryForFolderId:folderId];
732-
733- [folder clearCache];
734- // Should we wrap the entire loop or just individual article updates?
735- for (Article * article in articleArray)
736- {
737- //DBにぶち込む。
738- if ([db createArticle:folderId article:article guidHistory:guidHistory] && ([article status] == MA_MsgStatus_New))
739- ++newArticlesFromFeed;
740- }
741- [db commitTransaction];
742- } else {
743- //ローカル側のアイテムを全削除。
744- [db beginTransaction];
745- NSArray * localArticles = [folder articles];
746- for (Article * localArticle in localArticles)
747- {
748- [db markArticleFlagged:[folder itemId]
749- guid:[localArticle guid]
750- isFlagged:NO];
751- }
752- [db commitTransaction];
753- }
754-
755- [db beginTransaction];
756-
757- // A notify is only needed if we added any new articles.
758- if ([[folder name] hasPrefix:[Database untitledFeedFolderName]] && ![feedTitle isBlank])
759- {
760- // If there's an existing feed with this title, make ours unique
761- // BUGBUG: This duplicates logic in database.m so consider moving it there.
762- NSString * oldFeedTitle = feedTitle;
763- unsigned int index = 1;
764-
765- while (([db folderFromName:feedTitle]) != nil)
766- feedTitle = [NSString stringWithFormat:@"%@ (%i)", oldFeedTitle, index++];
767-
768- [db setFolderName:folderId newName:feedTitle];
769- }
770- if (feedDescription != nil)
771- [db setFolderDescription:folderId newDescription:feedDescription];
772-
773- [db commitTransaction];
774-
775- }
776-
777- // Done with this connection
778- [newFeed release];
779-
780- updateStarItem = NO;
781-}
782-
783657 /* folderRefreshCompleted
784658 * Called when a folder refresh completed.
785659 */
@@ -1058,7 +932,7 @@
1058932 -(void)syncReadFlag
1059933 {
1060934 Database *db = [Database sharedDatabase];
1061- for (NSString * readFeedId in [[EditManagerGoogle sharedManager] getReadFeedList])
935+ for (NSDictionary * readFeedDict in [[EditManagerGoogle sharedManager] getReadFeedList])
1062936 {
1063937 for (Folder * folder in [db arrayOfAllFolders])
1064938 {
@@ -1065,12 +939,17 @@
1065939 if (![folder isRSSFolder])
1066940 continue;
1067941
1068- Article * article = [folder articleFromGuid:readFeedId];
942+ Article * article = [folder articleFromGuid:[readFeedDict objectForKey:@"id"]];
1069943 //NSLog(@"%@", readFeedId);
1070944
1071- //if (nil != article)
1072- if (nil != article && NO == [article isRead])
945+ if (nil == article)
946+ {
947+ //既読記事取得
948+ //[[EditManagerGoogle sharedManager] getReedItem:[readFeedDict objectForKey:@"directStreamIds"]];
949+
950+ } else if (NO == [article isRead]) {
1073951 [db markArticleRead:[folder itemId] guid:[article guid] isRead:YES notifyFlag:NO];
952+ }
1074953 }
1075954 }
1076955
@@ -1077,6 +956,388 @@
1077956 [db updateLastRefreshDate];
1078957 }
1079958
959+/* refreshSubscriptions
960+ * Add the folders specified in the foldersArray to the refreshArray.
961+ */
962+-(void)refreshStarItem:(Folder *)folder
963+{
964+ RefreshItemGoogle * newItem = [[RefreshItemGoogle alloc] init];
965+ [newItem setFolder:folder];
966+ [newItem setType:MA_Refresh_Star];
967+ [refreshArray addObject:newItem];
968+ [newItem release];
969+ [self beginRefreshTimer];
970+}
971+
972+/*
973+ * スターリストの取得
974+ */
975+-(void)pumpStarItemListRefresh:(Folder *)folder
976+{
977+
978+ NSString * name = [[folder name] isEqualToString:[Database untitledFeedFolderName]] ? [folder feedURL] : [folder name];
979+ ActivityItem * aItem = [[ActivityLog defaultLog] itemByName:name];
980+ // Seed the activity log for this feed.
981+ [aItem clearDetails];
982+ [aItem setStatus:NSLocalizedString(@"Retrieving articles", nil)];
983+
984+ // Mark the folder as being refreshed. The updating status is not
985+ // persistent so we set this directly on the folder rather than
986+ // through the database.
987+ [self setFolderUpdatingFlag:folder flag:YES];
988+
989+ // Additional detail for the log
990+ [aItem appendDetail:[NSString stringWithFormat:NSLocalizedString(@"Connecting to %@", nil), [folder feedURL]]];
991+
992+ NSURL* url = [NSURL URLWithString:@"http://www.google.com/"
993+ @"reader/api/0/stream/items/ids?"
994+ @"s=user/-/state/com.google/starred&n=10000"];
995+
996+ [self connRequest:url
997+ :folder
998+ :aItem
999+ :@selector(getStarItemListCompleted:)];
1000+}
1001+
1002+-(void)getStarItemListCompleted:(AsyncConnection *)connector
1003+{
1004+ Folder * folder = (Folder *)[connector contextData];
1005+ int folderId = [folder itemId];
1006+ Database * db = [Database sharedDatabase];
1007+
1008+ [self setFolderUpdatingFlag:folder flag:NO];
1009+
1010+ if ([connector status] == MA_Connect_Stopped)
1011+ {
1012+ // Stopping the connection isn't an error, so clear any
1013+ // existing error flag.
1014+ [self setFolderErrorFlag:folder flag:NO];
1015+
1016+ // Set the last update date for this folder.
1017+ [db setFolderLastUpdate:folderId lastUpdate:[NSDate date]];
1018+
1019+ // If this folder also requires an image refresh, add that
1020+ if ([folder flags] & MA_FFlag_CheckForImage)
1021+ [self refreshFavIcon:folder];
1022+ }
1023+ else if ([connector status] == MA_Connect_URLIsGone)
1024+ {
1025+ // We got HTTP 410 which means the feed has been intentionally
1026+ // removed so unsubscribe the feed.
1027+ [db setFolderFlag:folderId flagToSet:MA_FFlag_Unsubscribed];
1028+ [[NSNotificationCenter defaultCenter] postNotificationName:@"MA_Notify_FoldersUpdated" object:[NSNumber numberWithInt:folderId]];
1029+ }
1030+ //saka 通信障害のルート
1031+ else if ([connector status] == MA_Connect_Failed)
1032+ {
1033+ // Mark the feed as failed
1034+ [self setFolderErrorFlag:folder flag:YES];
1035+ }
1036+ else if ([connector status] == MA_Connect_Succeeded)
1037+ {
1038+ NSData * receivedData = [connector receivedData];
1039+ DDXMLDocument *doc = [[[DDXMLDocument alloc] initWithData:receivedData
1040+ options:0 error:nil] autorelease];
1041+ DDXMLElement *root = [doc rootElement];
1042+
1043+
1044+ NSArray *feedListCount = [root nodesForXPath:@"//object[1]/list[1]/object" error:nil];
1045+ //NSLog(@"%d", [feedListCount count]);
1046+
1047+ int offset = 1;
1048+ NSArray * articlesArray = [folder articles];
1049+ if ([articlesArray count] != [feedListCount count]) {
1050+ [self pumpStarItemFeedRefresh:folder];
1051+ } else {
1052+ int roopCnt1=0;
1053+ for (;roopCnt1<[feedListCount count];roopCnt1++)
1054+ {
1055+ BOOL findFlg1 = NO;
1056+ // id
1057+ NSArray *feedListId = [root nodesForXPath:[NSString stringWithFormat:@"//object[1]/list[1]/object[%d]/number[1]",
1058+ roopCnt1+offset] error:nil];
1059+
1060+ NSString *tempGuid = [[feedListId objectAtIndex:0] stringValue];
1061+
1062+ //NSLog(@"%@", [NSString stringWithFormat:@"%016qx", [tempGuid longLongValue]]);
1063+
1064+ for (Article * article in articlesArray)
1065+ {
1066+ if ([[article guid] isEqualToString:[NSString stringWithFormat:@"%@%016qx", MA_StarItem_String, [tempGuid longLongValue]]]) {
1067+ findFlg1 = YES;
1068+ break;
1069+ }
1070+ }
1071+
1072+ if (findFlg1 == YES)
1073+ continue;
1074+
1075+ //未取得のスター記事を取得する
1076+ // directStreamIds
1077+ //NSArray *feedListDSI = [root nodesForXPath:[NSString stringWithFormat:@"//object[1]/list[1]/object[%d]/list[1]/string[1]", i+offset] error:nil];
1078+ [self pumpStarItemFeedRefresh:folder];
1079+ }
1080+
1081+ for (Article * article in articlesArray)
1082+ {
1083+ BOOL findFlg2 = NO;
1084+ int roopCnt2 = 0;
1085+ for (;roopCnt2<[feedListCount count];roopCnt2++)
1086+ {
1087+ // id
1088+ NSArray *feedListId = [root nodesForXPath:[NSString stringWithFormat:@"//object[1]/list[1]/object[%d]/number[1]",
1089+ roopCnt2+offset] error:nil];
1090+
1091+ NSString *tempGuid = [[feedListId objectAtIndex:0] stringValue];
1092+
1093+ //NSLog(@"%@", [NSString stringWithFormat:@"%016qx", [tempGuid longLongValue]]);
1094+
1095+ if ([[article guid] isEqualToString:[NSString stringWithFormat:@"%@%016qx", MA_StarItem_String, [tempGuid longLongValue]]]) {
1096+ findFlg2 = YES;
1097+ break;
1098+ }
1099+ }
1100+
1101+ if (findFlg2 == YES)
1102+ continue;
1103+ }
1104+
1105+ }
1106+
1107+
1108+ }
1109+ [self removeConnection:connector];
1110+}
1111+
1112+/*
1113+ * スター記事の取得
1114+ */
1115+-(void)pumpStarItemFeedRefresh:(Folder *)folder
1116+{
1117+
1118+ NSString * name = [[folder name] isEqualToString:[Database untitledFeedFolderName]] ? [folder feedURL] : [folder name];
1119+ ActivityItem * aItem = [[ActivityLog defaultLog] itemByName:name];
1120+ // Seed the activity log for this feed.
1121+ [aItem clearDetails];
1122+ [aItem setStatus:NSLocalizedString(@"Retrieving articles", nil)];
1123+
1124+ // Mark the folder as being refreshed. The updating status is not
1125+ // persistent so we set this directly on the folder rather than
1126+ // through the database.
1127+ [self setFolderUpdatingFlag:folder flag:YES];
1128+
1129+ // Additional detail for the log
1130+ [aItem appendDetail:[NSString stringWithFormat:NSLocalizedString(@"Connecting to %@", nil), [folder feedURL]]];
1131+
1132+ NSURL * url = [NSURL URLWithString:@"http://www.google.com"
1133+ @"/reader/atom/user/-/state/com.google/starred?n=10000"];
1134+
1135+ [self connRequest:url
1136+ :folder
1137+ :aItem
1138+ :@selector(getStarItemFeedCompleted:)];
1139+}
1140+
1141+-(void)getStarItemFeedCompleted:(AsyncConnection *)connector
1142+{
1143+ Folder * folder = (Folder *)[connector contextData];
1144+ int folderId = [folder itemId];
1145+ Database * db = [Database sharedDatabase];
1146+
1147+ [self setFolderUpdatingFlag:folder flag:NO];
1148+
1149+ if ([connector status] == MA_Connect_Stopped)
1150+ {
1151+ // Stopping the connection isn't an error, so clear any
1152+ // existing error flag.
1153+ [self setFolderErrorFlag:folder flag:NO];
1154+
1155+ // Set the last update date for this folder.
1156+ [db setFolderLastUpdate:folderId lastUpdate:[NSDate date]];
1157+
1158+ // If this folder also requires an image refresh, add that
1159+ if ([folder flags] & MA_FFlag_CheckForImage)
1160+ [self refreshFavIcon:folder];
1161+ }
1162+ else if ([connector status] == MA_Connect_URLIsGone)
1163+ {
1164+ // We got HTTP 410 which means the feed has been intentionally
1165+ // removed so unsubscribe the feed.
1166+ [db setFolderFlag:folderId flagToSet:MA_FFlag_Unsubscribed];
1167+ [[NSNotificationCenter defaultCenter] postNotificationName:@"MA_Notify_FoldersUpdated" object:[NSNumber numberWithInt:folderId]];
1168+ }
1169+ //saka 通信障害のルート
1170+ else if ([connector status] == MA_Connect_Failed)
1171+ {
1172+ // Mark the feed as failed
1173+ [self setFolderErrorFlag:folder flag:YES];
1174+ }
1175+ else if ([connector status] == MA_Connect_Succeeded)
1176+ {
1177+ NSData * receivedData = [connector receivedData];
1178+ Database * db = [Database sharedDatabase];
1179+
1180+ int newArticlesFromFeed = 0;
1181+ RichXMLParser * newFeed = [[RichXMLParser alloc] init];
1182+ if ([receivedData length] > 0)
1183+ {
1184+ // Create a new rich XML parser instance that will take care of
1185+ // parsing the XML data we just got.
1186+ if (newFeed == nil || ![newFeed parseRichXML:receivedData])
1187+ {
1188+ // Mark the feed as failed
1189+ [self setFolderErrorFlag:folder flag:YES];
1190+ [newFeed release];
1191+ return;
1192+ }
1193+
1194+ // Extract the latest title and description
1195+ NSString * feedTitle = [newFeed title];
1196+ NSString * feedDescription = [newFeed description];
1197+
1198+ // We'll be collecting articles into this array
1199+ NSMutableArray * articleArray = [NSMutableArray array];
1200+ NSMutableArray * articleGuidArray = [NSMutableArray array];
1201+
1202+ // Parse off items.
1203+
1204+ for (FeedItem * newsItem in [newFeed items])
1205+ {
1206+ NSDate * articleDate = [newsItem date];
1207+
1208+ //16桁のID部分のみを切り出す
1209+ NSMutableString * articleGuid = [NSMutableString stringWithFormat:[newsItem guid]];
1210+ [articleGuid replaceOccurrencesOfString:@"tag:google.com,2005:reader/item/"
1211+ withString:@""
1212+ options:NSLiteralSearch
1213+ range:NSMakeRange(0, [articleGuid length])];
1214+
1215+ //既存のレコードと重複させないよう、guidの先頭に"star:"を付与する。
1216+ NSString * starArticleGuid = [NSString stringWithFormat:@"%@%@",
1217+ MA_StarItem_String, articleGuid];
1218+
1219+ // Bad feeds! I'm talking to you, WordPress Trac.
1220+ NSUInteger articleIndex = [articleGuidArray indexOfObject:starArticleGuid];
1221+ if (articleIndex != NSNotFound)
1222+ {
1223+ if (articleDate == nil)
1224+ continue; // Skip this duplicate article
1225+
1226+ Article * existingArticle = [articleArray objectAtIndex:articleIndex];
1227+ if ([articleDate compare:[existingArticle date]] == NSOrderedDescending)
1228+ {
1229+ // This article is later, so use it instead
1230+ [articleArray removeObjectAtIndex:articleIndex];
1231+ [articleGuidArray removeObjectAtIndex:articleIndex];
1232+ }
1233+ else
1234+ continue; // Skip this duplicate article
1235+ }
1236+ [articleGuidArray addObject:starArticleGuid];
1237+
1238+ if (articleDate == nil)
1239+ articleDate = [NSDate date];
1240+
1241+ Article * article = [[Article alloc] initWithGuid:starArticleGuid];
1242+ [article setFolderId:folderId];
1243+ [article setAuthor:[newsItem author]];
1244+ [article setBody:[newsItem description]];
1245+ [article setTitle:[newsItem title]];
1246+ [article setLink:[newsItem link]];
1247+ [article setDate:articleDate];
1248+ [article setEnclosure:[newsItem enclosure]];
1249+ [article markRead:YES];
1250+ [article markFlagged:YES];
1251+ if ([[article enclosure] isNotEqualTo:@""])
1252+ {
1253+ [article setHasEnclosure:YES];
1254+ }
1255+ [articleArray addObject:article];
1256+ [article release];
1257+
1258+ //guidに対応するレコードがあれば、フラグをONにする。
1259+ [db updateStarItem:folderId :articleGuid];
1260+ }
1261+
1262+ // Here's where we add the articles to the database
1263+ if ([articleArray count] > 0u)
1264+ {
1265+ //サーバ側のスター付きアイテムに無いローカル側のアイテムは削除。
1266+ [db beginTransaction];
1267+ BOOL findFlag;
1268+ NSArray * localArticles = [folder articles];
1269+ for (Article * localArticle in localArticles)
1270+ {
1271+ findFlag = NO;
1272+ for (Article * serverArticle in articleArray)
1273+ {
1274+ if ([[localArticle guid] isEqualToString:[serverArticle guid]])
1275+ {
1276+ findFlag = YES;
1277+ break;
1278+ }
1279+ }
1280+ if (NO == findFlag)
1281+ {
1282+ //削除
1283+ [db markArticleFlagged:[folder itemId]
1284+ guid:[localArticle guid]
1285+ isFlagged:NO];
1286+ }
1287+ }
1288+
1289+ NSArray * guidHistory = [db guidHistoryForFolderId:folderId];
1290+
1291+ [folder clearCache];
1292+ // Should we wrap the entire loop or just individual article updates?
1293+ for (Article * article in articleArray)
1294+ {
1295+ //DBにぶち込む。
1296+ if ([db createArticle:folderId article:article guidHistory:guidHistory] && ([article status] == MA_MsgStatus_New))
1297+ ++newArticlesFromFeed;
1298+ }
1299+ [db commitTransaction];
1300+ } else {
1301+ //ローカル側のアイテムを全削除。
1302+ [db beginTransaction];
1303+ NSArray * localArticles = [folder articles];
1304+ for (Article * localArticle in localArticles)
1305+ {
1306+ [db markArticleFlagged:[folder itemId]
1307+ guid:[localArticle guid]
1308+ isFlagged:NO];
1309+ }
1310+ [db commitTransaction];
1311+ }
1312+
1313+ [db beginTransaction];
1314+
1315+ // A notify is only needed if we added any new articles.
1316+ if ([[folder name] hasPrefix:[Database untitledFeedFolderName]] && ![feedTitle isBlank])
1317+ {
1318+ // If there's an existing feed with this title, make ours unique
1319+ // BUGBUG: This duplicates logic in database.m so consider moving it there.
1320+ NSString * oldFeedTitle = feedTitle;
1321+ unsigned int index = 1;
1322+
1323+ while (([db folderFromName:feedTitle]) != nil)
1324+ feedTitle = [NSString stringWithFormat:@"%@ (%i)", oldFeedTitle, index++];
1325+
1326+ [db setFolderName:folderId newName:feedTitle];
1327+ }
1328+ if (feedDescription != nil)
1329+ [db setFolderDescription:folderId newDescription:feedDescription];
1330+
1331+ [db commitTransaction];
1332+
1333+ }
1334+
1335+ // Done with this connection
1336+ [newFeed release];
1337+ }
1338+ [self removeConnection:connector];
1339+}
1340+
10801341 -(void)dealloc
10811342 {
10821343 [super dealloc];
Show on old repository browser