Skip to content

Commit

Permalink
Merge pull request #694 from Kyusung4698/develop
Browse files Browse the repository at this point in the history
0.6.27
  • Loading branch information
Kyusung4698 authored May 8, 2020
2 parents ba5e001 + 08d5f5d commit c4c297c
Show file tree
Hide file tree
Showing 8 changed files with 569 additions and 478 deletions.
729 changes: 370 additions & 359 deletions CHANGELOG.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
![GitHub Release Date](https://img.shields.io/github/release-date/Kyusung4698/PoE-Overlay)
<a href="https://www.patreon.com/bePatron?u=30666721"><img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patron" width="85px" height="20px"></a>

# PoE Overlay 0.6.26
# PoE Overlay 0.6.27

An Overlay for Path of Exile. The ***core aspect*** is to blend in with the game. Built with Electron and Angular.

Expand Down Expand Up @@ -74,11 +74,11 @@ These instructions will set you up to run and enjoy the overlay.
#### Installing

1. Head over to [Releases](https://github.com/Kyusung4698/PoE-Overlay/releases) and download one of the following files
1. `poe-overlay-Setup-0.6.26.exe` to install locally. This supports auto update/ auto launch.
2. `poe-overlay-0.6.26.exe` portable version. This does not support auto update/ auto launch.
1. `poe-overlay-Setup-0.6.27.exe` to install locally. This supports auto update/ auto launch.
2. `poe-overlay-0.6.27.exe` portable version. This does not support auto update/ auto launch.
2. Run either of your downloaded file
3. Start Path of Exile
4. Wait until you can see `PoE Overlay 0.6.26` in the bottom left corner
4. Wait until you can see `PoE Overlay 0.6.27` in the bottom left corner
5. Hit `f7` and set `Language` and `League` to meet your game settings

#### Shortcuts
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "poe-overlay",
"version": "0.6.26",
"version": "0.6.27",
"private": true,
"description": "A Overlay for Path of Exile. Built with Electron and Angular.",
"main": "main.js",
Expand Down
2 changes: 2 additions & 0 deletions src/app/data/poe/service/trade-http.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ export class TradeHttpService {
return throwError(response);
}
return this.browser.retrieve(url).pipe(delay(RETRY_DELAY));
case 429:
return throwError(response);
default:
return of(response).pipe(delay(RETRY_DELAY));
}
Expand Down
196 changes: 131 additions & 65 deletions src/app/data/poe/service/trade-rate-limit.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ const HEADER_RULE_SEPARATOR = `,`
const HEADER_RULE_VALUE_SEPARATOR = `:`
const HEADER_RULE_STATE = `state`
const HEADER_RULES = `x-rate-limit-rules`;
const THROTTLE_RETRY_DELAY = 1000;

const RULE_FRESH_DURATION = 1000 * 10;

const WAITING_RETRY_DELAY = 1000;
const WAITING_RETRY_COUNT = 10;

interface TradeRateLimitRule {
count: number;
Expand All @@ -53,6 +57,14 @@ interface TradeRateLimitRequest {
interface TradeRateLimit {
requests: TradeRateLimitRequest[];
rules: TradeRateLimitRule[];
update: number;
}

enum TradeRateThrottle {
None = 1,
Stale = 2,
Reached = 3,
Limited = 4
}

@Injectable({
Expand All @@ -66,52 +78,76 @@ export class TradeRateLimitService {
public throttle<TResult>(resource: string, getRequest: () => Observable<HttpResponse<TResult>>): Observable<TResult> {
return of(null).pipe(
flatMap(() => {
if (this.shouldThrottle(resource)) {
return throwError('throttle');
const reason = this.shouldThrottle(resource);
switch (reason) {
case TradeRateThrottle.Limited:
return throwError('limited');
case TradeRateThrottle.Reached:
case TradeRateThrottle.Stale:
return throwError('waiting');
default:
const request = this.createRequest(resource);
return getRequest().pipe(
map(response => {
request.finished = Date.now();
this.updateRules(resource, response);
this.filterRequests(resource);
return response.body
}),
catchError(response => {
request.finished = Date.now();
if (response.status === 429) {
this.updateRules(resource, response);
}
this.filterRequests(resource);
return throwError(response);
})
);
}
const request = this.createRequest(resource);
return getRequest().pipe(
map(response => {
request.finished = Date.now();
this.updateRules(resource, response);
this.updateRequests(resource);
return response.body
}),
catchError(response => {
request.finished = Date.now();
if (response.status === 429) {
this.updateRules(resource, response);
}
this.updateRequests(resource);
return throwError(response);
})
);
}),
retryWhen(errors => errors.pipe(
flatMap(error => {
if (error === 'throttle') {
return of(error).pipe(delay(THROTTLE_RETRY_DELAY));
flatMap((error, count) => {
if (error === 'limited') {
return throwError({
status: 429
});
} else if (error === 'waiting') {
if (count >= WAITING_RETRY_COUNT) {
return throwError({
status: 429
});
}
return of(error).pipe(delay(WAITING_RETRY_DELAY));
}
return throwError(error);
})
))
);
}

private shouldThrottle(resource: string): boolean {
const { rules, requests } = this.getLimit(resource);
if (!rules) {
// only allow 1 request until rules are filled
return requests.some(request => !request.finished);
private shouldThrottle(resource: string): TradeRateThrottle {
const { rules, requests, update } = this.getLimit(resource);

const inflight = requests.some(request => !request.finished);
if (!inflight) {
return TradeRateThrottle.None;
}

// only allow 1 request until
// > rules are filled
// > rules are fresh again
const now = Date.now();
return rules.some(rule => {
// throttle while limited is greater than now
if (rule.limited && rule.limited > now) {
return true;
}
if (!rules || (now - update) > RULE_FRESH_DURATION) {
return TradeRateThrottle.Stale;
}

// only allow a new request if no rule is limited
const limited = rules.some(rule => rule.limited && rule.limited > now);
if (limited) {
return TradeRateThrottle.Limited;
}

const reached = rules.some(rule => {
// all requests which were made in the period count
const limit = now - rule.period * 1000;
const limiting = requests.filter(request => {
Expand All @@ -122,6 +158,10 @@ export class TradeRateLimitService {
});
return limiting.length >= rule.count;
});
if (reached) {
return TradeRateThrottle.Reached;
}
return TradeRateThrottle.None;
}

private createRequest(resource: string): TradeRateLimitRequest {
Expand All @@ -131,7 +171,7 @@ export class TradeRateLimitService {
return request;
}

private updateRequests(resource: string): void {
private filterRequests(resource: string): void {
const limit = this.getLimit(resource);
const now = Date.now();
limit.requests = limit.requests.filter(request => {
Expand All @@ -146,47 +186,73 @@ export class TradeRateLimitService {
}

private updateRules(resource: string, response: HttpResponse<any>): void {
const limit = this.getLimit(resource);
const current = this.getLimit(resource);

const rules = response?.headers?.get(HEADER_RULES);
if (rules) {
limit.rules = rules.toLowerCase()
.split(HEADER_RULE_SEPARATOR)
.map(name => name.trim())
.map(name => {
const limits = response.headers.get(`${HEADER_RULE}-${name}`).split(HEADER_RULE_SEPARATOR);
const states = response.headers.get(`${HEADER_RULE}-${name}-${HEADER_RULE_STATE}`).split(HEADER_RULE_SEPARATOR);
if (limits.length === states.length) {
return limits.map((_, index) => {
const [count, period, timeoff] = limits[index].split(HEADER_RULE_VALUE_SEPARATOR).map(x => +x);
const [currentCount, , currentTimeoff] = states[index].split(HEADER_RULE_VALUE_SEPARATOR).map(x => +x);
let limited = currentTimeoff;
if (limited <= 0 && currentCount > count) {
limited = timeoff;
if (!rules) {
current.rules = undefined;
return;
}

const now = Date.now();

current.update = now;
current.rules = rules.toLowerCase()
.split(HEADER_RULE_SEPARATOR)
.map(name => name.trim())
.map(name => {
const limits = response.headers.get(`${HEADER_RULE}-${name}`).split(HEADER_RULE_SEPARATOR);
const states = response.headers.get(`${HEADER_RULE}-${name}-${HEADER_RULE_STATE}`).split(HEADER_RULE_SEPARATOR);
if (limits.length !== states.length) {
return undefined;
}

return limits.map((_, index) => {
const [count, period, timeoff] = limits[index].split(HEADER_RULE_VALUE_SEPARATOR).map(x => +x);
const [currentCount, , currentTimeoff] = states[index].split(HEADER_RULE_VALUE_SEPARATOR).map(x => +x);

let limited = currentTimeoff;
if (limited <= 0 && currentCount > count) {
limited = timeoff;
}

const rule: TradeRateLimitRule = {
count, period,
limited: limited > 0
? now + limited * 1000
: undefined
};

if (!rule.limited) {
const limit = now - rule.period * 1000;
const limiting = current.requests.filter(request => {
if (!request.finished) {
return true;
}
const rule: TradeRateLimitRule = {
count, period,
limited: limited > 0
? Date.now() + limited * 1000
: undefined
};
return rule;
return request.finished >= limit;
});
} else {
return undefined;

let missing = currentCount - limiting.length;
while (missing > 0) {
current.requests.push({
finished: now,
});
--missing;
}
}
})
.reduce((a, b) => a.concat(b), [])
.filter(rule => rule !== undefined);
} else {
limit.rules = undefined;
}
return rule;
});
})
.reduce((a, b) => a.concat(b), [])
.filter(rule => rule !== undefined);
}

private getLimit(resource: string): TradeRateLimit {
if (!this.limits[resource]) {
this.limits[resource] = {
requests: [],
rules: undefined
rules: undefined,
update: undefined
};
}
return this.limits[resource];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,12 @@ export class EvaluateSearchComponent implements OnInit {
public ngOnInit(): void {
this.graph = this.settings.evaluateResultView === EvaluateResultView.Graph;
if (this.settings.evaluateQueryInitialSearch) {
this.search(this.queryItem);
this.initSearch();
}
this.registerSearchOnChange();
}

public onSearchClick(): void {
this.search(this.queryItem);
this.initSearch();
}

public onCurrencyClick(event: MouseEvent): void {
Expand Down Expand Up @@ -105,6 +104,11 @@ export class EvaluateSearchComponent implements OnInit {
this.evaluateResult.next({ amount, currency });
}

private initSearch(): void {
this.search(this.queryItem);
this.registerSearchOnChange();
}

private registerSearchOnChange(): void {
let subscription: Subscription;
this.queryItemChange.pipe(
Expand Down
Loading

0 comments on commit c4c297c

Please sign in to comment.