diff --git a/src/client/webapp/auto-verifier-with-args.ts b/src/client/webapp/auto-verifier-with-args.ts index 143f843..a1b0a8b 100644 --- a/src/client/webapp/auto-verifier-with-args.ts +++ b/src/client/webapp/auto-verifier-with-args.ts @@ -1,7 +1,7 @@ -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 electronRemote from '@electron/remote'; +//const electronConsole = electronRemote.getGlobal('console') as Console; +//import Logger from '../../logger/logger'; +//const LOG = Logger.create(__filename, electronConsole); import { AutoVerifier, AutoVerifierChangesType } from "./auto-verifier"; import { Changes, WithEquals } from "./data-types"; diff --git a/src/client/webapp/auto-verifier.ts b/src/client/webapp/auto-verifier.ts index 3137700..0aa7dcf 100644 --- a/src/client/webapp/auto-verifier.ts +++ b/src/client/webapp/auto-verifier.ts @@ -38,6 +38,7 @@ export class AutoVerifier { private verifyFunc: (primaryResult: T | null, trustedResult: T | null) => Promise ) {} + /** Returns the changes that must be made to primaryResult given trustedResult */ static getChanges & { id: string }>(primaryResult: T[] | null, trustedResult: T[] | null): Changes { const changes: Changes = { added: [], updated: [], deleted: [] }; diff --git a/src/client/webapp/dedup-awaiter.ts b/src/client/webapp/dedup-awaiter.ts index 2f0e6a3..97119b1 100644 --- a/src/client/webapp/dedup-awaiter.ts +++ b/src/client/webapp/dedup-awaiter.ts @@ -1,9 +1,4 @@ -import * as electronRemote from '@electron/remote'; -const electronConsole = electronRemote.getGlobal('console') as Console; -import Logger from '../../logger/logger'; -const LOG = Logger.create(__filename, electronConsole); - -// lets you wait until it is uncorked by someone before running +// Runs the promise unless it is already running export default class DedupAwaiter { private promise: Promise | null = null; diff --git a/src/client/webapp/elements/require/base-elements.tsx b/src/client/webapp/elements/require/base-elements.tsx index 1001956..690aa78 100644 --- a/src/client/webapp/elements/require/base-elements.tsx +++ b/src/client/webapp/elements/require/base-elements.tsx @@ -1,13 +1,6 @@ -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 React from 'react'; -export interface HTMLElementWithRemoveSelf extends HTMLElement { - removeSelf: (() => void); -} +// This file contains JSX elements that can be used in place directly of storing the elements on the disk. export default class BaseElements { // Scraped directly from discord (#) diff --git a/src/client/webapp/elements/require/elements-util.tsx b/src/client/webapp/elements/require/elements-util.tsx index f7d0d10..673dfb0 100644 --- a/src/client/webapp/elements/require/elements-util.tsx +++ b/src/client/webapp/elements/require/elements-util.tsx @@ -12,6 +12,8 @@ import * as uuid from 'uuid'; import Util from '../../util'; import CombinedGuild from '../../guild-combined'; +// This class contains general element management functions + export interface IAlignment { left?: string; centerX?: string; @@ -52,6 +54,7 @@ export default class ElementsUtil { setState(old => !start); } + /** Gets a string compatible with an src attribute */ static async getImageBufferSrc(buffer: Buffer): Promise { const result = await FileType.fromBuffer(buffer); switch (result && result.mime) { @@ -68,6 +71,7 @@ export default class ElementsUtil { } } + /** Gets a string compatible with an src attribute and uses a loading svg to start and an error png if it fails */ static async getImageSrcFromBufferFailSoftly(buff: Buffer | null): Promise { if (buff === null) { return './img/loading.svg'; @@ -108,6 +112,7 @@ export default class ElementsUtil { } // creates spans to format the text (all in q.js element markup that gets converted to jsx [aka hypergaming]) + /** Creates a JSX element from a text string like "**hello** *world* _my_ ***dudes***" */ static parseMessageText(text: string): JSX.Element { const obj: SimpleQElement = { tag: 'span', content: [], class: null }; const stack: SimpleQElement[] = [ obj ]; @@ -191,6 +196,7 @@ export default class ElementsUtil { // means align the center of the element to the top of the relative to // and align the left of the element to the right of the relative to plus 20 pixels // relativeTo can be an { x, y } or HTMLElement + /** Aligns an element relative to another element or a position in the window */ static alignContextElement( element: HTMLElement, relativeTo: HTMLElement | { x: number, y: number }, diff --git a/src/client/webapp/elements/require/guild-subscriptions.ts b/src/client/webapp/elements/require/guild-subscriptions.ts index 4c4989d..f5ea27e 100644 --- a/src/client/webapp/elements/require/guild-subscriptions.ts +++ b/src/client/webapp/elements/require/guild-subscriptions.ts @@ -16,6 +16,7 @@ import Globals from '../../globals'; import ElementsUtil from './elements-util'; // Abuse closures to get state in case it changed after an await call +// TODO: This function may be useless... function getStateAfterAwait(setState: Dispatch>): T { let x: unknown; setState(state => { @@ -25,22 +26,7 @@ function getStateAfterAwait(setState: Dispatch>): T { return x as T; } -export type SingleSubscriptionEvents = { - 'fetch': () => void; - 'updated': () => void; - 'conflict': () => void; - 'fetch-error': () => void; -} - -export type MultipleSubscriptionEvents = { - 'fetch': () => void; - 'fetch-error': () => void; - 'new': (newValues: T[]) => void; - 'updated': (updatedValues: T[]) => void; - 'removed': (removedValues: T[]) => void; - 'conflict': (changes: Changes) => void; -} - +// Parameters used by base guildSubscription to fetch the initial value interface EffectParams { guild: CombinedGuild; // TODO: I changed this from value: T | null to just value: T. I think @@ -52,13 +38,16 @@ interface EffectParams { unbindEventsFunc: () => void; } +// General typescript type that infers the arguments of a function type Arguments = T extends (...args: infer A) => unknown ? A : never; +// The result of a general subscription. Includes the value and associated guild export interface SubscriptionResult { value: T; guild: CombinedGuild; } +// The result of a scrolling subscription. Includes the state of each end of the list, the list, and the associated guild export interface ScrollingSubscriptionResult { value: { ends: { hasMoreAbove: boolean, hasMoreBelow: boolean }; @@ -67,10 +56,12 @@ export interface ScrollingSubscriptionResult { guild: CombinedGuild; } +// Ensures that a nullable subscriptionResult has a value and has been fetched export function isNonNullAndHasValue(subscriptionResult: SubscriptionResult | null): subscriptionResult is SubscriptionResult { return !!(subscriptionResult !== null && subscriptionResult.value !== null); } +// Maps a "single" data subscription's events (like guild-metadata) interface SingleEventMappingParams { updatedEventName: UE; updatedEventArgsMap: (...args: Arguments) => T; @@ -78,6 +69,8 @@ interface SingleEventMappingParams) => T; } +// Maps a "multiple" data subscription's events (like channels) +// This data subscription can be incrementally updated interface MultipleEventMappingParams< T, NE extends keyof Connectable, @@ -105,6 +98,9 @@ interface MultipleEventMappingParams< * @param fetchFunc Function that can be called to fetch the data for the subscription. This function will be called automatically if it is changed. * Typically, this function will be set up in a useCallback with a dependency on at least the guild. * If the fetch function returns null, this will not call "onFetch". This allows results to stay until the guilds are updated. + * @returns [ + * fetchRetryCallable Can be called to re-fetch the data + * ] */ function useGuildSubscriptionEffect( subscriptionParams: EffectParams, @@ -158,6 +154,10 @@ function useGuildSubscriptionEffect( * @param guild The guild to listen for changes on * @param eventMappingParams The events to use to listen for changes (such as updates and conflicts) * @param fetchFunc The function to call to fetch initial data + * @returns [ + * lastResult: The last result of the fetch (null = not fetched yet) + * fetchError: The error from the fetch + * ] */ function useSingleGuildSubscription( guild: CombinedGuild, @@ -219,7 +219,16 @@ function useSingleGuildSubscription { //LOG.silly('fetching metadata for subscription'); @@ -686,6 +722,15 @@ export function useGuildMetadataSubscription(guild: CombinedGuild) { }, fetchMetadataFunc); } +/** + * @param guild The guild to load from + * @param resourceId The resource id to load from + * @param resourceIdGuild The guild associated with the resource id to load from (if this does not match the guild to load from, this will not update) + * @returns [ + * resourceResult: The resource + * fetchError: Any error from fetching + * ] + */ export function useResourceSubscription(guild: CombinedGuild, resourceId: string | null, resourceIdGuild: CombinedGuild | null) { const fetchResourceFunc = useCallback(async () => { //LOG.silly('fetching resource for subscription (resourceId: ' + resourceId + ')'); @@ -704,6 +749,16 @@ export function useResourceSubscription(guild: CombinedGuild, resourceId: string }, fetchResourceFunc); } +/** + * @param guild The guild to load from + * @param resourceId The resource id to load from + * @param resourceIdGuild The guild associated with the resource id to load from (if this does not match the guild to load from, this will not update) + * @returns [ + * imgSrc: The image src (for use in an ) + * resourceResult: The resource + * fetchError: Any error from fetching + * ] + */ export function useSoftImageSrcResourceSubscription(guild: CombinedGuild, resourceId: string | null, resourceIdGuild: CombinedGuild | null): [ imgSrc: string, resourceResult: SubscriptionResult | null, @@ -724,7 +779,14 @@ export function useSoftImageSrcResourceSubscription(guild: CombinedGuild, resour return [ imgSrc, resourceResult, fetchError ]; } - + +/** + * @param guild The guild to load from + * @returns [ + * channelsResult: The guild's channels + * fetchError: Any error from fetching + * ] + */ export function useChannelsSubscription(guild: CombinedGuild) { const fetchChannelsFunc = useCallback(async () => { return await guild.fetchChannels(); @@ -742,6 +804,13 @@ export function useChannelsSubscription(guild: CombinedGuild) { }, fetchChannelsFunc); } +/** + * @param guild The guild to load from + * @returns [ + * membersResult: The guild's members + * fetchError: Any error from fetching + * ] + */ export function useMembersSubscription(guild: CombinedGuild) { const fetchMembersFunc = useCallback(async () => { const members = await guild.fetchMembers(); @@ -761,6 +830,13 @@ export function useMembersSubscription(guild: CombinedGuild) { }, fetchMembersFunc); } +/** + * @param guild The guild to load from + * @returns [ + * selfMemberResult The guild's self member + * TODO: __fetchError: Any error from fetching + * ] + */ export function useSelfMemberSubscription(guild: CombinedGuild): [ selfMemberResult: SubscriptionResult | null ] { @@ -785,6 +861,13 @@ export function useSelfMemberSubscription(guild: CombinedGuild): [ return [ selfMemberResult ]; } +/** + * @param guild The guild to load from + * @returns [ + * tokensResult: The guild's tokens + * fetchError: Any error from fetching + * ] + */ export function useTokensSubscription(guild: CombinedGuild) { const fetchTokensFunc = useCallback(async () => { //LOG.silly('fetching tokens for subscription'); @@ -803,6 +886,22 @@ export function useTokensSubscription(guild: CombinedGuild) { }, fetchTokensFunc); } +/** + * @param guild The guild to load from + * @param channel The channel to load from + * @param channelGuild The guild that the channel belongs to + * @param scrollToBottomFunc A function that will be called when the UI should scroll to the bottom (when the messages are loaded for the first time for the channel) + * @returns [ + * fetchRetryCallable: Can be called to re-fetch + * fetchAboveCallable: Call to fetch elements above the top element + * fetchBelowCallable: Call to fetch elements below the bottom element + * setScrollRatio: Call to set the position of the scrollbar. This is used to determine which elements to delete if a bunch of new elements are added. + * lastResult: The last result of the fetch (null = not fetched yet) + * fetchError: The error from the fetch + * fetchAboveError: The error from fetching above + * fetchBelowError: The error from fetching below + * ] + */ export function useMessagesScrollingSubscription(guild: CombinedGuild, channel: Channel, channelGuild: CombinedGuild, scrollToBottomFunc: () => void) { const maxFetchElements = Globals.MESSAGES_PER_REQUEST; const maxElements = Globals.MAX_CURRENT_MESSAGES; diff --git a/src/client/webapp/elements/require/guilds-manager-subscriptions.ts b/src/client/webapp/elements/require/guilds-manager-subscriptions.ts index ea790bb..f4a68fd 100644 --- a/src/client/webapp/elements/require/guilds-manager-subscriptions.ts +++ b/src/client/webapp/elements/require/guilds-manager-subscriptions.ts @@ -3,6 +3,7 @@ import * as uuid from 'uuid'; import CombinedGuild from '../../guild-combined'; import GuildsManager from "../../guilds-manager"; +// Subscribes to changes in the list of guilds in the manager export function useGuildListSubscription(guildsManager: GuildsManager): [ guilds: CombinedGuild[] ] { const [ refreshId, setRefreshId ] = useState(uuid.v4()); diff --git a/src/client/webapp/elements/require/react-helper.tsx b/src/client/webapp/elements/require/react-helper.tsx index 3d9bc94..c8361f3 100644 --- a/src/client/webapp/elements/require/react-helper.tsx +++ b/src/client/webapp/elements/require/react-helper.tsx @@ -14,6 +14,7 @@ import ElementsUtil, { IAlignment } from './elements-util'; import React from 'react'; import FileDropTarget from '../components/file-drop-target'; +/** Returns a ref that is true if the component is mounted and false otherwise. Very useful for async stuff */ export function useIsMountedRef() { const isMounted = useRef(false); useEffect(() => { @@ -23,6 +24,7 @@ export function useIsMountedRef() { return isMounted; } +/** Returns a boolean state that will be true for a specified duration after the doShake function is called */ function useShake(ms: number): [ shaking: boolean, doShake: () => void ] { const isMounted = useIsMountedRef(); @@ -73,6 +75,7 @@ export function useOneTimeAsyncAction( return [ value, error ]; } +/** Creates a callable async function that will not double-trigger and gives a result, error message, and shaking boolean */ export function useAsyncCallback( actionFunc: (isMounted: MutableRefObject) => Promise<{ errorMessage: string | null, result: ResultType | null }>, deps: DependencyList @@ -109,6 +112,7 @@ export function useAsyncCallback( return [ callable, result, errorMessage, shaking ]; } +/** Creates a callable async function that does not need to return a value (or shake) */ export function useAsyncVoidCallback( actionFunc: (isMounted: MutableRefObject) => Promise, deps: DependencyList @@ -123,8 +127,7 @@ export function useAsyncVoidCallback( return [ callable ]; } -// TODO: If this function gets expanded one more time, downloadSrc needs to be changed to fetchBuff and only -// be a function. Having 3 types for downloadSrc is a bit iffy. +/** Creates useful state for a button intended to be clicked to download something */ export function useDownloadButton( downloadName: string, fetchBuff: () => Promise, @@ -209,6 +212,7 @@ export function useDownloadButton( return [ callable, text, shaking ]; } +/** Creates useful state variables for a button intended call a submit action */ export function useAsyncSubmitButton( actionFunc: (isMounted: MutableRefObject) => Promise<{ errorMessage: string | null, result: ResultType | null }>, deps: DependencyList, @@ -250,6 +254,7 @@ export function useAsyncSubmitButton( return [ callable, text, shaking, result, errorMessage ]; } +/** Creates useful state for an infinite scroll subscription */ export function useColumnReverseInfiniteScroll( threshold: number, ends: { hasMoreBelow: boolean, hasMoreAbove: boolean } | null, @@ -317,6 +322,7 @@ export function useColumnReverseInfiniteScroll( } // Makes sure to also allow you to fly-out a click starting inside of the ref'd element but was dragged outside +/** Calls the close action when you hit escape or click outside of the ref element */ export function useCloseWhenEscapeOrClickedOrContextOutsideEffect(ref: RefObject, close: () => void) { // Have to use a ref here and not states since we can't re-assign state between mouseup and click const mouseRef = useRef<{ mouseDownTarget: Node | null, mouseUpTarget: Node | null}>({ mouseDownTarget: null, mouseUpTarget: null }); @@ -404,6 +410,7 @@ export function useCloseWhenEscapeOrClickedOrContextOutsideEffect(ref: RefObject }, [ handleKeyDown ]); } +/** Aligns an element to a reference element or position every time realignDeps changes */ export function useAlignment( rootRef: RefObject, relativeToRef: RefObject | null, @@ -431,6 +438,7 @@ export function useAlignment( return [ className ]; } +/** Creates useful context menu state */ export function useContextMenu( createContextMenu: (close: () => void) => ReactNode, createContextMenuDeps: DependencyList @@ -460,6 +468,7 @@ export function useContextMenu( return [ isOpen ? contextMenu : null, toggle, close, open, isOpen ]; } +/** Creates context menu state for right-clicks */ export function useContextClickContextMenu( createContextMenu: (alignment: IAlignment, relativeToPos: { x: number, y: number }, close: () => void) => ReactNode, createContextMenuDeps: DependencyList @@ -485,6 +494,7 @@ export function useContextClickContextMenu( return [ contextMenu, onContextMenu ]; } +/** Creates context state for hovering over an element */ export function useContextHover( createContextHover: () => ReactNode, createContextHoverDeps: DependencyList @@ -509,6 +519,7 @@ export function useContextHover( return [ isOpen ? contextHover : null, mouseEnterCallable, mouseLeaveCallable ]; } +/** Creates a drop target element that will appear when you drag a file over the document */ export function useDocumentDropTarget( message: string, setBuff: Dispatch>, @@ -544,3 +555,4 @@ export function useDocumentDropTarget( return [ dropTarget ]; } + diff --git a/src/client/webapp/fetchable-ensured.ts b/src/client/webapp/fetchable-ensured.ts index 94bfd5c..c12cd4f 100644 --- a/src/client/webapp/fetchable-ensured.ts +++ b/src/client/webapp/fetchable-ensured.ts @@ -1,6 +1,7 @@ import { GuildMetadata, Member, Channel, Message, Resource, Token } from "./data-types"; import { Fetchable, GuaranteedFetchable } from "./guild-types"; +/** Ensures that the fetchable actually returns a value (sanity check class and fixes types) */ export default class EnsuredFetchable implements GuaranteedFetchable { constructor( private fetchable: Fetchable diff --git a/src/client/webapp/fetchable-pair-verifier.ts b/src/client/webapp/fetchable-pair-verifier.ts index dafc236..a45b996 100644 --- a/src/client/webapp/fetchable-pair-verifier.ts +++ b/src/client/webapp/fetchable-pair-verifier.ts @@ -9,6 +9,7 @@ import { AutoVerifier, AutoVerifierChangesType } from './auto-verifier'; import { AutoVerifierWithArg, PartialMessageListQuery, IDQuery } from './auto-verifier-with-args'; import { EventEmitter } from 'tsee'; +/** Uses a primary fetchable and trusted fetchable and verifys the results. Can be chained together with itself as a trusted fetchable! */ export default class PairVerifierFetchable extends EventEmitter implements AsyncFetchable { private readonly fetchMetadataVerifier: AutoVerifier; diff --git a/src/client/webapp/guild-combined.ts b/src/client/webapp/guild-combined.ts index 0535a02..a7809c8 100644 --- a/src/client/webapp/guild-combined.ts +++ b/src/client/webapp/guild-combined.ts @@ -20,6 +20,7 @@ import { EventEmitter } from 'tsee'; import { AutoVerifierChangesType } from './auto-verifier'; import { IDQuery, PartialMessageListQuery } from './auto-verifier-with-args'; +/** The general guild class. This handles connecting a RAM, PersonalDB, and Socket guild together using fetchable-pair-verifiers and some manual caching to nicely update messages */ export default class CombinedGuild extends EventEmitter implements AsyncGuaranteedFetchable, AsyncRequestable { private readonly ramGuild: RAMGuild; private readonly personalDBGuild: PersonalDBGuild; diff --git a/src/client/webapp/guild-personal-db.ts b/src/client/webapp/guild-personal-db.ts index 0bf185d..05062b9 100644 --- a/src/client/webapp/guild-personal-db.ts +++ b/src/client/webapp/guild-personal-db.ts @@ -4,6 +4,7 @@ import { Channel, GuildMetadata, GuildMetadataLocal, Member, Message, Resource, import PersonalDB from "./personal-db"; import { AutoVerifierWithArg, PartialMessageListQuery } from './auto-verifier-with-args'; +/** A guild connected to a local Sqlite database */ export default class PersonalDBGuild implements AsyncFetchable, AsyncLackable { constructor( private readonly db: PersonalDB, diff --git a/src/client/webapp/guild-ram.ts b/src/client/webapp/guild-ram.ts index d930af8..5feafbf 100644 --- a/src/client/webapp/guild-ram.ts +++ b/src/client/webapp/guild-ram.ts @@ -4,6 +4,7 @@ import MessageRAMCache from "./message-ram-cache"; import ResourceRAMCache from "./resource-ram-cache"; import { AutoVerifierWithArg, PartialMessageListQuery } from './auto-verifier-with-args'; +/** A guild connected to the RAM. This guild does not nescessarily implement all aspects of the guild (for example, it does not do "fetchMessagesBefore") */ export default class RAMGuild implements SyncFetchable, SyncLackable { private metadata: GuildMetadata | null = null; private members = new Map(); // id -> member diff --git a/src/client/webapp/guild-socket.ts b/src/client/webapp/guild-socket.ts index 90704aa..1ff5761 100644 --- a/src/client/webapp/guild-socket.ts +++ b/src/client/webapp/guild-socket.ts @@ -14,6 +14,7 @@ import SocketVerifier from './socket-verifier'; import { EventEmitter } from 'tsee'; // Note: you should not be calling the eventemitter functions on outside classes +/** A guild connected to a socket.io socket server */ export default class SocketGuild extends EventEmitter implements AsyncGuaranteedFetchable, AsyncRequestable { private queryDedups = new Map>(); diff --git a/src/client/webapp/guilds-manager.ts b/src/client/webapp/guilds-manager.ts index 4863463..d3aafdb 100644 --- a/src/client/webapp/guilds-manager.ts +++ b/src/client/webapp/guilds-manager.ts @@ -10,50 +10,17 @@ import * as socketio from 'socket.io-client'; import * as crypto from 'crypto'; -import { Changes, Channel, GuildMetadata, GuildMetadataLocal, Member, Message, Resource, SocketConfig, Token } from './data-types'; +import { GuildMetadata, GuildMetadataLocal, Member, SocketConfig } from './data-types'; import { IAddGuildData } from './elements/overlays/overlay-add-guild'; import { EventEmitter } from 'tsee'; import CombinedGuild from './guild-combined'; import PersonalDB from './personal-db'; import MessageRAMCache from './message-ram-cache'; import ResourceRAMCache from './resource-ram-cache'; -import { GuildEventNames } from './guild-types'; -import { AutoVerifierChangesType } from './auto-verifier'; -import { IDQuery, PartialMessageListQuery } from './auto-verifier-with-args'; +/** Manages all guilds that the user is connected to */ export default class GuildsManager extends EventEmitter<{ 'update-guilds': () => void; - - 'connect': (guild: CombinedGuild) => void; - 'disconnect': (guild: CombinedGuild) => void; - 'verified': (guild: CombinedGuild) => void; - - 'update-metadata': (guild: CombinedGuild, guildMeta: GuildMetadata) => void; - - 'new-channels': (guild: CombinedGuild, channels: Channel[]) => void; - 'update-channels': (guild: CombinedGuild, updatedChannels: Channel[]) => void; - 'remove-channels': (guild: CombinedGuild, removedChannels: Channel[]) => void; - - 'new-members': (guild: CombinedGuild, members: Member[]) => void; - 'update-members': (guild: CombinedGuild, updatedMembers: Member[]) => void; - 'remove-members': (guild: CombinedGuild, removedMembers: Member[]) => void; - - 'new-messages': (guild: CombinedGuild, messages: Message[]) => void; - 'update-messages': (guild: CombinedGuild, updatedMessages: Message[]) => void; - 'remove-messages': (guild: CombinedGuild, removedMessages: Message[]) => void; - - 'update-resource': (guild: CombinedGuild, updatedResource: Resource) => void; - - 'new-tokens': (guild: CombinedGuild, newTokens: Token[]) => void; - 'update-tokens': (guild: CombinedGuild, updatedTokens: Token[]) => void; - 'remove-tokens': (guild: CombinedGuild, removedTokens: Token[]) => void; - - 'conflict-metadata': (guild: CombinedGuild, changesType: AutoVerifierChangesType, oldGuildMeta: GuildMetadata, newGuildMeta: GuildMetadata) => void; - 'conflict-channels': (guild: CombinedGuild, changesType: AutoVerifierChangesType, changes: Changes) => void; - 'conflict-members': (guild: CombinedGuild, changesType: AutoVerifierChangesType, changes: Changes) => void; - 'conflict-tokens': (guild: CombinedGuild, changesType: AutoVerifierChangesType, changes: Changes) => void; - 'conflict-messages': (guild: CombinedGuild, query: PartialMessageListQuery, changesType: AutoVerifierChangesType, changes: Changes) => void; - 'conflict-resource': (guild: CombinedGuild, query: IDQuery, changesType: AutoVerifierChangesType, oldResource: Resource, newResource: Resource) => void; }> { public guilds: CombinedGuild[] = []; @@ -81,13 +48,6 @@ export default class GuildsManager extends EventEmitter<{ this.guilds.push(guild); this.emit('update-guilds'); - // Forward guild events through this event emitter - for (const eventName of GuildEventNames) { - guild.on(eventName as any, (...args: any) => { - this.emit(eventName as any, guild, ...args); - }); - } - return guild; } diff --git a/src/client/webapp/message-ram-cache.ts b/src/client/webapp/message-ram-cache.ts index 5b8d4d7..8ad1700 100644 --- a/src/client/webapp/message-ram-cache.ts +++ b/src/client/webapp/message-ram-cache.ts @@ -4,15 +4,17 @@ import Globals from "./globals"; import * as electronRemote from '@electron/remote'; const electronConsole = electronRemote.getGlobal('console') as Console; import Logger from '../../logger/logger'; -import { AutoVerifierWithArg, PartialMessageListQuery } from "./auto-verifier-with-args"; const LOG = Logger.create(__filename, electronConsole); +import { AutoVerifierWithArg, PartialMessageListQuery } from "./auto-verifier-with-args"; + interface MessagesWithMetadata { messages: Map; totalCharacters: number; lastUsed: Date; } +/** Stores messages by-channel-by-guild in RAM */ export default class MessageRAMCache { // g#guildId/c#channelId -> list of messages private data = new Map(); diff --git a/src/client/webapp/personal-db.ts b/src/client/webapp/personal-db.ts index ea462cb..4c35c5f 100644 --- a/src/client/webapp/personal-db.ts +++ b/src/client/webapp/personal-db.ts @@ -12,6 +12,7 @@ import * as sqlite3 from 'sqlite3'; import { Channel, GuildMetadataLocal, Member, Message, Resource, SocketConfig } from "./data-types"; +/** Sqlite representation of a guild */ export default class PersonalDB { private transactions = new ConcurrentQueue(1); diff --git a/src/client/webapp/resource-ram-cache.ts b/src/client/webapp/resource-ram-cache.ts index d8ceee9..8be8316 100644 --- a/src/client/webapp/resource-ram-cache.ts +++ b/src/client/webapp/resource-ram-cache.ts @@ -2,6 +2,7 @@ import Globals from './globals'; import { Resource, ShouldNeverHappenError } from './data-types'; +/** Stores a limited size of resources per-guild in a LRU cache */ export default class ResourceRAMCache { private data = new Map(); // (guildId, resourceId) -> { resource, lastUsed } private size = 0; diff --git a/src/client/webapp/util.ts b/src/client/webapp/util.ts index 00cacf8..c442c52 100644 --- a/src/client/webapp/util.ts +++ b/src/client/webapp/util.ts @@ -23,6 +23,7 @@ export default class Util { } } + /** Get rid of potentially illegal characters in a file name string */ static sanitize(name: string): string { // Windows Version (created for Windows, most likely works cross-platform too given my research) // Allowed Characters: Extended Unicode Charset (1-255) @@ -62,8 +63,9 @@ export default class Util { return availableBaseName + ext; } + /** Waits a number of MS before continuing */ static async sleep(ms: number): Promise { - return await new Promise((resolve, reject) => { + return await new Promise((resolve) => { setTimeout(resolve, ms); }); } @@ -105,6 +107,7 @@ export default class Util { }); } + /** Randomly selects one element from the list using a uniform distribution */ static randomChoice(list: T[]): T { return list[Math.floor(Math.random() * list.length)] as T; }