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 * as socketio from 'socket.io-client'; import PersonalDBGuild from './guild-personal-db'; import RAMGuild from './guild-ram'; import SocketGuild from './guild-socket'; import { Changes, Channel, GuildMetadata, Member, Message, Resource, ServerMetaData, SocketConfig, Token } from './data-types'; import MessageRAMCache from "./message-ram-cache"; import PersonalDB from "./personal-db"; import ResourceRAMCache from "./resource-ram-cache"; import SocketVerifier from './socket-verifier'; import { Connectable, AsyncGuaranteedFetchable } from './guild-types'; import { AutoVerifier } from './auto-verifier'; import { AutoVerifierWithArg, PartialListQuery } from './auto-verifier-with-args'; import GuildPairVerifierGuild from './guild-pair-verifier'; export default class GuildController extends Connectable implements AsyncGuaranteedFetchable { private readonly ramGuild: RAMGuild; private readonly personalDBGuild: PersonalDBGuild; private readonly socketGuild: SocketGuild; private readonly pairVerifiers: GuildPairVerifierGuild[]; private readonly fetchable: AsyncGuaranteedFetchable; constructor( private readonly id: number, private readonly memberId: string, socket: socketio.Socket, socketVerifier: SocketVerifier, messageRAMCache: MessageRAMCache, resourceRAMCache: ResourceRAMCache, personalDB: PersonalDB ) { super(); this.ramGuild = new RAMGuild(messageRAMCache, resourceRAMCache, this.id); this.personalDBGuild = new PersonalDBGuild(personalDB, this.id, this.memberId); this.socketGuild = new SocketGuild(socket, socketVerifier); // TODO: Only unverify the personaldb->socket connection on d/c? this.socketGuild.on('connect', () => { LOG.info(`g#${this.id} connected`); this.emit('connect'); }); this.socketGuild.on('disconnect', () => { LOG.info(`g#${this.id} disconnected`); this.unverify(); this.emit('disconnect'); }); this.socketGuild.on('update-metadata', (guildMeta: GuildMetadata) => { LOG.info(`g#${this.id} updated metadata: ${guildMeta}`); this.emit('update-metadata', guildMeta); }); let listenForList = ( event: 'new-messages' | 'update-messages' | 'new-members' | 'update-members' | 'new-channels' | 'update-channels', logFunc: (arg: T) => void, guildUpdater: (args: T[]) => void ) => { this.socketGuild.on(event, (args: any[]) => { for (let arg of args) { logFunc(arg); } guildUpdater(args); this.emit(event, args); }); } listenForList('new-members', (member: Member) => LOG.info(`g#${this.id} ${member}`), (members: Member[]) => { this.ramGuild.handleMembersAdded(members); this.personalDBGuild.handleMembersAdded(members); } ); listenForList('update-members', (member: Member) => LOG.info(`g#${this.id} updated ${member}`), (members: Member[]) => { this.ramGuild.handleMembersChanged(members); this.personalDBGuild.handleMembersChanged(members); } ); listenForList('new-members', (channel: Channel) => LOG.info(`g#${this.id} ${channel}`), (channels: Channel[]) => { this.ramGuild.handleChannelsAdded(channels); this.personalDBGuild.handleChannelsAdded(channels); } ); listenForList('update-members', (channel: Channel) => LOG.info(`g#${this.id} updated ${channel}`), (channels: Channel[]) => { this.ramGuild.handleChannelsChanged(channels); this.personalDBGuild.handleChannelsChanged(channels); } ); listenForList('new-messages', (message: Message) => LOG.info(`g#${this.id} ${message}`), (messages: Message[]) => { this.ramGuild.handleMessagesAdded(messages); this.personalDBGuild.handleMessagesAdded(messages); } ); listenForList('update-messages', (message: Message) => LOG.info(`g#${this.id} updated ${message}`), (messages: Message[]) => { this.ramGuild.handleMessagesChanged(messages); this.personalDBGuild.handleMessagesChanged(messages); } ); let personalDBSocketPairVerifier = new GuildPairVerifierGuild( this.personalDBGuild, this.socketGuild ); let ramPersonalDBSocketPairVerifier = new GuildPairVerifierGuild( this.ramGuild, personalDBSocketPairVerifier ); this.pairVerifiers = [ personalDBSocketPairVerifier, ramPersonalDBSocketPairVerifier ]; this.fetchable = ramPersonalDBSocketPairVerifier; } static async create( personalGuildId: number, socketConfig: SocketConfig, messageRAMCache: MessageRAMCache, resourceRAMCache: ResourceRAMCache, personalDB: PersonalDB ) { let socket = socketio.connect(socketConfig.url, { forceNew: true, ca: socketConfig.cert }); let socketVerifier = new SocketVerifier(socket, socketConfig.publicKey, socketConfig.privateKey); let memberId = await socketVerifier.verify(); return new GuildController( personalGuildId, memberId, socket, socketVerifier, messageRAMCache, resourceRAMCache, personalDB ); } private unverify() { for (let pairVerifier of this.pairVerifiers) { pairVerifier.unverify(); } } async ensureRAMMembers() { if (this.ramGuild.getMembers().size === 0) { await this.fetchMembers(); } } async ensureRAMChannels() { if (this.ramGuild.getChannels().size === 0) { await this.fetchChannels(); } } async fetchMetadata(): Promise { return await this.fetchable.fetchMetadata(); } async fetchMembers(): Promise { return await this.fetchable.fetchMembers(); } async fetchChannels(): Promise { return await this.fetchable.fetchChannels(); } async fetchMessagesRecent(channelId: string, number: number): Promise { return await this.fetchable.fetchMessagesRecent(channelId, number); } async fetchMessagesBefore(channelId: string, messageId: string, number: number): Promise { return await this.fetchable.fetchMessagesBefore(channelId, messageId, number); } async fetchMessagesAfter(channelId: string, messageId: string, number: number): Promise { return await this.fetchable.fetchMessagesAfter(channelId, messageId, number); } async fetchResource(resourceId: string): Promise { return await this.fetchable.fetchResource(resourceId); } async fetchTokens(): Promise { return await this.fetchable.fetchTokens(); } }