import { HttpClient } from "@angular/common/http"; import { Injectable } from "@angular/core"; import { TwitterApiProvider } from "../twitter-api/twitter-api"; import { P2pDatabaseGunProvider } from "../p2p-database-gun/p2p-database-gun"; import { P2pStorageIpfsProvider } from "../p2p-storage-ipfs/p2p-storage-ipfs"; @Injectable() export class FeedProvider { constructor( private http: HttpClient, private twitter: TwitterApiProvider, private gun: P2pDatabaseGunProvider, private ipfs: P2pStorageIpfsProvider ) {} public async loadUserTimeline( userId, oldestPublicTweet?, oldestPrivateTweet? ) { const maxId = oldestPublicTweet ? oldestPublicTweet["id_str"] : undefined; // Fetch tweets from Twitter let tweets = await this.twitter.fetchUserTimeline(userId, maxId); tweets = tweets.filter(tweet => tweet.id_str != maxId); // Determine start and end of time interval to look for private tweets const intervalStart: Date = oldestPrivateTweet ? new Date(oldestPrivateTweet["created_at"]) : new Date(); const intervalEnd: Date = this.getOldestTweetTimestamp(tweets); // Fetch private tweet hashs from P2P DB for corresponding interval const privateTweetHashs: string[] = await this.gun.fetchPrivateTweetHashsForUserInInterval( userId, intervalStart, intervalEnd ); if (privateTweetHashs.length) { // Load private tweets from P2P storage let privateTweets = await this.ipfs.fetchTweets(privateTweetHashs); // Add user object to private tweets privateTweets = await Promise.all( privateTweets.map(async tweet => await this.addUserToTweet(tweet)) ); // Combine and sort tweets return tweets .concat(privateTweets) .sort((a, b) => this.sortByDateAsc(a, b)); } else { return tweets; } } public async loadHomeTimeline( userId, oldestPublicTweet?, oldestPrivateTweet? ) { // Fetch tweets from Twitter const maxId = oldestPublicTweet ? oldestPublicTweet["id_str"] : undefined; let tweets = await this.twitter.fetchHomeFeed(maxId); tweets = tweets.filter(tweet => tweet.id_str != maxId); // Determine start and end of time interval to look for private tweets const intervalStart: Date = oldestPrivateTweet ? new Date(oldestPrivateTweet["created_at"]) : new Date(); const intervalEnd: Date = this.getOldestTweetTimestamp(tweets); // Fetch user's friends const friends = await this.twitter.fetchFriends(userId); let privateTweetHashs = []; friends.forEach(async friend => { privateTweetHashs = privateTweetHashs.concat( await this.gun.fetchPrivateTweetHashsForUserInInterval( friend.id_str, intervalStart, intervalEnd ) ); }); // Add users private tweets privateTweetHashs = privateTweetHashs.concat( await this.gun.fetchPrivateTweetHashsForUserInInterval( userId, intervalStart, intervalEnd ) ); if (privateTweetHashs.length) { // Load private tweets from P2P storage let privateTweets = await this.ipfs.fetchTweets(privateTweetHashs); // Add user object to private tweets privateTweets = await Promise.all( privateTweets.map(async tweet => await this.addUserToTweet(tweet)) ); // Combine and sort tweets return tweets .concat(privateTweets) .sort((a, b) => this.sortByDateAsc(a, b)); } else { return tweets; } } private async addUserToTweet(tweet) { tweet.user = await this.twitter.fetchUser(tweet.user_id); return tweet; } private getOldestTweetTimestamp(tweets): Date { if (tweets.length < 15) { // End of timeline is reached - load all private tweets return new Date("2018-04-01T00:00:00"); } else { const lastTweetTimestamp = tweets[tweets.length - 1].created_at; return new Date(lastTweetTimestamp); } } private sortByDateAsc(a, b) { const dateA = new Date(a.created_at); const dateB = new Date(b.created_at); if (dateA > dateB) { return -1; } else if (dateA < dateB) { return 1; } else { return 0; } } }