Enforce 5s cooldown between ads across all connected characters
This commit is contained in:
		
							parent
							
								
									9879195a41
								
							
						
					
					
						commit
						d2de87b554
					
				@ -2,7 +2,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Canary
 | 
					## Canary
 | 
				
			||||||
*   Fix caching issue that causes cache misses on charater page metadata
 | 
					*   Fix caching issue that causes cache misses on charater page metadata
 | 
				
			||||||
 | 
					*   Fix ad posting issue that sometimes disconnects characters if multiple characters are in use
 | 
				
			||||||
*   URL preview fixes for Redgifs, Gelbooru, Tumblr, and Gifmixxx
 | 
					*   URL preview fixes for Redgifs, Gelbooru, Tumblr, and Gifmixxx
 | 
				
			||||||
 | 
					*   All dependencies are now up to date
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 1.0.1
 | 
					## 1.0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -126,8 +126,8 @@ import {InlineDisplayMode} from '../interfaces';
 | 
				
			|||||||
            core.connection.onEvent('closed', (isReconnect) => {
 | 
					            core.connection.onEvent('closed', (isReconnect) => {
 | 
				
			||||||
                if(process.env.NODE_ENV !== 'production') {
 | 
					                if(process.env.NODE_ENV !== 'production') {
 | 
				
			||||||
                    log.debug(
 | 
					                    log.debug(
 | 
				
			||||||
 | 
					                      'connection.closed',
 | 
				
			||||||
                      {
 | 
					                      {
 | 
				
			||||||
                        type: 'connection.closed',
 | 
					 | 
				
			||||||
                        character: core.characters.ownCharacter?.name,
 | 
					                        character: core.characters.ownCharacter?.name,
 | 
				
			||||||
                        error: this.error,
 | 
					                        error: this.error,
 | 
				
			||||||
                        isReconnect
 | 
					                        isReconnect
 | 
				
			||||||
@ -141,6 +141,7 @@ import {InlineDisplayMode} from '../interfaces';
 | 
				
			|||||||
                this.connecting = false;
 | 
					                this.connecting = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                AdManager.onConnectionClosed();
 | 
					                AdManager.onConnectionClosed();
 | 
				
			||||||
 | 
					                core.adCoordinator.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                document.title = l('title');
 | 
					                document.title = l('title');
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
@ -149,8 +150,8 @@ import {InlineDisplayMode} from '../interfaces';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if(process.env.NODE_ENV !== 'production') {
 | 
					                if(process.env.NODE_ENV !== 'production') {
 | 
				
			||||||
                    log.debug(
 | 
					                    log.debug(
 | 
				
			||||||
 | 
					                      'connection.connecting',
 | 
				
			||||||
                      {
 | 
					                      {
 | 
				
			||||||
                        type: 'connection.connecting',
 | 
					 | 
				
			||||||
                        character: core.characters.ownCharacter?.name
 | 
					                        character: core.characters.ownCharacter?.name
 | 
				
			||||||
                      }
 | 
					                      }
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
@ -165,8 +166,8 @@ import {InlineDisplayMode} from '../interfaces';
 | 
				
			|||||||
            core.connection.onEvent('connected', () => {
 | 
					            core.connection.onEvent('connected', () => {
 | 
				
			||||||
                if(process.env.NODE_ENV !== 'production') {
 | 
					                if(process.env.NODE_ENV !== 'production') {
 | 
				
			||||||
                    log.debug(
 | 
					                    log.debug(
 | 
				
			||||||
 | 
					                      'connection.connected',
 | 
				
			||||||
                      {
 | 
					                      {
 | 
				
			||||||
                        type: 'connection.connected',
 | 
					 | 
				
			||||||
                        character: core.characters.ownCharacter?.name
 | 
					                        character: core.characters.ownCharacter?.name
 | 
				
			||||||
                      }
 | 
					                      }
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
@ -185,8 +186,8 @@ import {InlineDisplayMode} from '../interfaces';
 | 
				
			|||||||
            core.connection.onError((e) => {
 | 
					            core.connection.onError((e) => {
 | 
				
			||||||
                if(process.env.NODE_ENV !== 'production') {
 | 
					                if(process.env.NODE_ENV !== 'production') {
 | 
				
			||||||
                    log.debug(
 | 
					                    log.debug(
 | 
				
			||||||
 | 
					                      'connection.error',
 | 
				
			||||||
                      {
 | 
					                      {
 | 
				
			||||||
                        type: 'connection.error',
 | 
					 | 
				
			||||||
                        error: errorToString(e),
 | 
					                        error: errorToString(e),
 | 
				
			||||||
                        character: core.characters.ownCharacter?.name
 | 
					                        character: core.characters.ownCharacter?.name
 | 
				
			||||||
                      }
 | 
					                      }
 | 
				
			||||||
@ -214,7 +215,7 @@ import {InlineDisplayMode} from '../interfaces';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            // skipping await
 | 
					            // skipping await
 | 
				
			||||||
            // tslint:disable-next-line: no-floating-promises
 | 
					            // tslint:disable-next-line: no-floating-promises
 | 
				
			||||||
            await core.notifications.initSounds(['attention', 'login', 'logout', 'modalert', 'newnote']);
 | 
					            core.notifications.initSounds(['attention', 'login', 'logout', 'modalert', 'newnote']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            core.connection.connect(this.selectedCharacter.name);
 | 
					            core.connection.connect(this.selectedCharacter.name);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										51
									
								
								chat/ads/ad-coordinator-guest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								chat/ads/ad-coordinator-guest.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					import _ from 'lodash';
 | 
				
			||||||
 | 
					import { ipcRenderer, IpcRendererEvent } from 'electron';
 | 
				
			||||||
 | 
					import log from 'electron-log'; //tslint:disable-line:match-default-export-name
 | 
				
			||||||
 | 
					import core from '../core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class AdCoordinatorGuest {
 | 
				
			||||||
 | 
					    protected pendingAds: Record<string, any> = {};
 | 
				
			||||||
 | 
					    protected adCounter = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor() {
 | 
				
			||||||
 | 
					        ipcRenderer.on('grant-send-ad', (_event: IpcRendererEvent, adId: string) => this.processPendingAd(adId));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    processPendingAd(adId: string): void {
 | 
				
			||||||
 | 
					        if (!(adId in this.pendingAds)) {
 | 
				
			||||||
 | 
					            log.debug('adid.pending.miss', {adId, character: core.characters.ownCharacter?.name});
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        log.debug('adid.pending.process', {adId, character: core.characters.ownCharacter?.name});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.pendingAds[adId].resolve();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        delete this.pendingAds[adId];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    requestTurnToPostAd(): Promise<void> {
 | 
				
			||||||
 | 
					        return new Promise(
 | 
				
			||||||
 | 
					          (resolve, reject) => {
 | 
				
			||||||
 | 
					            const adId = `${Math.round(Math.random() * 1000000)}-${this.adCounter++}-${Date.now()}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.pendingAds[adId] = { resolve, reject, from: Date.now() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            log.debug('adid.request', {adId, character: core.characters.ownCharacter?.name});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ipcRenderer.send('request-send-ad', adId);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clear(): void {
 | 
				
			||||||
 | 
					      _.each(this.pendingAds, (pa) => (pa.reject()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      console.debug('adid.clear', _.keys(this.pendingAds), core.characters.ownCharacter?.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.pendingAds = {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								chat/ads/ad-coordinator-host.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								chat/ads/ad-coordinator-host.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					import throat from 'throat';
 | 
				
			||||||
 | 
					import Bluebird from 'bluebird';
 | 
				
			||||||
 | 
					import { IpcMainEvent } from 'electron';
 | 
				
			||||||
 | 
					import log from 'electron-log'; //tslint:disable-line:match-default-export-name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const adCoordinatorThroat = throat(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class AdCoordinatorHost {
 | 
				
			||||||
 | 
					  static readonly MIN_DISTANCE = 5000;
 | 
				
			||||||
 | 
					  private lastPost = Date.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async processAdRequest(event: IpcMainEvent, adId: string) {
 | 
				
			||||||
 | 
					    await adCoordinatorThroat(
 | 
				
			||||||
 | 
					      async() => {
 | 
				
			||||||
 | 
					        const sinceLastPost = Date.now() - this.lastPost;
 | 
				
			||||||
 | 
					        const waitTime = Math.max(0, AdCoordinatorHost.MIN_DISTANCE - sinceLastPost);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        log.debug('adid.request.host', {adId, sinceLastPost, waitTime});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await Bluebird.delay(waitTime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        log.debug('adid.request.host.grant', {adId, sinceLastPost, waitTime});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        event.reply('grant-send-ad', adId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.lastPost = Date.now();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -71,8 +71,8 @@ export class AdManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (process.env.NODE_ENV !== 'production') {
 | 
					                if (process.env.NODE_ENV !== 'production') {
 | 
				
			||||||
                    log.debug(
 | 
					                    log.debug(
 | 
				
			||||||
 | 
					                      'adManager.sendAdToChannel',
 | 
				
			||||||
                      {
 | 
					                      {
 | 
				
			||||||
                        type: 'sendAdToChannel',
 | 
					 | 
				
			||||||
                        character: core.characters.ownCharacter?.name,
 | 
					                        character: core.characters.ownCharacter?.name,
 | 
				
			||||||
                        channel: conv.channel.name,
 | 
					                        channel: conv.channel.name,
 | 
				
			||||||
                        throatDelta: throatTime - initTime,
 | 
					                        throatDelta: throatTime - initTime,
 | 
				
			||||||
 | 
				
			|||||||
@ -147,6 +147,7 @@ abstract class Conversation implements Interfaces.Conversation {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PrivateConversation extends Conversation implements Interfaces.PrivateConversation {
 | 
					class PrivateConversation extends Conversation implements Interfaces.PrivateConversation {
 | 
				
			||||||
    readonly name = this.character.name;
 | 
					    readonly name = this.character.name;
 | 
				
			||||||
    readonly context = CommandContext.Private;
 | 
					    readonly context = CommandContext.Private;
 | 
				
			||||||
@ -402,7 +403,12 @@ class ChannelConversation extends Conversation implements Interfaces.ChannelConv
 | 
				
			|||||||
            async() => {
 | 
					            async() => {
 | 
				
			||||||
                const throatTime = Date.now();
 | 
					                const throatTime = Date.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                await Conversation.testPostDelay();
 | 
					                await Promise.all(
 | 
				
			||||||
 | 
					                    [
 | 
				
			||||||
 | 
					                        await Conversation.testPostDelay(),
 | 
				
			||||||
 | 
					                        await core.adCoordinator.requestTurnToPostAd()
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const delayTime = Date.now();
 | 
					                const delayTime = Date.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -411,8 +417,8 @@ class ChannelConversation extends Conversation implements Interfaces.ChannelConv
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (process.env.NODE_ENV !== 'production') {
 | 
					                if (process.env.NODE_ENV !== 'production') {
 | 
				
			||||||
                    log.debug(
 | 
					                    log.debug(
 | 
				
			||||||
 | 
					                    'conversation.sendAd',
 | 
				
			||||||
                      {
 | 
					                      {
 | 
				
			||||||
                        type: 'sendAd',
 | 
					 | 
				
			||||||
                        character: core.characters.ownCharacter?.name,
 | 
					                        character: core.characters.ownCharacter?.name,
 | 
				
			||||||
                        channel: this.channel.name,
 | 
					                        channel: this.channel.name,
 | 
				
			||||||
                        throatDelta: throatTime - initTime,
 | 
					                        throatDelta: throatTime - initTime,
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import BBCodeParser from './bbcode';
 | 
				
			|||||||
import {Settings as SettingsImpl} from './common';
 | 
					import {Settings as SettingsImpl} from './common';
 | 
				
			||||||
import Conversations from './conversations';
 | 
					import Conversations from './conversations';
 | 
				
			||||||
import {Channel, Character, Connection, Conversation, Logs, Notifications, Settings, State as StateInterface} from './interfaces';
 | 
					import {Channel, Character, Connection, Conversation, Logs, Notifications, Settings, State as StateInterface} from './interfaces';
 | 
				
			||||||
 | 
					import { AdCoordinatorGuest } from './ads/ad-coordinator-guest';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function createBBCodeParser(): BBCodeParser {
 | 
					function createBBCodeParser(): BBCodeParser {
 | 
				
			||||||
    const parser = new BBCodeParser();
 | 
					    const parser = new BBCodeParser();
 | 
				
			||||||
@ -65,6 +66,8 @@ const data = {
 | 
				
			|||||||
    characters: <Character.State | undefined>undefined,
 | 
					    characters: <Character.State | undefined>undefined,
 | 
				
			||||||
    notifications: <Notifications | undefined>undefined,
 | 
					    notifications: <Notifications | undefined>undefined,
 | 
				
			||||||
    cache: <CacheManager | undefined>undefined,
 | 
					    cache: <CacheManager | undefined>undefined,
 | 
				
			||||||
 | 
					    adCoordinator: <AdCoordinatorGuest | undefined>undefined,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    register<K extends 'characters' | 'conversations' | 'channels'>(module: K, subState: VueState[K]): void {
 | 
					    register<K extends 'characters' | 'conversations' | 'channels'>(module: K, subState: VueState[K]): void {
 | 
				
			||||||
        Vue.set(vue, module, subState);
 | 
					        Vue.set(vue, module, subState);
 | 
				
			||||||
        (<VueState[K]>data[module]) = subState;
 | 
					        (<VueState[K]>data[module]) = subState;
 | 
				
			||||||
@ -86,6 +89,7 @@ export function init(this: any, connection: Connection, logsClass: new() => Logs
 | 
				
			|||||||
    data.settingsStore = new settingsClass();
 | 
					    data.settingsStore = new settingsClass();
 | 
				
			||||||
    data.notifications = new notificationsClass();
 | 
					    data.notifications = new notificationsClass();
 | 
				
			||||||
    data.cache = new CacheManager();
 | 
					    data.cache = new CacheManager();
 | 
				
			||||||
 | 
					    data.adCoordinator = new AdCoordinatorGuest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // tslint:disable-next-line no-floating-promises
 | 
					    // tslint:disable-next-line no-floating-promises
 | 
				
			||||||
    data.cache.start();
 | 
					    data.cache.start();
 | 
				
			||||||
@ -111,6 +115,7 @@ export interface Core {
 | 
				
			|||||||
    readonly bbCodeParser: BBCodeParser
 | 
					    readonly bbCodeParser: BBCodeParser
 | 
				
			||||||
    readonly notifications: Notifications
 | 
					    readonly notifications: Notifications
 | 
				
			||||||
    readonly cache: CacheManager
 | 
					    readonly cache: CacheManager
 | 
				
			||||||
 | 
					    readonly adCoordinator: AdCoordinatorGuest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    watch<T>(getter: (this: VueState) => T, callback: WatchHandler<T>): void
 | 
					    watch<T>(getter: (this: VueState) => T, callback: WatchHandler<T>): void
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -50,6 +50,8 @@ import fetch from 'node-fetch';
 | 
				
			|||||||
import MenuItemConstructorOptions = Electron.MenuItemConstructorOptions;
 | 
					import MenuItemConstructorOptions = Electron.MenuItemConstructorOptions;
 | 
				
			||||||
import * as _ from 'lodash';
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
import DownloadItem = Electron.DownloadItem;
 | 
					import DownloadItem = Electron.DownloadItem;
 | 
				
			||||||
 | 
					import { AdCoordinatorHost } from '../chat/ads/ad-coordinator-host';
 | 
				
			||||||
 | 
					import { IpcMainEvent } from 'electron';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//tslint:disable-next-line:no-require-imports
 | 
					//tslint:disable-next-line:no-require-imports
 | 
				
			||||||
const pck = require('./package.json');
 | 
					const pck = require('./package.json');
 | 
				
			||||||
@ -542,6 +544,12 @@ function onReady(): void {
 | 
				
			|||||||
        const index = characters.indexOf(character);
 | 
					        const index = characters.indexOf(character);
 | 
				
			||||||
        if(index !== -1) characters.splice(index, 1);
 | 
					        if(index !== -1) characters.splice(index, 1);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const adCoordinator = new AdCoordinatorHost();
 | 
				
			||||||
 | 
					    electron.ipcMain.on('request-send-ad', (event: IpcMainEvent, adId: string) => (adCoordinator.processAdRequest(event, adId)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const emptyBadge = electron.nativeImage.createEmpty();
 | 
					    const emptyBadge = electron.nativeImage.createEmpty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //tslint:disable-next-line:no-require-imports no-unsafe-any
 | 
					    //tslint:disable-next-line:no-require-imports no-unsafe-any
 | 
				
			||||||
 | 
				
			|||||||
@ -131,8 +131,8 @@ export default class Connection implements Interfaces.Connection {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if(res.error === 'Invalid ticket.' || res.error === 'Your login ticket has expired (five minutes) or no ticket requested.') {
 | 
					        if(res.error === 'Invalid ticket.' || res.error === 'Your login ticket has expired (five minutes) or no ticket requested.') {
 | 
				
			||||||
            log.debug(
 | 
					            log.debug(
 | 
				
			||||||
 | 
					              'api.ticket.loss',
 | 
				
			||||||
              {
 | 
					              {
 | 
				
			||||||
                type: 'api.ticket.loss',
 | 
					 | 
				
			||||||
                error: res.error,
 | 
					                error: res.error,
 | 
				
			||||||
                character: core.characters.ownCharacter?.name,
 | 
					                character: core.characters.ownCharacter?.name,
 | 
				
			||||||
                deltaToLastApiCall: Date.now() - lastFetch,
 | 
					                deltaToLastApiCall: Date.now() - lastFetch,
 | 
				
			||||||
@ -146,8 +146,8 @@ export default class Connection implements Interfaces.Connection {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if(res.error !== '') {
 | 
					        if(res.error !== '') {
 | 
				
			||||||
            log.debug(
 | 
					            log.debug(
 | 
				
			||||||
 | 
					              'error.api.query',
 | 
				
			||||||
              {
 | 
					              {
 | 
				
			||||||
                type: 'error.api.query',
 | 
					 | 
				
			||||||
                error: res.error,
 | 
					                error: res.error,
 | 
				
			||||||
                endpoint,
 | 
					                endpoint,
 | 
				
			||||||
                character: core.characters.ownCharacter?.name,
 | 
					                character: core.characters.ownCharacter?.name,
 | 
				
			||||||
@ -237,8 +237,8 @@ export default class Connection implements Interfaces.Connection {
 | 
				
			|||||||
            console.log(`https://www.f-list.net/json/getApiTicket.php, gap: ${Date.now() - lastApiTicketFetch}ms`);
 | 
					            console.log(`https://www.f-list.net/json/getApiTicket.php, gap: ${Date.now() - lastApiTicketFetch}ms`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            log.debug(
 | 
					            log.debug(
 | 
				
			||||||
 | 
					              'api.getTicket',
 | 
				
			||||||
              {
 | 
					              {
 | 
				
			||||||
                type: 'api.getTicket',
 | 
					 | 
				
			||||||
                character: core.characters.ownCharacter?.name,
 | 
					                character: core.characters.ownCharacter?.name,
 | 
				
			||||||
                deltaToLastApiCall: Date.now() - lastFetch,
 | 
					                deltaToLastApiCall: Date.now() - lastFetch,
 | 
				
			||||||
                deltaToLastApiTicket: Date.now() - lastApiTicketFetch
 | 
					                deltaToLastApiTicket: Date.now() - lastApiTicketFetch
 | 
				
			||||||
@ -257,8 +257,8 @@ export default class Connection implements Interfaces.Connection {
 | 
				
			|||||||
            console.error('API Ticket Error', data.error);
 | 
					            console.error('API Ticket Error', data.error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            log.error(
 | 
					            log.error(
 | 
				
			||||||
 | 
					              'error.api.getTicket',
 | 
				
			||||||
              {
 | 
					              {
 | 
				
			||||||
                type: 'error.api.getTicket',
 | 
					 | 
				
			||||||
                character: core.characters.ownCharacter.name,
 | 
					                character: core.characters.ownCharacter.name,
 | 
				
			||||||
                error: data.error,
 | 
					                error: data.error,
 | 
				
			||||||
                deltaToLastApiCall: Date.now() - lastFetch,
 | 
					                deltaToLastApiCall: Date.now() - lastFetch,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user