Cap simultaneous API queries to 2 and prevent multiple requests trying to refresh the API ticket at the same time
This commit is contained in:
parent
f862d53243
commit
168d659785
chat
fchat
mobile
site/character_page
|
@ -124,16 +124,14 @@ import {InlineDisplayMode} from '../interfaces';
|
|||
}
|
||||
});
|
||||
core.connection.onEvent('closed', (isReconnect) => {
|
||||
if(process.env.NODE_ENV !== 'production') {
|
||||
log.debug(
|
||||
'connection.closed',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name,
|
||||
error: this.error,
|
||||
isReconnect
|
||||
}
|
||||
);
|
||||
}
|
||||
log.debug(
|
||||
'connection.closed',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name,
|
||||
error: this.error,
|
||||
isReconnect
|
||||
}
|
||||
);
|
||||
|
||||
if(isReconnect) (<Modal>this.$refs['reconnecting']).show(true);
|
||||
if(this.connected) core.notifications.playSound('logout');
|
||||
|
@ -148,14 +146,12 @@ import {InlineDisplayMode} from '../interfaces';
|
|||
core.connection.onEvent('connecting', async() => {
|
||||
this.connecting = true;
|
||||
|
||||
if(process.env.NODE_ENV !== 'production') {
|
||||
log.debug(
|
||||
'connection.connecting',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name
|
||||
}
|
||||
);
|
||||
}
|
||||
log.debug(
|
||||
'connection.connecting',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name
|
||||
}
|
||||
);
|
||||
|
||||
profileApiInit({
|
||||
defaultCharacter: this.defaultCharacter, animateEicons: core.state.settings.animatedEicons, fuzzyDates: true,
|
||||
|
@ -164,14 +160,12 @@ import {InlineDisplayMode} from '../interfaces';
|
|||
if(core.state.settings.notifications) await core.notifications.requestPermission();
|
||||
});
|
||||
core.connection.onEvent('connected', () => {
|
||||
if(process.env.NODE_ENV !== 'production') {
|
||||
log.debug(
|
||||
'connection.connected',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name
|
||||
}
|
||||
);
|
||||
}
|
||||
log.debug(
|
||||
'connection.connected',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name
|
||||
}
|
||||
);
|
||||
|
||||
(<Modal>this.$refs['reconnecting']).hide();
|
||||
this.error = '';
|
||||
|
@ -184,15 +178,13 @@ import {InlineDisplayMode} from '../interfaces';
|
|||
document.title = (hasNew ? '💬 ' : '') + l(core.connection.isOpen ? 'title.connected' : 'title', core.connection.character);
|
||||
});
|
||||
core.connection.onError((e) => {
|
||||
if(process.env.NODE_ENV !== 'production') {
|
||||
log.debug(
|
||||
'connection.error',
|
||||
{
|
||||
error: errorToString(e),
|
||||
character: core.characters.ownCharacter?.name
|
||||
}
|
||||
);
|
||||
}
|
||||
log.debug(
|
||||
'connection.error',
|
||||
{
|
||||
error: errorToString(e),
|
||||
character: core.characters.ownCharacter?.name
|
||||
}
|
||||
);
|
||||
|
||||
if((<Error & {request?: object}>e).request !== undefined) {//catch axios network errors
|
||||
this.error = l('login.connectError', errorToString(e));
|
||||
|
|
|
@ -3,9 +3,15 @@ import { ipcRenderer, IpcRendererEvent } from 'electron';
|
|||
import log from 'electron-log'; //tslint:disable-line:match-default-export-name
|
||||
import core from '../core';
|
||||
|
||||
interface PendingAd {
|
||||
resolve(): void,
|
||||
reject(err: Error): void,
|
||||
from: number;
|
||||
}
|
||||
|
||||
|
||||
export class AdCoordinatorGuest {
|
||||
protected pendingAds: Record<string, any> = {};
|
||||
protected pendingAds: Record<string, PendingAd> = {};
|
||||
protected adCounter = 0;
|
||||
|
||||
constructor() {
|
||||
|
@ -26,7 +32,7 @@ export class AdCoordinatorGuest {
|
|||
}
|
||||
|
||||
|
||||
requestTurnToPostAd(): Promise<void> {
|
||||
async requestTurnToPostAd(): Promise<void> {
|
||||
return new Promise(
|
||||
(resolve, reject) => {
|
||||
const adId = `${Math.round(Math.random() * 1000000)}-${this.adCounter++}-${Date.now()}`;
|
||||
|
@ -42,7 +48,7 @@ export class AdCoordinatorGuest {
|
|||
|
||||
|
||||
clear(): void {
|
||||
_.each(this.pendingAds, (pa) => (pa.reject()));
|
||||
_.each(this.pendingAds, (pa) => (pa.reject(new Error('Pending ad cleared'))));
|
||||
|
||||
console.debug('adid.clear', _.keys(this.pendingAds), core.characters.ownCharacter?.name);
|
||||
|
||||
|
|
|
@ -69,19 +69,17 @@ export class AdManager {
|
|||
|
||||
const delayTime = Date.now();
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
log.debug(
|
||||
'adManager.sendAdToChannel',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name,
|
||||
channel: conv.channel.name,
|
||||
throatDelta: throatTime - initTime,
|
||||
delayDelta: delayTime - throatTime,
|
||||
totalWait: delayTime - initTime,
|
||||
msg
|
||||
}
|
||||
);
|
||||
}
|
||||
log.debug(
|
||||
'adManager.sendAdToChannel',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name,
|
||||
channel: conv.channel.name,
|
||||
throatDelta: throatTime - initTime,
|
||||
delayDelta: delayTime - throatTime,
|
||||
totalWait: delayTime - initTime,
|
||||
msg
|
||||
}
|
||||
);
|
||||
|
||||
await conv.sendAd(msg);
|
||||
}
|
||||
|
|
|
@ -415,19 +415,17 @@ class ChannelConversation extends Conversation implements Interfaces.ChannelConv
|
|||
core.connection.send('LRP', {channel: this.channel.id, message: text});
|
||||
core.cache.markLastPostTime();
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
log.debug(
|
||||
'conversation.sendAd',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name,
|
||||
channel: this.channel.name,
|
||||
throatDelta: throatTime - initTime,
|
||||
delayDelta: delayTime - throatTime,
|
||||
totalWait: delayTime - initTime,
|
||||
text
|
||||
}
|
||||
);
|
||||
}
|
||||
log.debug(
|
||||
'conversation.sendAd',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name,
|
||||
channel: this.channel.name,
|
||||
throatDelta: throatTime - initTime,
|
||||
delayDelta: delayTime - throatTime,
|
||||
totalWait: delayTime - initTime,
|
||||
text
|
||||
}
|
||||
);
|
||||
|
||||
await this.addMessage(
|
||||
createMessage(MessageType.Ad, core.characters.ownCharacter, text, new Date())
|
||||
|
|
|
@ -4,6 +4,7 @@ import {Connection as Interfaces, WebSocketConnection} from './interfaces';
|
|||
import ReadyState = WebSocketConnection.ReadyState;
|
||||
import log from 'electron-log'; //tslint:disable-line:match-default-export-name
|
||||
import core from '../chat/core';
|
||||
import throat from 'throat';
|
||||
|
||||
const fatalErrors = [2, 3, 4, 9, 30, 31, 33, 39, 40, 62, -4];
|
||||
const dieErrors = [9, 30, 31, 39, 40];
|
||||
|
@ -11,12 +12,12 @@ const dieErrors = [9, 30, 31, 39, 40];
|
|||
let lastFetch = Date.now();
|
||||
let lastApiTicketFetch = Date.now();
|
||||
|
||||
const queryApiThroat = throat(2);
|
||||
const queryTicketThroat = throat(1);
|
||||
|
||||
|
||||
async function queryApi(this: void, endpoint: string, data: object): Promise<AxiosResponse> {
|
||||
if (false) {
|
||||
console.log(`https://www.f-list.net/json/api/${endpoint}, gap: ${Date.now() - lastFetch}ms`);
|
||||
lastFetch = Date.now();
|
||||
}
|
||||
lastFetch = Date.now();
|
||||
|
||||
return Axios.post(`https://www.f-list.net/json/api/${endpoint}`, qs.stringify(data));
|
||||
}
|
||||
|
@ -115,13 +116,59 @@ export default class Connection implements Interfaces.Connection {
|
|||
if(!keepState) this.character = '';
|
||||
}
|
||||
|
||||
|
||||
get isOpen(): boolean {
|
||||
return this.socket !== undefined && this.socket.readyState === ReadyState.OPEN;
|
||||
}
|
||||
|
||||
|
||||
async queryApi<T = object>(endpoint: string, data?: {account?: string, ticket?: string}): Promise<T> {
|
||||
return queryApiThroat(async() => this.queryApiExec<T>(endpoint, data));
|
||||
}
|
||||
|
||||
|
||||
protected async refreshTicket(oldTicket: string): Promise<string> {
|
||||
if (this.ticket !== oldTicket) {
|
||||
log.debug(
|
||||
'api.ticket.renew.resolve.cache',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name
|
||||
}
|
||||
);
|
||||
|
||||
return this.ticket;
|
||||
}
|
||||
|
||||
if (!this.ticketProvider) {
|
||||
throw new Error('No credentials set!');
|
||||
}
|
||||
|
||||
this.ticket = await queryTicketThroat(async() => this.ticketProvider!());
|
||||
|
||||
log.debug(
|
||||
'api.ticket.renew.resolve.refresh',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name
|
||||
}
|
||||
);
|
||||
|
||||
return this.ticket;
|
||||
}
|
||||
|
||||
|
||||
protected async queryApiExec<T = object>(endpoint: string, data?: {account?: string, ticket?: string}): Promise<T> {
|
||||
if(!this.ticketProvider) throw new Error('No credentials set!');
|
||||
|
||||
log.debug(
|
||||
'api.query.start',
|
||||
{
|
||||
endpoint,
|
||||
character: core.characters.ownCharacter?.name,
|
||||
deltaToLastApiCall: Date.now() - lastFetch,
|
||||
deltaToLastApiTicket: Date.now() - lastApiTicketFetch
|
||||
}
|
||||
);
|
||||
|
||||
if(data === undefined) data = {};
|
||||
|
||||
data.account = this.account;
|
||||
|
@ -140,13 +187,13 @@ export default class Connection implements Interfaces.Connection {
|
|||
}
|
||||
);
|
||||
|
||||
data.ticket = this.ticket = await this.ticketProvider();
|
||||
data.ticket = await this.refreshTicket(data.ticket);
|
||||
res = <T & {error: string}>(await queryApi(endpoint, data)).data;
|
||||
}
|
||||
|
||||
if(res.error !== '') {
|
||||
log.debug(
|
||||
'error.api.query',
|
||||
'api.query.error',
|
||||
{
|
||||
error: res.error,
|
||||
endpoint,
|
||||
|
@ -160,6 +207,17 @@ export default class Connection implements Interfaces.Connection {
|
|||
(<Error & {request: true}>error).request = true;
|
||||
throw error;
|
||||
}
|
||||
|
||||
log.debug(
|
||||
'api.query.success',
|
||||
{
|
||||
endpoint,
|
||||
character: core.characters.ownCharacter?.name,
|
||||
deltaToLastApiCall: Date.now() - lastFetch,
|
||||
deltaToLastApiTicket: Date.now() - lastApiTicketFetch
|
||||
}
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -232,43 +290,48 @@ export default class Connection implements Interfaces.Connection {
|
|||
|
||||
private async getTicket(password: string): Promise<string> {
|
||||
console.log('Acquiring new API ticket');
|
||||
const oldLastApiTicketFetch = lastApiTicketFetch;
|
||||
|
||||
if(process.env.NODE_ENV !== 'production') {
|
||||
console.log(`https://www.f-list.net/json/getApiTicket.php, gap: ${Date.now() - lastApiTicketFetch}ms`);
|
||||
log.debug(
|
||||
'api.getTicket.start',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name,
|
||||
deltaToLastApiCall: Date.now() - lastFetch,
|
||||
deltaToLastApiTicket: Date.now() - oldLastApiTicketFetch
|
||||
}
|
||||
);
|
||||
|
||||
log.debug(
|
||||
'api.getTicket',
|
||||
{
|
||||
character: core.characters.ownCharacter?.name,
|
||||
deltaToLastApiCall: Date.now() - lastFetch,
|
||||
deltaToLastApiTicket: Date.now() - lastApiTicketFetch
|
||||
}
|
||||
);
|
||||
|
||||
lastApiTicketFetch = Date.now();
|
||||
}
|
||||
lastApiTicketFetch = Date.now();
|
||||
|
||||
const data = <{ticket?: string, error: string}>(await Axios.post('https://www.f-list.net/json/getApiTicket.php', qs.stringify(
|
||||
{account: this.account, password, no_friends: true, no_bookmarks: true, no_characters: true}))).data;
|
||||
|
||||
if(data.ticket !== undefined) return data.ticket;
|
||||
|
||||
if(process.env.NODE_ENV !== 'production') {
|
||||
console.error('API Ticket Error', data.error);
|
||||
|
||||
log.error(
|
||||
'error.api.getTicket',
|
||||
if(data.ticket !== undefined) {
|
||||
log.debug(
|
||||
'api.getTicket.success',
|
||||
{
|
||||
character: core.characters.ownCharacter.name,
|
||||
error: data.error,
|
||||
character: core.characters.ownCharacter?.name,
|
||||
deltaToLastApiCall: Date.now() - lastFetch,
|
||||
deltaToLastApiTicket: Date.now() - lastApiTicketFetch
|
||||
deltaToLastApiTicket: Date.now() - oldLastApiTicketFetch
|
||||
}
|
||||
);
|
||||
|
||||
lastApiTicketFetch = Date.now();
|
||||
return data.ticket;
|
||||
}
|
||||
|
||||
|
||||
console.error('API Ticket Error', data.error);
|
||||
|
||||
log.error(
|
||||
'error.api.getTicket',
|
||||
{
|
||||
character: core.characters.ownCharacter.name,
|
||||
error: data.error,
|
||||
deltaToLastApiCall: Date.now() - lastFetch,
|
||||
deltaToLastApiTicket: Date.now() - oldLastApiTicketFetch
|
||||
}
|
||||
);
|
||||
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,4 +51,4 @@ initCore(connection, Logs, SettingsStore, Notifications);
|
|||
|
||||
new Index({ //tslint:disable-line:no-unused-expression
|
||||
el: '#app'
|
||||
});
|
||||
});
|
||||
|
|
|
@ -295,10 +295,14 @@
|
|||
|
||||
|
||||
async updateMeta(name: string): Promise<void> {
|
||||
await this.updateImages();
|
||||
await this.updateGuestbook();
|
||||
await this.updateFriends();
|
||||
await this.updateGroups();
|
||||
await Promise.all(
|
||||
[
|
||||
this.updateImages(),
|
||||
this.updateGuestbook(),
|
||||
this.updateFriends(),
|
||||
this.updateGroups()
|
||||
]
|
||||
);
|
||||
|
||||
await core.cache.profileCache.registerMeta(
|
||||
name,
|
||||
|
|
Loading…
Reference in New Issue