feed.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import { Injectable } from "@angular/core";
  2. import { TwitterApiProvider } from "../twitter-api/twitter-api";
  3. import { P2pDatabaseGunProvider } from "../p2p-database-gun/p2p-database-gun";
  4. import { P2pStorageIpfsProvider } from "../p2p-storage-ipfs/p2p-storage-ipfs";
  5. @Injectable()
  6. export class FeedProvider {
  7. friends;
  8. constructor(
  9. private twitter: TwitterApiProvider,
  10. private gun: P2pDatabaseGunProvider,
  11. private ipfs: P2pStorageIpfsProvider
  12. ) {}
  13. public async loadUserTimeline(
  14. userId,
  15. oldestPublicTweet?,
  16. oldestPrivateTweet?
  17. ) {
  18. const maxId = oldestPublicTweet ? oldestPublicTweet["id_str"] : undefined;
  19. // Fetch tweets from Twitter
  20. let tweets = await this.twitter.fetchUserTimeline(userId, maxId);
  21. tweets = tweets.filter(tweet => tweet.id_str != maxId);
  22. // Determine start and end of time interval to look for private tweets
  23. const intervalStart: Date = oldestPrivateTweet
  24. ? new Date(oldestPrivateTweet["created_at"])
  25. : new Date();
  26. const intervalEnd: Date = this.getOldestTweetTimestamp(tweets);
  27. // Fetch private tweet hashs from P2P DB for corresponding interval
  28. const privateTweetHashs: string[] = await this.gun.fetchPrivateTweetHashsForUserInInterval(
  29. userId,
  30. intervalStart,
  31. intervalEnd
  32. );
  33. if (privateTweetHashs.length) {
  34. const privateTweets = await this.fetchPrivateTweets(privateTweetHashs);
  35. // Combine and sort tweets
  36. return tweets
  37. .concat(privateTweets)
  38. .sort((a, b) => this.sortByDateAsc(a, b));
  39. } else {
  40. return tweets;
  41. }
  42. }
  43. public async loadHomeTimeline(
  44. userId,
  45. oldestPublicTweet?,
  46. oldestPrivateTweet?
  47. ) {
  48. // Fetch tweets from Twitter
  49. const maxId = oldestPublicTweet ? oldestPublicTweet["id_str"] : undefined;
  50. let tweets = await this.twitter.fetchHomeFeed(maxId);
  51. tweets = tweets.filter(tweet => tweet.id_str != maxId);
  52. // Determine start and end of time interval to look for private tweets
  53. const intervalStart: Date = oldestPrivateTweet
  54. ? new Date(oldestPrivateTweet["created_at"])
  55. : new Date();
  56. const intervalEnd: Date = this.getOldestTweetTimestamp(tweets);
  57. // Fetch user's friends
  58. const friends = await this.getCachedFriends(userId);
  59. let privateTweetHashs = [];
  60. friends.forEach(async friend => {
  61. privateTweetHashs = privateTweetHashs.concat(
  62. await this.gun.fetchPrivateTweetHashsForUserInInterval(
  63. friend.id_str,
  64. intervalStart,
  65. intervalEnd
  66. )
  67. );
  68. });
  69. // Add users private tweets
  70. privateTweetHashs = privateTweetHashs.concat(
  71. await this.gun.fetchPrivateTweetHashsForUserInInterval(
  72. userId,
  73. intervalStart,
  74. intervalEnd
  75. )
  76. );
  77. if (privateTweetHashs.length) {
  78. const privateTweets = await this.fetchPrivateTweets(privateTweetHashs);
  79. // Combine and sort tweets
  80. return tweets
  81. .concat(privateTweets)
  82. .sort((a, b) => this.sortByDateAsc(a, b));
  83. } else {
  84. return tweets;
  85. }
  86. }
  87. private async fetchPrivateTweets(privateTweetHashs) {
  88. // Load private tweets from P2P storage
  89. const privateTweets = await this.ipfs.fetchTweets(privateTweetHashs);
  90. // Add user object to private tweets
  91. return await Promise.all(
  92. privateTweets.map(async tweet => await this.addUserToTweet(tweet))
  93. );
  94. }
  95. private async addUserToTweet(tweet) {
  96. tweet.user = await this.twitter.fetchUser(tweet.user_id);
  97. return tweet;
  98. }
  99. private getOldestTweetTimestamp(tweets): Date {
  100. if (tweets.length < 15) {
  101. // End of timeline is reached - load all private tweets
  102. return new Date("2018-04-01T00:00:00");
  103. } else {
  104. const lastTweetTimestamp = tweets[tweets.length - 1].created_at;
  105. return new Date(lastTweetTimestamp);
  106. }
  107. }
  108. private sortByDateAsc(a, b) {
  109. const dateA = new Date(a.created_at);
  110. const dateB = new Date(b.created_at);
  111. if (dateA > dateB) {
  112. return -1;
  113. } else if (dateA < dateB) {
  114. return 1;
  115. } else {
  116. return 0;
  117. }
  118. }
  119. private async getCachedFriends(userId) {
  120. // Cache friends for 15 minutes to avoid unnecessary API calls
  121. if (!this.friends || (Date.now() - this.friends.lastUpdate) / 900000 > 15) {
  122. this.friends = {
  123. friendList: await this.twitter.fetchFriends(userId),
  124. lastUpdate: Date.now()
  125. };
  126. }
  127. return this.friends.friendList;
  128. }
  129. }