fetch item prices - throttle end points with promise queue
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
import { inject, observer } from 'mobx-react';
|
import { inject, observer } from 'mobx-react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { IItem, IItemPrice } from '../../model';
|
||||||
import { AppStore } from '../../stores/app.store';
|
import { AppStore } from '../../stores/app.store';
|
||||||
import { Navbar } from '../navbar/navbar';
|
import { Navbar } from '../navbar/navbar';
|
||||||
import { PriceListItem } from '../price-list-item/price-list-item';
|
import { PriceListItem } from '../price-list-item/price-list-item';
|
||||||
@@ -19,15 +21,29 @@ export class Home extends React.Component<IProps, IState> {
|
|||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPriceUpdate = (id: string, itemPrice: IItemPrice) => {
|
||||||
|
this.props.appStore!.updateItemPrice(id, itemPrice);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderItemList = () => {
|
||||||
|
const { activeLeague, stashItems } = this.props.appStore!;
|
||||||
|
const orderedItems = _.orderBy(
|
||||||
|
stashItems,
|
||||||
|
(i: IItem) => {
|
||||||
|
return i.itemPrice && i.itemPrice.recommendedPrice ? parseFloat(i.itemPrice.recommendedPrice) : 0;
|
||||||
|
},
|
||||||
|
['desc'],
|
||||||
|
);
|
||||||
|
return orderedItems.map((v, k) => {
|
||||||
|
return <PriceListItem key={k} item={v} league={activeLeague!.id} onPriceUpdate={this.onPriceUpdate} />;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<div style={{ padding: '10px' }}>
|
<div style={{ padding: '10px' }}>{this.renderItemList()}</div>
|
||||||
{this.props.appStore!.stashItems.map((v, k) => {
|
|
||||||
return <PriceListItem key={k} data={v} />;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,4 @@ export * from './home/home';
|
|||||||
export * from './login-webview/login-webview';
|
export * from './login-webview/login-webview';
|
||||||
export * from './navbar/navbar';
|
export * from './navbar/navbar';
|
||||||
export * from './price-list-item/price-list-item';
|
export * from './price-list-item/price-list-item';
|
||||||
export * from './price-list/price-list';
|
|
||||||
export * from './stash-tab/stash-tab';
|
export * from './stash-tab/stash-tab';
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export class Navbar extends React.Component<IProps, any> {
|
|||||||
<div className="navbar">
|
<div className="navbar">
|
||||||
{this.renderLeagueSelector()}
|
{this.renderLeagueSelector()}
|
||||||
{this.renderStashTabSelector()}
|
{this.renderStashTabSelector()}
|
||||||
|
<button onClick={() => this.props.appStore!.resetState()}>Logout</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { IItemPrice } from '../../model';
|
||||||
import { FrameType } from '../../model/frame-type';
|
import { FrameType } from '../../model/frame-type';
|
||||||
import { IItem } from '../../model/item';
|
import { IItem } from '../../model/item';
|
||||||
import { RarityColor } from '../../model/rarity-color';
|
import { RarityColor } from '../../model/rarity-color';
|
||||||
import { ItemTextService } from '../../services';
|
import { ItemTextService, PoeService } from '../../services';
|
||||||
import './price-list-item.scss';
|
import './price-list-item.scss';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
data: IItem;
|
item: IItem;
|
||||||
|
league: string;
|
||||||
|
onPriceUpdate: (id: string, price: IItemPrice) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
@@ -19,17 +22,36 @@ export class PriceListItem extends React.Component<IProps, IState> {
|
|||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {}
|
componentDidMount() {
|
||||||
|
PoeService.priceCheck(this.props.item, this.props.league).then((data: any) => {
|
||||||
|
this.props.onPriceUpdate(this.props.item.id, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getItemPriceText = (p: IItemPrice) => {
|
||||||
|
let s = '';
|
||||||
|
s += p.recommendedPrice ? `Recommended Price: ${p.median_price}\n` : '';
|
||||||
|
s += p.max_price ? `Max Price: ${p.max_price}\n` : '';
|
||||||
|
s += p.median_price ? `Median Price: ${p.median_price}\n` : '';
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { icon, priceInfo, stackSize, typeLine, frameType } = this.props.data;
|
const { icon, itemPrice, stackSize, typeLine, frameType } = this.props.item;
|
||||||
const name = ItemTextService.filterName(typeLine);
|
const name = ItemTextService.filterName(typeLine);
|
||||||
const fullText = ItemTextService.parseItem(this.props.data);
|
const fullText = ItemTextService.parseItem(this.props.item);
|
||||||
|
|
||||||
const rarityColor = RarityColor[(FrameType[frameType] || '').toLowerCase()];
|
const rarityColor = RarityColor[(FrameType[frameType] || '').toLowerCase()];
|
||||||
|
|
||||||
|
const itemPriceElement = itemPrice ? (
|
||||||
|
<small title={this.getItemPriceText(itemPrice)}>
|
||||||
|
{itemPrice.recommendedPrice} {itemPrice.currency_rec}
|
||||||
|
</small>
|
||||||
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pli" onClick={() => console.log(this.props.data)}>
|
<div className="pli" onClick={() => console.log(this.props.item)}>
|
||||||
<div style={{ width: '60px' }}>
|
<div style={{ width: '60px' }}>
|
||||||
<img title={fullText} src={icon} className="pli__img" />
|
<img title={fullText} src={icon} className="pli__img" />
|
||||||
</div>
|
</div>
|
||||||
@@ -38,10 +60,10 @@ export class PriceListItem extends React.Component<IProps, IState> {
|
|||||||
<div className="ellipsis" title={name} style={{ color: rarityColor }}>
|
<div className="ellipsis" title={name} style={{ color: rarityColor }}>
|
||||||
{name}
|
{name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-secondary">{stackSize && <small>Stack Size: {stackSize}</small>}</div>
|
<div className="text-secondary">
|
||||||
</div>
|
{stackSize && <small>Stack Size: {stackSize}</small>}
|
||||||
<div>
|
<div>{itemPriceElement}</div>
|
||||||
{priceInfo ? `${priceInfo.min || priceInfo.min_price} ${priceInfo.currency || priceInfo.currency_rec}` : ''}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import React from 'react';
|
// import React from 'react';
|
||||||
import { PriceListItem } from '../price-list-item/price-list-item';
|
// import { PriceListItem } from '../price-list-item/price-list-item';
|
||||||
|
|
||||||
interface IProps {
|
// interface IProps {
|
||||||
data: any[];
|
// data: any[];
|
||||||
}
|
// }
|
||||||
|
|
||||||
export class PriceList extends React.Component<IProps, any> {
|
// export class PriceList extends React.Component<IProps, any> {
|
||||||
constructor(props: IProps) {
|
// constructor(props: IProps) {
|
||||||
super(props);
|
// super(props);
|
||||||
}
|
// }
|
||||||
|
|
||||||
render = () => this.props.data.map((value, index) => <PriceListItem data={value} key={index} />);
|
// render = () => this.props.data.map((value, index) => <PriceListItem data={value} key={index} />);
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export const http = axios.create();
|
export const http = axios.create();
|
||||||
|
|
||||||
export const setHeader = (header: string, value: string) => {
|
|
||||||
http.defaults.headers[header] = value;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1 +1,6 @@
|
|||||||
|
export * from './frame-type';
|
||||||
|
export * from './item';
|
||||||
|
export * from './item-price';
|
||||||
export * from './league';
|
export * from './league';
|
||||||
|
export * from './rarity-color';
|
||||||
|
export * from './stash-tab';
|
||||||
|
|||||||
14
app/model/item-price.ts
Normal file
14
app/model/item-price.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export interface IItemPrice {
|
||||||
|
currency_rec: string;
|
||||||
|
data: any;
|
||||||
|
error: number;
|
||||||
|
item_base: string;
|
||||||
|
max_price: string;
|
||||||
|
median_price: string;
|
||||||
|
min_price: string;
|
||||||
|
name: string;
|
||||||
|
pred_explanation: any[];
|
||||||
|
recommendedPrice: string;
|
||||||
|
resultsCounted: number;
|
||||||
|
status: number;
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
|
import { IItemPrice } from './item-price';
|
||||||
|
|
||||||
export interface IItem {
|
export interface IItem {
|
||||||
category: any[];
|
category: any[];
|
||||||
|
corrupted: boolean;
|
||||||
descrText: string;
|
descrText: string;
|
||||||
|
elder: boolean;
|
||||||
explicitMods: string[];
|
explicitMods: string[];
|
||||||
frameType: number;
|
frameType: number;
|
||||||
h: number;
|
h: number;
|
||||||
@@ -8,10 +12,15 @@ export interface IItem {
|
|||||||
id: string;
|
id: string;
|
||||||
identified: boolean;
|
identified: boolean;
|
||||||
ilvl: number;
|
ilvl: number;
|
||||||
|
implicitMods: string[];
|
||||||
inventoryId: string;
|
inventoryId: string;
|
||||||
|
itemPrice?: IItemPrice;
|
||||||
league: string;
|
league: string;
|
||||||
name: string;
|
name: string;
|
||||||
properties: any[];
|
properties: any[];
|
||||||
|
requirements: any[];
|
||||||
|
shaper: boolean;
|
||||||
|
sockets: any[];
|
||||||
stackSize?: number;
|
stackSize?: number;
|
||||||
typeLine: string;
|
typeLine: string;
|
||||||
verified: boolean;
|
verified: boolean;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { FrameType } from '../model/frame-type';
|
import { FrameType } from '../model/frame-type';
|
||||||
|
import { IItem } from '../model/item';
|
||||||
|
|
||||||
const lineBreak = '--------\n';
|
const lineBreak = '--------\n';
|
||||||
|
|
||||||
const parseItem = (item: any): string => {
|
const parseItem = (item: IItem): string => {
|
||||||
let name = '';
|
let name = '';
|
||||||
|
|
||||||
name += `Rarity: ${FrameType[item.frameType]}\n`;
|
name += `Rarity: ${FrameType[item.frameType]}\n`;
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import PQueue from 'p-queue';
|
import * as _ from 'lodash';
|
||||||
import { POE_HOME, POE_LEAGUE_LIST_URL, POE_STASH_ITEMS_URL } from '../constants';
|
import { POE_HOME, POE_LEAGUE_LIST_URL, POE_STASH_ITEMS_URL } from '../constants';
|
||||||
import { http } from '../http';
|
import { http } from '../http';
|
||||||
|
import { IItem } from '../model/item';
|
||||||
|
import { PromiseQueue } from '../util';
|
||||||
|
import { ItemTextService } from './item-text.service';
|
||||||
|
import { StorageService } from './storage.service';
|
||||||
|
|
||||||
const queue = new PQueue({ concurrency: 1 });
|
const queue = new PromiseQueue();
|
||||||
|
|
||||||
const getStash = async (username: string, league: string, tabIndex: number | string): Promise<any> => {
|
const getStash = async (username: string, league: string, tabIndex: number | string): Promise<any> => {
|
||||||
const res = await http.get(
|
const res = await http.get(
|
||||||
@@ -11,32 +15,51 @@ const getStash = async (username: string, league: string, tabIndex: number | str
|
|||||||
return res.data;
|
return res.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const priceCheck = async (item: any): Promise<any> => {
|
/**
|
||||||
|
* Clears the request queue. Used when switching leagues/stashes
|
||||||
|
*/
|
||||||
|
const clearRequestQueue = () => {
|
||||||
|
queue.clearQueue();
|
||||||
|
};
|
||||||
|
|
||||||
|
const priceCheck = async (item: IItem, league: string): Promise<any> => {
|
||||||
|
const itemCache = StorageService.getItemCache(item.id);
|
||||||
|
// return cached item if it exists - otherwise fetch from Poe Prices
|
||||||
|
if (itemCache) {
|
||||||
|
return Promise.resolve(itemCache);
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
queue.add(() => {
|
queue.add(() => {
|
||||||
return http
|
return http
|
||||||
.get(`https://poeprices.info/api?l=Incursion&i=${encodeURI(btoa(item))}`, {
|
.get(`https://poeprices.info/api?l=${league}&i=${encodeURI(btoa(ItemTextService.parseItem(item)))}`, {
|
||||||
headers: {
|
headers: {
|
||||||
'Cache-Control': 'max-age=600',
|
'Cache-Control': 'max-age=600',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(resolve);
|
.then(data => {
|
||||||
});
|
if (_.get(data, 'data.error') === 0) {
|
||||||
|
StorageService.storeItemCache(item.id, data.data);
|
||||||
|
}
|
||||||
|
return resolve(data.data);
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUsername = async (): Promise<any> => {
|
const getUsername = async (headers: any): Promise<any> => {
|
||||||
const res = await http.get(POE_HOME);
|
const res = await http.get(POE_HOME, { headers });
|
||||||
const username = res.data.match(/\/account\/view-profile\/(.*?)\"/);
|
const username = res.data.match(/\/account\/view-profile\/(.*?)\"/);
|
||||||
return username[1];
|
return username[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
const getLeagues = async (): Promise<any> => {
|
const getLeagues = async (headers: any): Promise<any> => {
|
||||||
const res = await http.get(POE_LEAGUE_LIST_URL);
|
const res = await http.get(POE_LEAGUE_LIST_URL, { headers });
|
||||||
return res.data;
|
return res.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PoeService = {
|
export const PoeService = {
|
||||||
|
clearRequestQueue,
|
||||||
getLeagues,
|
getLeagues,
|
||||||
getStash,
|
getStash,
|
||||||
getUsername,
|
getUsername,
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import Store from 'electron-store';
|
import Store from 'electron-store';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import { IItemPrice } from '../model';
|
||||||
|
import { IItem } from '../model/item';
|
||||||
const store = new Store();
|
const store = new Store();
|
||||||
|
|
||||||
const storeUsername = (username: string) => {
|
const storeUsername = (username: string) => {
|
||||||
@@ -17,9 +20,30 @@ const getUsername = (): string | undefined => {
|
|||||||
return store.get('user') || undefined;
|
return store.get('user') || undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getItemCache = (id: string): IItem | undefined => {
|
||||||
|
const storedVal = store.get(id);
|
||||||
|
if (!storedVal) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const val = JSON.parse(storedVal);
|
||||||
|
if (DateTime.fromISO(val.timestamp) < DateTime.local().plus({ minutes: 10 })) {
|
||||||
|
return val.item;
|
||||||
|
}
|
||||||
|
store.delete(id);
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const storeItemCache = (id: string, item: IItemPrice) => {
|
||||||
|
const timestamp = DateTime.local();
|
||||||
|
const val = JSON.stringify({ timestamp, item });
|
||||||
|
store.set(id, val);
|
||||||
|
};
|
||||||
|
|
||||||
export const StorageService = {
|
export const StorageService = {
|
||||||
|
getItemCache,
|
||||||
getUsername,
|
getUsername,
|
||||||
getSessionID,
|
getSessionID,
|
||||||
|
storeItemCache,
|
||||||
storeUsername,
|
storeUsername,
|
||||||
storeSessionID,
|
storeSessionID,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Store from 'electron-store';
|
import Store from 'electron-store';
|
||||||
|
import * as _ from 'lodash';
|
||||||
import { action, computed, observable } from 'mobx';
|
import { action, computed, observable } from 'mobx';
|
||||||
import { setHeader } from '../http';
|
import { IItemPrice, ILeague } from '../model';
|
||||||
import { ILeague } from '../model';
|
|
||||||
import { IItem } from '../model/item';
|
import { IItem } from '../model/item';
|
||||||
import { IStashTab } from '../model/stash-tab';
|
import { IStashTab } from '../model/stash-tab';
|
||||||
import { PoeService } from '../services';
|
import { PoeService } from '../services';
|
||||||
@@ -14,7 +14,7 @@ export class AppStore {
|
|||||||
@observable
|
@observable
|
||||||
public sessionID?: string;
|
public sessionID?: string;
|
||||||
@observable
|
@observable
|
||||||
public activeLeague: ILeague;
|
public activeLeague?: ILeague;
|
||||||
@observable
|
@observable
|
||||||
public selectedTabIndex: number = 0;
|
public selectedTabIndex: number = 0;
|
||||||
@observable
|
@observable
|
||||||
@@ -46,7 +46,7 @@ export class AppStore {
|
|||||||
@action
|
@action
|
||||||
private async loadLeagues() {
|
private async loadLeagues() {
|
||||||
try {
|
try {
|
||||||
const leagues = await PoeService.getLeagues();
|
const leagues = await PoeService.getLeagues(this.sessionCookieHeader);
|
||||||
if (!leagues) {
|
if (!leagues) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -67,19 +67,29 @@ export class AppStore {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
public resetState() {
|
public resetState() {
|
||||||
delete this.username;
|
this.username = undefined;
|
||||||
delete this.sessionID;
|
this.sessionID = undefined;
|
||||||
setHeader('Cookie', '');
|
this.activeLeague = undefined;
|
||||||
|
this.selectedTabIndex = 0;
|
||||||
|
this.stashTabs = [];
|
||||||
|
this.stashItems = [];
|
||||||
|
this.leagues = [];
|
||||||
store.clear();
|
store.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
public setSessionID(sessionID: string) {
|
public setSessionID(sessionID: string) {
|
||||||
setHeader('Cookie', `POESESSID=${sessionID}`);
|
|
||||||
this.sessionID = sessionID;
|
this.sessionID = sessionID;
|
||||||
StorageService.storeSessionID(sessionID);
|
StorageService.storeSessionID(sessionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@computed
|
||||||
|
public get sessionCookieHeader(): { Cookie: string } {
|
||||||
|
return {
|
||||||
|
Cookie: `POESESSID=${this.sessionID}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
public setUsername(username: string) {
|
public setUsername(username: string) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
@@ -101,14 +111,27 @@ export class AppStore {
|
|||||||
@action
|
@action
|
||||||
public async performLogin(sessionID: string) {
|
public async performLogin(sessionID: string) {
|
||||||
this.setSessionID(sessionID);
|
this.setSessionID(sessionID);
|
||||||
const username = await PoeService.getUsername();
|
const username = await PoeService.getUsername(this.sessionCookieHeader);
|
||||||
this.setUsername(username);
|
this.setUsername(username);
|
||||||
|
this.loadLeagues();
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
public async loadItems(tabIndex: number | string) {
|
public async loadItems(tabIndex: number | string) {
|
||||||
const data = await PoeService.getStash(this.username!, this.activeLeague.id, tabIndex);
|
PoeService.clearRequestQueue();
|
||||||
|
const data = await PoeService.getStash(this.username!, this.activeLeague!.id, tabIndex);
|
||||||
this.stashTabs = data.tabs;
|
this.stashTabs = data.tabs;
|
||||||
this.stashItems = data.items;
|
this.stashItems = data.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the price of an item in the list - updates based on id
|
||||||
|
*/
|
||||||
|
@action
|
||||||
|
public updateItemPrice(id: string, itemPrice: IItemPrice) {
|
||||||
|
const item = _.find(this.stashItems, i => i.id === id);
|
||||||
|
if (item) {
|
||||||
|
item.itemPrice = itemPrice;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
app/util/index.ts
Normal file
1
app/util/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './promise-queue';
|
||||||
43
app/util/promise-queue.ts
Normal file
43
app/util/promise-queue.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Allow promises to be queued up and executed in order.
|
||||||
|
*/
|
||||||
|
export class PromiseQueue {
|
||||||
|
private queue: any[] = [];
|
||||||
|
private locked: boolean = false;
|
||||||
|
|
||||||
|
/** Add new promise to queue */
|
||||||
|
add(p: () => Promise<any>, delay?: number) {
|
||||||
|
this._add(p, false, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add new promise to the from of the queue */
|
||||||
|
addToBeginning(p: () => Promise<any>, delay?: number) {
|
||||||
|
this._add(p, true, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clear the queue and reset state. */
|
||||||
|
clearQueue() {
|
||||||
|
this.queue = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private delay = (ms: number) => () => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|
||||||
|
_add = (p: () => Promise<any>, beginning: boolean = false, delay?: number) => {
|
||||||
|
const newPromise = delay ? [p, this.delay(delay)] : [p];
|
||||||
|
beginning ? this.queue.unshift(newPromise) : this.queue.push(newPromise);
|
||||||
|
if (!this.locked) {
|
||||||
|
this.next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private next() {
|
||||||
|
this.locked = true;
|
||||||
|
const p = this.queue.shift();
|
||||||
|
const finished = () => {
|
||||||
|
this.queue.length > 0 ? this.next() : (this.locked = false);
|
||||||
|
};
|
||||||
|
Promise.all(p.map((v: any) => v()))
|
||||||
|
.then(finished)
|
||||||
|
.catch(finished);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
package-lock.json
generated
20
package-lock.json
generated
@@ -97,16 +97,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.116.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.116.tgz",
|
||||||
"integrity": "sha512-lRnAtKnxMXcYYXqOiotTmJd74uawNWuPnsnPrrO7HiFuE3npE2iQhfABatbYDyxTNqZNuXzcKGhw37R7RjBFLg=="
|
"integrity": "sha512-lRnAtKnxMXcYYXqOiotTmJd74uawNWuPnsnPrrO7HiFuE3npE2iQhfABatbYDyxTNqZNuXzcKGhw37R7RjBFLg=="
|
||||||
},
|
},
|
||||||
|
"@types/luxon": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-JziyQbl0YIE36lVLDMLhkEhZ1h3Do/+H6x908tXRhzPFrcGAyh7mJ44rhDff+R230RaeIUKeWnhoB8lH5SdsPA=="
|
||||||
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "7.0.69",
|
"version": "7.0.69",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.69.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.69.tgz",
|
||||||
"integrity": "sha512-S5NC8HV6HnRipg8nC0j30TPl7ktXjRTKqgyINLNe8K/64UJUI8Lq0sRopXC0hProsV2F5ibj8IqPkl1xpGggrw=="
|
"integrity": "sha512-S5NC8HV6HnRipg8nC0j30TPl7ktXjRTKqgyINLNe8K/64UJUI8Lq0sRopXC0hProsV2F5ibj8IqPkl1xpGggrw=="
|
||||||
},
|
},
|
||||||
"@types/p-queue": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/p-queue/-/p-queue-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-JyO7uMAtkcMMULmsTQ4t/lCC8nxirTtweGG1xAFNNIAoC1RemmeIxq8PiKghuEy99XdbS6Lwx4zpbXUjfeSSAA=="
|
|
||||||
},
|
|
||||||
"@types/prop-types": {
|
"@types/prop-types": {
|
||||||
"version": "15.5.5",
|
"version": "15.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz",
|
||||||
@@ -8325,6 +8325,11 @@
|
|||||||
"yallist": "2.1.2"
|
"yallist": "2.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"luxon": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-3CM0jpS3mbHwWoPYprX1/Zsd5esni0LkhMfSiSY6xQ3/M3pnct3OPWbWkQdEEl9MO9593k6PvDn1DhxCkpuZEw=="
|
||||||
|
},
|
||||||
"macos-alias": {
|
"macos-alias": {
|
||||||
"version": "0.2.11",
|
"version": "0.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/macos-alias/-/macos-alias-0.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/macos-alias/-/macos-alias-0.2.11.tgz",
|
||||||
@@ -9390,11 +9395,6 @@
|
|||||||
"p-limit": "1.3.0"
|
"p-limit": "1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"p-queue": {
|
|
||||||
"version": "2.4.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-2.4.2.tgz",
|
|
||||||
"integrity": "sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng=="
|
|
||||||
},
|
|
||||||
"p-try": {
|
"p-try": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/electron-store": "^1.3.0",
|
"@types/electron-store": "^1.3.0",
|
||||||
"@types/lodash": "^4.14.116",
|
"@types/lodash": "^4.14.116",
|
||||||
"@types/p-queue": "^2.3.1",
|
"@types/luxon": "^1.2.2",
|
||||||
"@types/react": "^16.4.9",
|
"@types/react": "^16.4.9",
|
||||||
"@types/react-dom": "^16.0.7",
|
"@types/react-dom": "^16.0.7",
|
||||||
"autoprefixer": "^9.1.1",
|
"autoprefixer": "^9.1.1",
|
||||||
@@ -68,12 +68,12 @@
|
|||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"lodash": "^4.17.10",
|
"lodash": "^4.17.10",
|
||||||
|
"luxon": "^1.3.3",
|
||||||
"mobx": "^5.1.0",
|
"mobx": "^5.1.0",
|
||||||
"mobx-react": "^5.2.5",
|
"mobx-react": "^5.2.5",
|
||||||
"node-sass": "^4.9.3",
|
"node-sass": "^4.9.3",
|
||||||
"normalize.css": "^8.0.0",
|
"normalize.css": "^8.0.0",
|
||||||
"open-color": "^1.6.3",
|
"open-color": "^1.6.3",
|
||||||
"p-queue": "^2.4.2",
|
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
"react": "^16.4.2",
|
"react": "^16.4.2",
|
||||||
"react-dom": "^16.4.2",
|
"react-dom": "^16.4.2",
|
||||||
|
|||||||
Reference in New Issue
Block a user