import * as electronRemote from '@electron/remote'; const electronConsole = electronRemote.getGlobal('console') as Console; import Logger from '../../logger/logger'; const LOG = Logger.create(__filename, electronConsole); import { Changes, Channel, GuildMetadata, Member, Message, Resource, Token } from './data-types'; import { AsyncFetchable, Fetchable, Lackable, Conflictable } from './guild-types'; import { AutoVerifier, AutoVerifierChangesType } from './auto-verifier'; import { AutoVerifierWithArg, PartialMessageListQuery, IDQuery } from './auto-verifier-with-args'; import { EventEmitter } from 'tsee'; export default class PairVerifierFetchable extends EventEmitter implements AsyncFetchable { private readonly fetchMetadataVerifier: AutoVerifier; private readonly fetchMembersVerifier: AutoVerifier; private readonly fetchChannelsVerifier: AutoVerifier; private readonly fetchTokensVerifier: AutoVerifier; private readonly fetchResourceVerifier: AutoVerifierWithArg private readonly fetchMessagesRecentVerifier: AutoVerifierWithArg; private readonly fetchMessagesBeforeVerifier: AutoVerifierWithArg; private readonly fetchMessagesAfterVerifier: AutoVerifierWithArg; constructor( private primary: Fetchable & Lackable, private trusted: Fetchable ) { super(); if (trusted instanceof PairVerifierFetchable) { // handle trusted conflicts trusted.on('conflict-metadata', this.handleMetadataConflict.bind(this)); trusted.on('conflict-members', this.handleMembersConflict.bind(this) ); trusted.on('conflict-channels', this.handleChannelsConflict.bind(this)); trusted.on('conflict-tokens', this.handleTokensConflict.bind(this) ); trusted.on('conflict-resource', this.handleResourceConflict.bind(this)); trusted.on('conflict-messages', this.handleMessagesConflict.bind(this)); } this.fetchMetadataVerifier = AutoVerifier.createStandardSingleAutoVerifier( async () => await this.primary.fetchMetadata(), async () => await this.trusted.fetchMetadata(), this.handleMetadataConflict.bind(this) ); this.fetchMembersVerifier = AutoVerifier.createStandardListAutoVerifier( async () => await this.primary.fetchMembers(), async () => await this.trusted.fetchMembers(), this.handleMembersConflict.bind(this) ); this.fetchChannelsVerifier = AutoVerifier.createStandardListAutoVerifier( async () => await this.primary.fetchChannels(), async () => await this.trusted.fetchChannels(), this.handleChannelsConflict.bind(this) ); this.fetchTokensVerifier = AutoVerifier.createStandardListAutoVerifier( async () => await this.primary.fetchTokens(), async () => await this.trusted.fetchTokens(), this.handleTokensConflict.bind(this) ); this.fetchResourceVerifier = AutoVerifierWithArg.createStandardIDQueriedSingleAutoVerifier( async (query: IDQuery) => await this.primary.fetchResource(query.id), async (query: IDQuery) => await this.trusted.fetchResource(query.id), this.handleResourceConflict.bind(this) ); this.fetchMessagesRecentVerifier = AutoVerifierWithArg.createStandardPartialMessageListAutoVerifier( async (query: PartialMessageListQuery) => await this.primary.fetchMessagesRecent(query.channelId, query.number), async (query: PartialMessageListQuery) => await this.trusted.fetchMessagesRecent(query.channelId, query.number), this.handleMessagesConflict.bind(this) ); this.fetchMessagesBeforeVerifier = AutoVerifierWithArg.createStandardPartialMessageListAutoVerifier( async (query: PartialMessageListQuery) => await this.primary.fetchMessagesBefore(query.channelId, query.messageId as string, query.number), async (query: PartialMessageListQuery) => await this.trusted.fetchMessagesBefore(query.channelId, query.messageId as string, query.number), this.handleMessagesConflict.bind(this) ); this.fetchMessagesAfterVerifier = AutoVerifierWithArg.createStandardPartialMessageListAutoVerifier( async (query: PartialMessageListQuery) => await this.primary.fetchMessagesAfter(query.channelId, query.messageId as string, query.number), async (query: PartialMessageListQuery) => await this.trusted.fetchMessagesAfter(query.channelId, query.messageId as string, query.number), this.handleMessagesConflict.bind(this) ); } canFetch() { return true; } async handleMetadataConflict(changesType: AutoVerifierChangesType, primaryMetadata: GuildMetadata | null, trustedMetadata: GuildMetadata | null): Promise { // LOG.debug('metadata conflict', { // primaryClass: this.primary.constructor.name, // trustedClass: this.trusted.constructor.name, // changesType: AutoVerifierChangesType[changesType], // primaryMetadata: primaryMetadata, // trustedMetadata: trustedMetadata, // }); if (changesType === AutoVerifierChangesType.TRUSTED_ONLY) { await this.primary.handleMetadataChanged(trustedMetadata as GuildMetadata); } else if (changesType === AutoVerifierChangesType.CONFLICT) { await this.primary.handleMetadataChanged(trustedMetadata as GuildMetadata); this.emit('conflict-metadata', changesType, primaryMetadata as GuildMetadata, trustedMetadata as GuildMetadata); } } async handleMembersConflict(changesType: AutoVerifierChangesType, changes: Changes): Promise{ if (changes.added.length > 0) await this.primary.handleMembersAdded(changes.added); if (changes.updated.length > 0) await this.primary.handleMembersChanged(changes.updated.map(change => change.newDataPoint)); if (changes.deleted.length > 0) await this.primary.handleMembersDeleted(changes.deleted); if (changesType === AutoVerifierChangesType.CONFLICT) { this.emit('conflict-members', changesType, changes); } } async handleChannelsConflict(changesType: AutoVerifierChangesType, changes: Changes): Promise { if (changes.added.length > 0) await this.primary.handleChannelsAdded(changes.added); if (changes.updated.length > 0) await this.primary.handleChannelsChanged(changes.updated.map(change => change.newDataPoint)); if (changes.deleted.length > 0) await this.primary.handleChannelsDeleted(changes.deleted); if (changesType === AutoVerifierChangesType.CONFLICT) { this.emit('conflict-channels', changesType, changes); } } async handleTokensConflict(changesType: AutoVerifierChangesType, changes: Changes): Promise { if (changes.added.length > 0) await this.primary.handleTokensAdded(changes.added); if (changes.updated.length > 0) await this.primary.handleTokensChanged(changes.updated.map(change => change.newDataPoint)); if (changes.deleted.length > 0) await this.primary.handleTokensDeleted(changes.deleted); if (changesType === AutoVerifierChangesType.CONFLICT) { this.emit('conflict-tokens', changesType, changes); } } async handleResourceConflict(query: IDQuery, changesType: AutoVerifierChangesType, primaryResource: Resource | null, trustedResource: Resource | null): Promise { if (changesType === AutoVerifierChangesType.PRIMARY_ONLY) { await this.primary.handleResourceDeleted(trustedResource as Resource); } else if (changesType === AutoVerifierChangesType.TRUSTED_ONLY) { await this.primary.handleResourceAdded(trustedResource as Resource); } else if (changesType === AutoVerifierChangesType.CONFLICT) { await this.primary.handleResourceChanged(trustedResource as Resource); this.emit('conflict-resource', changesType, query, primaryResource as Resource, trustedResource as Resource); } } async handleMessagesConflict(query: PartialMessageListQuery, changesType: AutoVerifierChangesType, changes: Changes): Promise { if (changes.added.length > 0) await this.primary.handleMessagesAdded(changes.added); if (changes.updated.length > 0) await this.primary.handleMessagesChanged(changes.updated.map(change => change.newDataPoint)); if (changes.deleted.length > 0) await this.primary.handleMessagesDeleted(changes.deleted); if (changesType === AutoVerifierChangesType.CONFLICT) { this.emit('conflict-messages', changesType, query, changes); } } unverify() { this.fetchMetadataVerifier.unverify(); this.fetchMembersVerifier.unverify(); this.fetchChannelsVerifier.unverify(); this.fetchTokensVerifier.unverify(); this.fetchResourceVerifier.unverifyAll(); this.fetchMessagesRecentVerifier.unverifyAll(); this.fetchMessagesBeforeVerifier.unverifyAll(); this.fetchMessagesAfterVerifier.unverifyAll(); if (this.trusted instanceof PairVerifierFetchable) { this.trusted.unverify(); } } async fetchMetadata(): Promise { return await this.fetchMetadataVerifier.fetchAndVerifyIfNeeded(); } async fetchMembers(): Promise { return await this.fetchMembersVerifier.fetchAndVerifyIfNeeded(); } async fetchChannels(): Promise { return await this.fetchChannelsVerifier.fetchAndVerifyIfNeeded(); } async fetchMessagesRecent(channelId: string, number: number): Promise { return await this.fetchMessagesRecentVerifier.fetchAndVerifyIfNeded({ channelId, messageId: null, number }); } async fetchMessagesBefore(channelId: string, messageId: string, number: number): Promise { return await this.fetchMessagesBeforeVerifier.fetchAndVerifyIfNeded({ channelId, messageId, number }); } async fetchMessagesAfter(channelId: string, messageId: string, number: number): Promise { return await this.fetchMessagesAfterVerifier.fetchAndVerifyIfNeded({ channelId, messageId, number }); } async fetchResource(resourceId: string): Promise { return await this.fetchResourceVerifier.fetchAndVerifyIfNeded({ id: resourceId }, true); // lazy verification } async fetchTokens(): Promise { return await this.fetchTokensVerifier.fetchAndVerifyIfNeeded(); } }