Skip to content

Commit

Permalink
Merge b7b8054 into 7abc694
Browse files Browse the repository at this point in the history
  • Loading branch information
yl-coder committed Apr 7, 2016
2 parents 7abc694 + b7b8054 commit d770eae
Show file tree
Hide file tree
Showing 14 changed files with 396 additions and 30 deletions.
19 changes: 18 additions & 1 deletion src/main/java/backend/Logic.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public void refresh() {
.collect(Collectors.toList()))
.thenRun(this::refreshUI)
.thenCompose(n -> getRateLimitResetTime())
.thenApply(this::updateSyncRefreshRate)
.thenApply(this::updateRemainingRate)
.exceptionally(Futures::log);
}
Expand Down Expand Up @@ -163,6 +164,7 @@ private CompletableFuture<Boolean> openRepository(String repoId, Optional<Filter
.thenRun(this::refreshUI)
.thenRun(() -> notifyRepoOpened(panel))
.thenCompose(n -> getRateLimitResetTime())
.thenApply(this::updateSyncRefreshRate)
.thenApply(this::updateRemainingRate)
.thenApply(rateLimits -> true)
.exceptionally(withResult(false));
Expand Down Expand Up @@ -231,8 +233,23 @@ public void removeUnusedModels(Set<String> reposInUse) {
.forEach(models::removeRepoModelById);
}

/**
* Updates events related to remaining rate.
* @param rateLimits The api rate limits for updating of the remaining rate.
* @return Return rateLimits instance
*/
public ImmutablePair<Integer, Long> updateRemainingRate(ImmutablePair<Integer, Long> rateLimits) {
uiManager.updateRateLimits(rateLimits);
uiManager.updateRemainingRate(rateLimits);
return rateLimits;
}

/**
* Updates the sync refresh rate of updating on the current data store.
* @param rateLimits The api rate limits for calculation of the refresh rate.
* @return Return rateLimits instance
*/
public ImmutablePair<Integer, Long> updateSyncRefreshRate(ImmutablePair<Integer, Long> rateLimits) {
uiManager.updateSyncRefreshRate(rateLimits);
return rateLimits;
}

Expand Down
11 changes: 8 additions & 3 deletions src/main/java/backend/UIManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
import ui.UI;
import ui.issuepanel.FilterPanel;
import util.events.ModelUpdatedEvent;
import util.events.UpdateRateLimitsEvent;
import util.events.UpdateRemainingRateEvent;
import util.events.UpdateSyncRefreshRateEvent;

import java.util.List;
import java.util.Map;
Expand All @@ -26,8 +27,12 @@ public void update(Map<FilterExpression, List<GuiElement>> elementsToShow,
Platform.runLater(() -> ui.triggerEvent(new ModelUpdatedEvent(elementsToShow, users)));
}

public void updateRateLimits(ImmutablePair<Integer, Long> rateLimits) {
ui.triggerEvent(new UpdateRateLimitsEvent(rateLimits.left, rateLimits.right));
public void updateRemainingRate(ImmutablePair<Integer, Long> rateLimits) {
ui.triggerEvent(new UpdateRemainingRateEvent(rateLimits.left, rateLimits.right));
}

public void updateSyncRefreshRate(ImmutablePair<Integer, Long> rateLimits) {
ui.triggerEvent(new UpdateSyncRefreshRateEvent(rateLimits.left, rateLimits.right));
}

/**
Expand Down
59 changes: 51 additions & 8 deletions src/main/java/ui/GUIController.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,21 @@ public class GUIController {
private final PanelControl panelControl;
private final UI ui;
private final Label apiBox;

/**
* To store the previous amount of the available remaining API request.
*/
private int previousRemainingApiRequests = 0;

/**
* To store the previous amount of api calls used.
*/
private int lastNumberOfApiCallsUsed = 0;

private String defaultRepoId;

long refreshTimeInMins = 1;

public GUIController(UI ui, PanelControl panelControl, Label apiBox) {
this.ui = ui;
this.panelControl = panelControl;
Expand All @@ -41,14 +54,15 @@ public GUIController(UI ui, PanelControl panelControl, Label apiBox) {

public final void registerEvents() {
UI.events.registerEvent((ModelUpdatedEventHandler) this::modelUpdated);
UI.events.registerEvent((UpdateRateLimitsEventHandler) this::updateAPIBox);
UI.events.registerEvent((UpdateRemainingRateEventHandler) this::updateRemainingRateEvent);
UI.events.registerEvent((UpdateSyncRefreshRateEventHandler) this::updateSyncRefreshRate);
UI.events.registerEvent((ShowErrorDialogEventHandler) this::showErrorDialog);
UI.events.registerEvent((PrimaryRepoChangedEventHandler) this::setDefaultRepo);
}

/**
* The handler method for a ModelUpdatedEvent.
* <p>
* <p/>
* It processes each panel in the current GUI, and checks the ModelUpdatedEvent for issues to be displayed
* that match the current panel's filter expression:
* - If not, the panel does not change its appearance.
Expand All @@ -72,7 +86,7 @@ private void modelUpdated(ModelUpdatedEvent e) {
/**
* Handler method for an applyFilterExpression call from an FilterPanel, which is in turn triggered by
* the user pressing ENTER while the cursor is on the FilterPanel's filterTextField.
* <p>
* <p/>
* Triggers a processAndRefresh call in Logic with only the given panel's filterExpression. Contrast this
* with refreshAllPanels in Logic, triggers processAndRefresh with all FilterExpressions from the GUI.
*
Expand Down Expand Up @@ -102,11 +116,40 @@ public List<FilterPanel> getAllPanels() {
.collect(Collectors.toList());
}

private void updateAPIBox(UpdateRateLimitsEvent e) {
Platform.runLater(() -> apiBox.setText(String.format("%s/%s",
e.remainingRequests,
Utility.minutesFromNow(e.nextRefreshInMillisecs)))
);
private void updateRemainingRateEvent(UpdateRateLimitsEvent e) {
updateAPIBox(e.remainingRequests, e.nextRefreshInMillisecs);
}

/**
* Updates the sync refresh rate of updating on the current data store.
* @param e The current api rate limits for calculation of the refresh rate.
*/
private void updateSyncRefreshRate(UpdateRateLimitsEvent e) {
lastNumberOfApiCallsUsed = computePreviousRemainingApiRequests(e);
refreshTimeInMins = ui.timerManager.computeTickerTimerPeriod(e.remainingRequests,
Utility.minutesFromNow(e.nextRefreshInMillisecs), lastNumberOfApiCallsUsed);
ui.timerManager.changeTickingTimerPeriodInMins((int) refreshTimeInMins);
}

private int computePreviousRemainingApiRequests(UpdateRateLimitsEvent e) {
int difference = previousRemainingApiRequests - e.remainingRequests;
previousRemainingApiRequests = e.remainingRequests;

if (difference >= 0) {
return difference;
}
return lastNumberOfApiCallsUsed;
}

/**
* Updates the GUI APIBox to indicate the no of remaining api request, time until next api renewal and
* the current sync refresh rate.
* @param remainingRequests The number of remaining api request.
* @param nextRefreshInMillisecs The next refresh time in epoch format.
*/
private void updateAPIBox(int remainingRequests, long nextRefreshInMillisecs) {
Platform.runLater(() -> apiBox.setText(String.format("%s/%s[x%d]", remainingRequests,
Utility.minutesFromNow(nextRefreshInMillisecs), (int) Math.ceil(refreshTimeInMins))));
}

private void showErrorDialog(ShowErrorDialogEvent e) {
Expand Down
21 changes: 13 additions & 8 deletions src/main/java/ui/UI.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
import java.util.concurrent.TimeUnit;

import static ui.components.KeyboardShortcuts.SHOW_ISSUE_PICKER;
import static ui.components.KeyboardShortcuts.SHOW_REPO_PICKER;


public class UI extends Application implements EventDispatcher {

Expand All @@ -57,11 +57,10 @@ public class UI extends Application implements EventDispatcher {
public static final int VERSION_PATCH = 0;

private static final Logger logger = LogManager.getLogger(UI.class.getName());
public static final int APIQUOTA_BUFFER = 200;
private static HWND mainWindowHandle;
private final GlobalHotkey globalHotkey = new GlobalHotkey(this);

private static final int REFRESH_PERIOD = 60;

/**
* Minimum Java Version Required by HT.
*
Expand Down Expand Up @@ -93,10 +92,10 @@ public class UI extends Application implements EventDispatcher {
public static StatusUI status;
public static EventDispatcher events;
public EventBus eventBus;
private TickingTimer refreshTimer;
public GUIController guiController;
private NotificationController notificationController;
public UndoController undoController;
public TickingTimerManager timerManager;


// Main UI elements
Expand Down Expand Up @@ -240,11 +239,17 @@ private void initPreApplicationState() {
private void initApplicationState() {
// In the future, when more arguments are passed to logic,
// we can pass them in the form of an array.

logic = new Logic(uiManager, prefs, Optional.empty(), Optional.empty());

// TODO clear cache if necessary
refreshTimer = new TickingTimer("Refresh Timer", REFRESH_PERIOD,
status::updateTimeToRefresh, logic::refresh, TimeUnit.SECONDS);
refreshTimer.start();

TickingTimer refreshTimer = new TickingTimer("Refresh Timer", TickingTimerManager.DEFAULT_REFRESH_PERIOD_IN_SEC,
status::updateTimeToRefresh, logic::refresh, TimeUnit.SECONDS);

timerManager = new TickingTimerManager(refreshTimer);
timerManager.startTimer();

undoController = new UndoController(notificationController);
}

Expand Down Expand Up @@ -350,7 +355,7 @@ private void setupMainStage(Scene scene) {
if (shouldRefresh) {
logger.info("Browser view has changed; refreshing");
logic.refresh();
refreshTimer.restart();
timerManager.restartTimer();
}
}
});
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/util/TickingTimer.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class TickingTimer {
private final String name;

// The period after which the timer times out.
private final int period;
private int period;

// onTick will not pause the timer when run, so it should not be a long-running task.
// Will run before onTimeout.
Expand Down Expand Up @@ -158,4 +158,13 @@ public boolean isStarted() {
return started;
}

/**
* Changes the timer's period and restart the timer based on the new period.
* @param period : the amount of time before triggering the timer.
*/
public synchronized void changePeriodInSecs(int period){
this.period = period;
this.time = period;
}

}
95 changes: 95 additions & 0 deletions src/main/java/util/TickingTimerManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package util;

/**
* This class manages the TickingTimer instance used for refreshing. It computes the refresh rate period and change
* the refresh period.
*/
public class TickingTimerManager {

/**
* To allow some additional time until next refresh.
*/
public static final int BUFFER_TIME = 1;

/**
* The amount that is set aside for manual refresh or creation of issues, labels and milestones.
*/
public static final int APIQUOTA_BUFFER = 200;

public static final int NO_OF_REFRESH_THAT_REQUIRES_MORE_TIME = 1;
public static final int DEFAULT_REFRESH_PERIOD_IN_SEC = 60;

private final TickingTimer timer;

public TickingTimerManager(TickingTimer timer) {
this.timer = timer;
}

public void startTimer() {
timer.start();
}

public void restartTimer() {
timer.restart();
}

/**
* Computes the TickerTimer period that are used for refreshing the issues periodically.
* @param apiQuota : The remaining allowed api request until the next api request allowance renewal.
* @param remainingTime : The remaining time left until the next api request allowance renewal.
* @param lastApiCallsUsed : The amount of api used in the last api pull.
*/
public long computeTickerTimerPeriod(int apiQuota, long remainingTime, int lastApiCallsUsed) {

assert apiQuota >= 0 && remainingTime >= 0 && lastApiCallsUsed >= 0;

long refreshTimeInMin;

if (isDuringAppInitOrRemainingTimeIsZero(apiQuota, remainingTime, lastApiCallsUsed)) {
refreshTimeInMin = Utility.secsToMins(DEFAULT_REFRESH_PERIOD_IN_SEC);
return refreshTimeInMin;
}

if (isQuotaInsufficient(apiQuota, lastApiCallsUsed)) {
refreshTimeInMin = remainingTime + BUFFER_TIME;
return refreshTimeInMin;
}

if (isQuotaSufficient(apiQuota, lastApiCallsUsed)) {
double noOfRefreshAllowed = computeNoOfRefreshAllowed(apiQuota, lastApiCallsUsed);
refreshTimeInMin = (long) Math.ceil(remainingTime / noOfRefreshAllowed);

if (noOfRefreshAllowed == NO_OF_REFRESH_THAT_REQUIRES_MORE_TIME) {
refreshTimeInMin = refreshTimeInMin + BUFFER_TIME;
}
return refreshTimeInMin;
}

return Utility.secsToMins(DEFAULT_REFRESH_PERIOD_IN_SEC);
}

private double computeNoOfRefreshAllowed(int apiQuota, int lastApiCallsUsed) {
return Math.floor((apiQuota - APIQUOTA_BUFFER) / (double) lastApiCallsUsed);
}

/**
* Changes the timer refresh period.
* @param period
*/
public void changeTickingTimerPeriodInMins(int period) {
timer.changePeriodInSecs((int) Utility.minsToSecs(period));
}

private boolean isQuotaSufficient(int apiQuota, int lastApiCallsUsed) {
return apiQuota - APIQUOTA_BUFFER >= lastApiCallsUsed;
}

private boolean isQuotaInsufficient(int apiQuota, int lastApiCallsUsed) {
return apiQuota == 0 && lastApiCallsUsed == 0 || apiQuota <= APIQUOTA_BUFFER
|| apiQuota - APIQUOTA_BUFFER > 0 && apiQuota - APIQUOTA_BUFFER < lastApiCallsUsed;
}

private boolean isDuringAppInitOrRemainingTimeIsZero(int apiQuota, long remainingTime, int lastApiCallsUsed) {
return apiQuota != 0 && lastApiCallsUsed == 0 || remainingTime == 0;
}
}
8 changes: 8 additions & 0 deletions src/main/java/util/Utility.java
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,14 @@ public static long millisecToMinutes(long millisecDuration) {
return millisecDuration / 1000 / 60;
}

public static long minsToSecs(long minsDuration) {
return minsDuration * 60;
}

public static long secsToMins(long secsDuration) {
return secsDuration / 60;
}

public static long minutesFromNow(long targetTime) {
return millisecToMinutes(targetTime - new Date().getTime());
}
Expand Down
9 changes: 0 additions & 9 deletions src/main/java/util/events/UpdateRateLimitsEventHandler.java

This file was deleted.

12 changes: 12 additions & 0 deletions src/main/java/util/events/UpdateRemainingRateEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package util.events;

/**
* An event to call tasks related to the api remaining rate.
*/
public class UpdateRemainingRateEvent extends UpdateRateLimitsEvent{

public UpdateRemainingRateEvent(int remainingRequests, long nextRefreshInMillisecs) {
super(remainingRequests, nextRefreshInMillisecs);
}

}
12 changes: 12 additions & 0 deletions src/main/java/util/events/UpdateRemainingRateEventHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package util.events;

import com.google.common.eventbus.Subscribe;

/**
* This is an EventHandler to handle the UpdateRemainingRateEvent event.
*/
@FunctionalInterface
public interface UpdateRemainingRateEventHandler extends EventHandler {
@Subscribe
void handle(UpdateRemainingRateEvent e);
}
Loading

0 comments on commit d770eae

Please sign in to comment.