package myfeed.feed;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.hateoas.Resource;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import rx.Observable;
import rx.Single;
/**
* @author Spencer Gibb
*/
@RestController
@MessageEndpoint
@Slf4j
public class FeedItemInitializer {
private final FeedItemRepository repo;
private final UserService userService;
private final RandomText randomText;
private final Random random = new Random();
@Value("${myfeed.feed.initializer.maxItems:0}")
int minItems = 0;
@Value("${myfeed.feed.initializer.maxItems:10}")
int maxItems = 10;
@Value("${myfeed.feed.initializer.minWords:5}")
int minWords = 5;
@Value("${myfeed.feed.initializer.maxWords:20}")
int maxWords = 20;
@Autowired
public FeedItemInitializer(FeedItemRepository repo, UserService userService, RandomText randomText) {
this.repo = repo;
this.userService = userService;
this.randomText = randomText;
}
@RequestMapping("/init/all")
public Single<Map<String, Collection<FeedItem>>> initAll() {
return userService.getUsers()
.map(Resource::getContent)
.map(User::getUsername)
.flatMap(this::initUser)
.toMultimap(ufi -> ufi.username, ufi -> ufi.feedItem).toSingle();
}
@RequestMapping("/init")
public Single<List<FeedItem>> init(@RequestParam(value = "user") String username) {
return initUser(username)
.map(UserFeedItem::getFeedItem)
.toList().toSingle();
}
Observable<UserFeedItem> initUser(String username) {
Single<String> userid = userService.findId(username);
return initUser(username, userid);
}
Observable<UserFeedItem> initUser(String username, Single<String> userid) {
int numItems = getNumItems(minItems, maxItems);
return Observable.range(0, numItems)
.map(i -> numItems - i)
.flatMap(i -> {
Single<String> text = Single.just(randomText.getText(getNumItems(minWords, maxWords)));
LocalDateTime dateTime = LocalDateTime.now().minusDays(i);
Single<Date> created = Single.just(Date.from(dateTime.toInstant(ZoneOffset.UTC)));
Single<String> feedUsername = getRandomUsername(username);
Single<FeedItem> feedItem = Single.zip(userid, feedUsername, text, created, FeedItem::new);
return Single.zip(Single.just(username), feedItem, UserFeedItem::new).toObservable();
})
.map(userFeedItem -> {
FeedItem saved = repo.save(userFeedItem.feedItem);
userFeedItem.feedItem = saved;
return userFeedItem;
});
}
@ServiceActivator(inputChannel = FeedBinder.USER_INITIALIZED)
public void handleUserInited(User user) {
this.initUser(user.getUsername(), Single.just(user.getUserId()))
.forEach(feedItem -> log.info("Initialized user {} with feed item {}", user, feedItem));
}
@Data
@AllArgsConstructor
class UserFeedItem {
String username;
FeedItem feedItem;
}
private int getNumItems(int min, int bound) {
int numItems = 0;
while (numItems <= min) {
numItems = random.nextInt(bound);
}
return numItems;
}
Single<String> getRandomUsername(String defaultUsername) {
List<String> usernames = userService.getUsers()
.map(Resource::getContent)
.map(User::getUsername)
.toList().toBlocking().first();
if (usernames.isEmpty()) {
return Single.just(defaultUsername);
}
return Single.just(usernames.get(random.nextInt(usernames.size())));
}
}