diff --git a/client/main.ts b/client/main.ts index 6516f4d..525400b 100644 --- a/client/main.ts +++ b/client/main.ts @@ -20,9 +20,11 @@ electronMain.initialize(); (async () => { await electron.app.whenReady(); - LOG.silly('electron app is ready'); + await LOG.ensureSourceMaps(); + LOG.silly('base log source maps loaded'); + const window = new electron.BrowserWindow({ width: 1580,//1080, height: 720, diff --git a/client/webapp/actions.ts b/client/webapp/actions.ts index a3b6cff..d19c19d 100644 --- a/client/webapp/actions.ts +++ b/client/webapp/actions.ts @@ -70,10 +70,8 @@ export default class Actions { async fetchAndUpdateMessagesRecent(q: Q, server: ClientController, channel: Channel | { id: string }) { await Util.withPotentialErrorWarnOnCancel(q, { taskFunc: async () => { - LOG.debug('active server is s#' + this.ui.activeServer?.id); - LOG.debug('active channel is ch#' + this.ui.activeChannel?.id); if (this.ui.activeServer === null || this.ui.activeServer.id !== server.id) return; - if (this.ui.activeChannel === null || this.ui.activeChannel.id !== server.id) return; + if (this.ui.activeChannel === null || this.ui.activeChannel.id !== channel.id) return; let messages = await server.grabRecentMessages(channel.id, Globals.MESSAGES_PER_REQUEST); await this.ui.setMessages(server, channel, messages, { atTop: messages.length < Globals.MESSAGES_PER_REQUEST, atBottom: true }); }, @@ -89,7 +87,7 @@ export default class Actions { await Util.withPotentialErrorWarnOnCancel(q, { taskFunc: async () => { if (this.ui.activeServer === null || this.ui.activeServer.id !== server.id) return; - if (this.ui.activeChannel === null || this.ui.activeChannel.id !== server.id) return; + if (this.ui.activeChannel === null || this.ui.activeChannel.id !== channel.id) return; let topPair = this.ui.getTopMessagePair(); if (topPair == null) return; let messages = await server.fetchMessagesBefore(channel.id, topPair.message.id, Globals.MESSAGES_PER_REQUEST); @@ -112,7 +110,7 @@ export default class Actions { await Util.withPotentialErrorWarnOnCancel(q, { taskFunc: async () => { if (this.ui.activeServer === null || this.ui.activeServer.id !== server.id) return; - if (this.ui.activeChannel === null || this.ui.activeChannel.id !== server.id) return; + if (this.ui.activeChannel === null || this.ui.activeChannel.id !== channel.id) return; let bottomPair = this.ui.getBottomMessagePair(); if (bottomPair == null) return; let messages = await server.fetchMessagesAfter(channel.id, bottomPair.message.id, Globals.MESSAGES_PER_REQUEST); diff --git a/client/webapp/client-controller.ts b/client/webapp/client-controller.ts index 3a7a3d6..9af5b15 100644 --- a/client/webapp/client-controller.ts +++ b/client/webapp/client-controller.ts @@ -14,6 +14,7 @@ import { Message, Member, Channel, Changes, ConnectionInfo, CacheServerData, Ser import DBCache from './db-cache'; import ResourceRAMCache from './resource-ram-cache'; import RecentMessageRAMCache from './message-ram-cache'; +import { channel } from 'diagnostics_channel'; // Events: // 'connected' function() called when connected to the server @@ -23,11 +24,11 @@ import RecentMessageRAMCache from './message-ram-cache'; // 'update-server' function(serverData) called when the server metadata updates // 'deleted-members' function(members) called when members were deleted on the server-side -// 'updated-members' function(data: Array [ { oldDataPoint, newDataPoint } ]) called when a member was updated on the server-side +// 'updated-members' function(data: Array [ { oldMember, newMember } ]) called when a member was updated on the server-side // 'added-members' function(members) called when members were added on the server-side // 'deleted-channels' function(channels) called when channels were deleted on the server-side -// 'updated-channels' function(data: Array [ { oldDataPoint, newDataPoint } ]) called when a channel was updated on the server-side +// 'updated-channels' function(data: Array [ { oldChannel, newChannel } ]) called when a channel was updated on the server-side // 'added-channels' function(channels) called when channels are added on the server-side // 'new-message' function(message) called when a message is received in a channel @@ -54,7 +55,7 @@ import RecentMessageRAMCache from './message-ram-cache'; // async setStatus(status) Set the current logged in user's status // async setDisplayName(displayName) Sets the current logged in user's display name -// async setAvatar(avatarBu{ updated: { oldDataPoint: T, newDataPoint: T }[], added: T[], removed: T[] } +// async setAvatar(avatarBuff) // async updateChannel(channelId, name, flavorText) Updates a channel's name and flavor text // async queryTokens() Queries for the login tokens as [ { token, member_id, created, expires }, ... ] @@ -162,7 +163,7 @@ export default class ClientController extends EventEmitter { await this.ensureMembers(); let oldMember = this.members.get(member.id); if (oldMember) { - this.emit('updated-members', [ { oldDataPoint: oldMember, newDataPoint: member } ]); + this.emit('updated-members', [ { oldMember: oldMember, newMember: member } ]); } else { this.emit('added-members', [ member ]); } @@ -171,7 +172,7 @@ export default class ClientController extends EventEmitter { await this.ensureChannels(); let oldChannel = this.channels.get(channel.id); if (oldChannel) { - this.emit('updated-channels', [ { oldDataPoint: oldChannel, newDataPoint: channel } ]); + this.emit('updated-channels', [ { oldChannel: oldChannel, newChannel: channel } ]); } else { this.emit('added-channels', [ channel ]); } @@ -193,9 +194,9 @@ export default class ClientController extends EventEmitter { } await DBCache.updateServerMembers(this.id, Array.from(this.members.values())); }); - this.on('updated-members', async (data: { oldDataPoint: Member, newDataPoint: Member }[]) => { - for (const { oldDataPoint, newDataPoint } of data) { - this.members.set(newDataPoint.id, newDataPoint); + this.on('updated-members', async (data: { oldMember: Member, newMember: Member }[]) => { + for (const { oldMember, newMember } of data) { + this.members.set(newMember.id, newMember); } await DBCache.updateServerMembers(this.id, Array.from(this.members.values())); }); @@ -212,9 +213,9 @@ export default class ClientController extends EventEmitter { } await DBCache.updateServerChannels(this.id, Array.from(this.channels.values())); }); - this.on('updated-channels', async (data: { oldDataPoint: Channel, newDataPoint: Channel }[]) => { - for (const { oldDataPoint, newDataPoint } of data) { - this.channels.set(newDataPoint.id, newDataPoint); + this.on('updated-channels', async (data: { oldChannel: Channel, newChannel: Channel }[]) => { + for (const { oldChannel, newChannel } of data) { + this.channels.set(newChannel.id, newChannel); } await DBCache.updateServerChannels(this.id, Array.from(this.channels.values())); }); @@ -236,13 +237,12 @@ export default class ClientController extends EventEmitter { // Alternatively, just store the date in the message and use order-by this._recentMessages.dropChannel(this.id, channel.id); }); - this.on('updated-messages', async (data: { oldDataPoint: Message, newDataPoint: Message }[]) => { - LOG.debug('updated-messages: ', data); - for (let { oldDataPoint, newDataPoint } of data) { - this._recentMessages.updateMessage(this.id, oldDataPoint, newDataPoint); + this.on('updated-messages', async (channel: Channel, data: { oldMessage: Message, newMessage: Message }[]) => { + for (let { oldMessage, newMessage } of data) { + this._recentMessages.updateMessage(this.id, oldMessage, newMessage); } }); - this.on('deleted-messages', async (messages: Message[]) => { + this.on('deleted-messages', async (_channel: Channel, messages: Message[]) => { for (let message of messages) { this._recentMessages.deleteMessage(this.id, message); } @@ -515,7 +515,7 @@ export default class ClientController extends EventEmitter { async grabRecentMessages(channelId: string, number: number): Promise { let cached = this._recentMessages.getRecentMessages(this.id, channelId, number); - if (cached != null) return cached; + if (cached !== null) return cached; return await this.fetchMessagesRecent(channelId, number); } @@ -621,7 +621,7 @@ export default class ClientController extends EventEmitter { this.emit('added-members', changes.added); } if (changes.updated.length > 0) { - this.emit('updated-members', changes.updated); + this.emit('updated-members', changes.updated.map(change => ({ oldMember: change.oldDataPoint, newMember: change.newDataPoint }))); } return true; @@ -662,7 +662,7 @@ export default class ClientController extends EventEmitter { this.emit('added-channels', changes.added); } if (changes.updated.length > 0) { - this.emit('updated-channels', changes.updated); + this.emit('updated-channels', changes.updated.map(change => ({ oldChannel: change.oldDataPoint, newChannel: change.newDataPoint }))); } return true; diff --git a/client/webapp/script.ts b/client/webapp/script.ts index 40ea86a..e71cf41 100644 --- a/client/webapp/script.ts +++ b/client/webapp/script.ts @@ -38,6 +38,9 @@ window.addEventListener('DOMContentLoaded', () => { document.body.classList.remove('preload'); (async () => { + await LOG.ensureSourceMaps(); + LOG.silly('web client log source maps loaded'); + await DBCache.connect(); await DBCache.init(); @@ -149,12 +152,12 @@ window.addEventListener('DOMContentLoaded', () => { await ui.deleteMembers(server, members); }); - controller.on('updated-members', async (server: ClientController, data: { oldDataPoint: Member, newDataPoint: Member }[]) => { + controller.on('updated-members', async (server: ClientController, data: { oldMember: Member, newMember: Member }[]) => { LOG.debug(data.length + ' updated members s#' + server.id); await ui.updateMembers(server, data); if ( ui.activeConnection !== null && - data.find((c: any) => c.newDataPoint.id === (ui.activeConnection as ConnectionInfo).id) + data.find(change => change.newMember.id === (ui.activeConnection as ConnectionInfo).id) ) { await actions.fetchAndUpdateConnection(server); } @@ -170,7 +173,7 @@ window.addEventListener('DOMContentLoaded', () => { await ui.deleteChannels(server, channels); }); - controller.on('updated-channels', async (server: ClientController, data: { oldDataPoint: Channel, newDataPoint: Channel }[]) => { + controller.on('updated-channels', async (server: ClientController, data: { oldChannel: Channel, newChannel: Channel }[]) => { LOG.debug(data.length + ' updated channels'); await ui.updateChannels(actions, server, data); }); @@ -187,7 +190,7 @@ window.addEventListener('DOMContentLoaded', () => { await ui.deleteMessages(server, channel, messages); }); - controller.on('updated-messages', async (server: ClientController, channel: Channel, data: { oldDataPoint: Message, newDataPoint: Message }[]) => { + controller.on('updated-messages', async (server: ClientController, channel: Channel, data: { oldMessage: Message, newMessage: Message }[]) => { LOG.debug(data.length + ' updated messages'); // messages were updated on the server-side await ui.updateMessages(server, channel, data); @@ -218,12 +221,12 @@ window.addEventListener('DOMContentLoaded', () => { // messages that were updated (currently extraneous) // Note: this should never happen since these should be handled by updated-messages // Note: this may be used to replace dummy pre-sent messages - let toUpdate: { newDataPoint: Message, oldDataPoint: Message }[] = []; + let toUpdate: { newMessage: Message, oldMessage: Message }[] = []; for (let addedMessage of addedBefore.values()) { if (ui.messagePairs.has(addedMessage.id)) { toUpdate.push({ - newDataPoint: addedMessage, - oldDataPoint: (ui.messagePairs.get(addedMessage.id) as { message: Message, element: HTMLElement }).message + newMessage: addedMessage, + oldMessage: (ui.messagePairs.get(addedMessage.id) as { message: Message, element: HTMLElement }).message }); } } diff --git a/client/webapp/ui.ts b/client/webapp/ui.ts index 8d12c5c..6286987 100644 --- a/client/webapp/ui.ts +++ b/client/webapp/ui.ts @@ -263,10 +263,9 @@ export default class UI { }); } - public async updateChannels(actions: Actions, server: ClientController, data: { oldDataPoint: Channel, newDataPoint: Channel }[]): Promise { + public async updateChannels(actions: Actions, server: ClientController, data: { oldChannel: Channel, newChannel: Channel }[]): Promise { await this.lockChannels(server, () => { - for (const { oldDataPoint, newDataPoint } of data) { - let newChannel = newDataPoint; + for (const { oldChannel, newChannel } of data) { let oldElement = this.q.$('#channel-list .channel[meta-id="' + newChannel.id + '"]'); let newElement = createChannel(this.document, this.q, this, actions, server, newChannel); oldElement.parentElement?.replaceChild(newElement, oldElement); @@ -359,10 +358,9 @@ export default class UI { }); } - public async updateMembers(server: ClientController, data: { oldDataPoint: Member, newDataPoint: Member }[]): Promise { + public async updateMembers(server: ClientController, data: { oldMember: Member, newMember: Member }[]): Promise { await this.lockMembers(server, () => { - for (const { oldDataPoint, newDataPoint } of data) { - let newMember = newDataPoint; + for (const { oldMember, newMember } of data) { let oldElement = this.q.$_('#server-members .member[meta-id="' + newMember.id + '"]'); if (oldElement) { let newElement = createMember(this.q, server, newMember); @@ -373,8 +371,7 @@ export default class UI { }); if (this.activeChannel === null) return; await this.lockMessages(server, this.activeChannel, () => { - for (const { oldDataPoint, newDataPoint } of data) { - let newMember = newDataPoint; + for (const { oldMember, newMember } of data) { let newStyle = newMember.roleColor ? 'color: ' + newMember.roleColor : null; let newName = newMember.displayName; // the extra query selectors may be overkill @@ -635,11 +632,9 @@ export default class UI { }); } - public async updateMessages(server: ClientController, channel: Channel, data: { oldDataPoint: Message, newDataPoint: Message }[]): Promise { + public async updateMessages(server: ClientController, channel: Channel, data: { oldMessage: Message, newMessage: Message }[]): Promise { await this.lockMessages(server, channel, () => { - for (const { oldDataPoint, newDataPoint } of data) { - let oldMessage = oldDataPoint; - let newMessage = newDataPoint; + for (const { oldMessage, newMessage } of data) { if (this.messagePairs.has(oldMessage.id)) { let oldElement = (this.messagePairs.get(oldMessage.id) as { message: Message, element: HTMLElement }).element; let prevElement = Q.previousElement(oldElement); diff --git a/logger/logger.ts b/logger/logger.ts index dbbf708..98c0575 100644 --- a/logger/logger.ts +++ b/logger/logger.ts @@ -146,6 +146,8 @@ export default class Logger { private name: string; private console: Console; private sourceMaps = new Map(); + private hasSourceMaps = false; + private sourceMapsWaiters: (() => void)[] = []; private constructor(name: string, processConsole?: Console) { this.name = name; @@ -158,10 +160,25 @@ export default class Logger { (async () => { let sourceMaps = await getStaticSourceMaps(); log.sourceMaps = sourceMaps; + log.onGetSourceMaps(); })(); return log; } + private onGetSourceMaps() { + this.hasSourceMaps = true; + for (let sourceMapWaiter of this.sourceMapsWaiters) { + sourceMapWaiter(); + } + } + + public async ensureSourceMaps(): Promise { + if (this.hasSourceMaps) return; + return new Promise((resolve) => { + this.sourceMapsWaiters.push(resolve); + }); + } + /** Logs a message and potentially corresponding data */ private log(level: LoggerLevel, message: string | null, data?: Error | any): void { let frames: StackTrace.Frame[] = StackTrace.parse(new Error()); diff --git a/todo.txt b/todo.txt index 245ddf1..8a114c9 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,6 @@ +Moved to https://cowfield.atlassian.net + + ------ Minimum Viable Product ------ Clean up TypeScript type names @@ -6,6 +9,8 @@ Clean up HTML / CSS Get rid of all static classes that store state +There's a bug with 'undefined' when + Unit tests would be pretty nice for the cache stuff Get rid of the duplicate fetch metadata query at startup (fetch-server)